Note: If you click on the fiddle, ensure your sound is turned down to a minimum.
I'm using the Web Audio API and I want to detune one oscillator against another by a few cents to create a thicker sound. The problem is when I do detune one oscillator it creates a pulsating sound. If i play with the detune amount it gets better or worse depending on the values I set for each oscillator. If I detune one oscillator by -1 (as shown in the example below) the sound coming back from the oscillators cuts out periodically.
Why is this? Software synths I've used before allow you to detune by single cents so assuming that isn't the issue.
// create web audio api context
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// create Oscillator node
var oscillator = audioCtx.createOscillator();
oscillator.type = 'square';
oscillator.frequency.setValueAtTime(440, audioCtx.currentTime); // value in hertz
oscillator.connect(audioCtx.destination);
// create Oscillator node
var oscillator1 = audioCtx.createOscillator();
oscillator1.type = 'square';
oscillator1.frequency.setValueAtTime(440, audioCtx.currentTime); // value in hertz
oscillator1.detune.setValueAtTime(-1, audioCtx.currentTime);
oscillator1.connect(audioCtx.destination);
oscillator.start();
oscillator1.start();
https://jsfiddle.net/c1xdnLtm/
Related
How can I extract and work with the ARMeshGeometry generated by the new SceneReconstruction API on the iPad Pro? I am using Apple's Visualising Scene Semantics sample app/code
I am trying to attach an AudioKit AKOscillator() to the centre of the 'face' as a 3D sound source as its created in realtime.
I can see from the LiDAR example code that this 'seems' to be the point at which a 'face' is created however I am having trouble combining both the extraction/seeing the 'face' data and adding the AudioKit sound source.
Here is where I believe the face is determined (I am new to swift could be very wrong):
DispatchQueue.global().async {
for anchor in meshAnchors {
for index in 0..<anchor.geometry.faces.count {
// Get the center of the face so that we can compare it to the given location.
let geometricCenterOfFace = anchor.geometry.centerOf(faceWithIndex: index)
// Convert the face's center to world coordinates.
var centerLocalTransform = matrix_identity_float4x4
centerLocalTransform.columns.3 = SIMD4<Float>(geometricCenterOfFace.0, geometricCenterOfFace.1, geometricCenterOfFace.2, 1)
let centerWorldPosition = (anchor.transform * centerLocalTransform).position
I would really benefit from seeing the RAW array data if that is achievable? Is this from ARGeometrySource?? Can this be printed or viewed/extracted??
I then want to add something like an oscillator/noise generator to that 'face' in the 3D world location and it be spatialised using the array/location data using something like:
var oscillator = AKOscillator() Create the sound generator
AudioKit.output = oscillator Tell AudioKit what to output
AudioKit.start() Start up AudioKit
oscillator.start() Start the oscillator
oscillator.frequency = random(in: 220...880) Set oscillator parameters
I appreciate this is almost a two-fold question however any approach on the ARMeshGemotery data extraction/use or the implementation of a sound source in the centre of each 'face' or both are welcomed.
Further code for LiDAR visualising scene semantics example in link above.
Thanks, your assistance is much appreciated,
R
I have been researching methods to detect people only in the video from a security camera. I want to use vision.peopledetector with vision.BlobAnalysis and vision.ForegroundDetector. But it doesn't work.
It should be like Motion-Based Multiple Object Tracking example, but only for detecting humans. Cant seem to get it work.
What I have done so far without using vision.BlobAnalysis and `vision.ForegroundDetector. It is not accurate at all and cant count
video = VideoReader('atrium.mp4');
peopleDetector = vision.PeopleDetector;
videoPlayer = vision.VideoPlayer;
while hasFrame(video)
img = readFrame(video);
[bboxes,scores] = step(peopleDetector,img);
D = 1;
frame = insertObjectAnnotation(img,'rectangle',bboxes,D);
step(videoPlayer,frame);
end
OK. So here's what I think is happening: the resolution of the atrium.mp4 video is not high enough to make reliable detections using vision.PeopleDetector. Here's what I did to modify your code:
video = VideoReader('atrium.mp4');
peopleDetector = vision.PeopleDetector;
videoPlayer = vision.VideoPlayer;
while hasFrame(video)
img = readFrame(video);
img = imresize(img, 3); % resize the frame to make people large enough
[bboxes,scores] = step(peopleDetector,img);
D = 1;
frame = insertObjectAnnotation(img,'rectangle',bboxes,D);
step(videoPlayer,frame);
end
I now see fairly consistent detections in the video, but they are still not tracked all the time, and there seems to be some erroneous detections (one, specifically at the right bottom corner of the video). To avoid these issues, I would do something like what this demo does:
https://www.mathworks.com/help/vision/examples/track-face-raspberry-pi2.html
In essence, this demo uses face detection only when there are no detections, and switches over to tracking once a detection has been made. That way, your processing loop is significantly faster (tracking is less computationally demanding than detection), and you can have (in general) higher fidelity tracking than independent detections in each frame. You could also include some other heuristics such as no movements at all in > 50 frames implies a false positive, and such.
I can use the linearRampToValueAtTime() method of the Web Audio API's AudioParam Interface to schedule a gradual linear change in the param. For instance, for gain,
var gainNode = audioContext.createGain();
gainNode.gain.linearRampToValueAtTime(1.0, audioContext.currentTime + 2);
I want to linearly ramp the position of a PannerNode. A Panner has a setPosition method, but I don't see an associated AudioParam:
var pannerNode = audioContext.createPanner();
pannerNode.setPosition(xPosition, yPosition, zPosition);
Can I linearly ramp the position of a panner node? I know that I could manually create a timer, and directly call setPosition over time, but can the Web Audio API handle that for me?
You can't. It's one of the many things wrong with the initial AudioPanner design, and why it's being refactored into two different nodes. https://github.com/WebAudio/web-audio-api/issues/372.
For the time being, you'll have to animate this via setInterval or the like.
I've recently been working on porting my game to be cross-platform, and decided to go with OpenAL for my cross-platform audio engine.
I have 16 "channels" (OpenAL sources) for playing up to 16 sounds concurrently. To play a sound, I switch which buffer is linked to a given source, and also set the gain, source position, and so on in order to play a sound in a given "channel" (source).
The problem is, I've noticed that my "gain" settings do not seem to have immediate effect. For instance, if a loud "lightning" sound plays in a given source at 0.5 gain, then when I have a button click sound play at 0.15 gain later, this click starts off FAR too loud. Then, each subsequent time it is played, the volume decreases until around the 3rd or 4th click it sounds like it's around the proper 0.15 gain.
The first button click is barely audible, and it seems to ramp up in volume until it reaches the 0.15 gain.
So in short, a "source" seems to be remembering the former gain settings, even though I am resetting those before playing a new sound in the same source! Is this a bug? Or something I don't understand about OpenAL? How can I get it to "instantly" change to the new gain/position settings?
Relevant code to play a sound:
[Channel is a value between 0 and 15, soundID is a valid index into the gBuffer array, stereoPosition is an integer between -255 and 255, and volume is between 0 and 255. This is from a function that's a wrapper for my game that used to use values between 0-255, so it converts the values to proper OpenAL values.]
// Stop any sound currently playing in this channel ("source")
alSourceStop( gSource[channel] );
// What sound effect ("buffer") is currently linked with this channel? (Even if not currently playing)
alGetSourcei( gSource[channel], AL_BUFFER, &curBuffer );
// attach a different buffer (sound effect) to the source (channel) only if it's different than the previously-attached one.
// (Avoid error code by changing it only if it's different)
if (curBuffer != gBuffer[soundID])
alSourcei( gSource[channel], AL_BUFFER, gBuffer[soundID] );
// Loop the sound?
alSourcei( gSource[channel], AL_LOOPING, (loopType == kLoopForever) );
// For OpenAL, we do this BEFORE starting the sound effect, to avoid sudden changes a split second after it starts!
volume = (volume / 2) + 1; // Convert from 0-255 to 0-128
{
float sourcePos[3] = {(float)stereoPosition / 50, 0.0, 2.0};
// Set Source Position
alSourcefv( gSource[channelNum], AL_POSITION, sourcePos ); // fv = float vector
// Set source volume
alSourcef( gSource[channelNum], AL_GAIN, (float)newVolume / 255 );
}
// Start playing the sound!
alSourcePlay( gSource[channel] );
I can post setup code too if desired, but nothing fancy there. Just calling
alSourcef( gSource[n], AL_REFERENCE_DISTANCE, 5.0f );
for each source.
We just faced the same problem when setting the ByteOffset for seeking to a position in a sample and found now the solution to get it working:
Just always delete and recreate the source before setting any parameter on it.
So if you want to change the gain and/or other parameters:
OpenAL.AL.DeleteSource(oldSourceID);
newSourceId = OpenAL.AL.GenSource();
OpenAL.AL.Source(newSourceId , OpenTK.Audio.OpenAL.ALSourcef.Gain, yourVolume);
OpenAL.AL.Source(newSourceId , OpenTK.Audio.OpenAL.ALSourcef.xxx, yourOtherParameter);
Hope it works for you and finally have a workaround after 10 years :-)
I've recently been trying to incorporate an intensive sound management class, where sound playback precision is a must.
What I'm looking for is the option to load a sound, set the playback starting position (or playhead), play for a certain time, pause the sound, set the 'playhead' position to a new interval and resume playback again. (with dynamic intervals).
I've tried using AVAudioPlayer for that matter - but it seems it's just too slow. The performance is just not what you expect, it lags when calling pause and setCurrentTime:.
It's the easiest library to use and the only one with stated setCurrentTime: function.
I come here asking for your help, a recommendation for a decent open-source SoundEngine that can handle interval setting (playhead movement) with low latency, or reference to where it is stated that OpenAL or AudioUnit tools can handle playback position setting.
Thank you in advance,
~ Natanavra.
It would be worth your time to check out the openAL programmer's guide that comes with the SDK. Its got all sorts of goodies!
From that:
Under source: Each source generated by alGenSources has properties which can be set or retrieved.
The alSource[f, 3f, fv, i] and alGetSource[f, 3f, fv, i] families of functions can be used to set or retrieve the following source properties:
...
AL_SEC_OFFSET f, fv, i, iv the playback position, expressed in seconds
AL_SAMPLE_OFFSET f, fv, i, iv the playback position, expressed in samples
AL_BYTE_OFFSET f, fv, i, iv the playback position, expressed in bytes
So you can get the playback position in seconds and divide by 60 to get your normalized time.
float pos = 0; alGetSourcef( sourceID, AL_SEC_OFFSET, &pos );
float normalizedPos = pos / 60.0f;
OpenAL definitely has the capabilities to playback sound pause whatever you like. remember OpenAL is often used in games as it delivers sound playback with low latency and on demand playback. You have a lot of control over the sound. compared to the AVAudioPlayer class.
Hope this helps
Do reply
Pk