Removing pop/hiss from WebAudio generated sound - html

I am using the nodeOscillator function from Web Audio API to generate a sound, however when the sound cuts it makes a pop sound (the amplitude is not zero at the cut). Does anyone know a way to check the amplitude of a nodeOscillator and wait until it is zero before I call nodeOff()?

Just fade it out on a gain node over a short time interval 1ms or so - use a setTargetAtTime - and schedule the stop for just longer than that interval.

If you are using an Apple computer, take a look at this: https://vsee.zendesk.com/hc/en-us/articles/204973595-Mac-audio-pop-click-sound

Related

How to play multiple AudioBufferSourceNode synchronized?

I have multiple audio files that must be played in sync. I have read that Web Audio API is the best solution for this. But, I can't find any document that shows how to achieve this.
Almost all articles I have read do this to start playback.
//Let's say I have AudioBufferSourceNode connected to two buffers
var source1, source2;
source1.start(0);
source2.start(0);
Shouldn't this cause source2 to start playing slightly later than source1?
Also, what makes the sources stay in sync? I can not find any mention in any documentation that assures that sources are played in sync.
Thanks.
There is a single clock for the audio context, and the buffer playback is on that clock - so yes, they will stay in sync.
Even calling start(0); start(0); as above will be perfectly synchronized, because start() is setting up a scheduling request on the audio thread, and the actual scheduling of both of those will happen together. "now" is actually slightly in the future (the audio system latency).
You can schedule them slightly in the future.
var source1, source2;
var when = context.currentTime + 0.01;
source1.start(when);
source2.start(when);
That'll schedule both sounds to play exactly 10ms from the moment you define when. It's quick enough that it'll be perceived as immediate, but gives a bit of breathing room for the overhead of actually calling start on the first source node.
There are better ways to do this if you have a ton of nodes, but for simple situations, this should be fine.

Recording internal audio with Flash/AS3

After searching the net high and low, I just cannot for the life of me figure this out. I'm definitely a newbie with all things Flash, but I'm teaching myself where I can. I've gotten a simple Flash piano working, and would like to add record & play back functions. This is where the problem comes in- I can find any multitude of answers for recording from the microphone and saving/playing it back with Flash, but the only things I can find relating to internal audio (or Flash-based pianos) at all are questions like this one with either really vague answers or just no answers at all.
I have some sort of idea that I should be creating an array that tracks the clicks? (It's a mouse-playable piano at the moment, but if it's better for me to make it keyboard-based, that's something I can do at least). After (before? during?) creating that array, how do I keep the rhythm/timing correct?
I'm just super lost and really need your expertise...
You're on the right track in storing the clicks in an array. As far as rhythm and timing, when the user wants to start "recording" you can start a timer, I'd every 200ms or so. You can use that timer to determine at what point in time the key was clicked for use when playing it back.
I don't know if something like a long press is something you'd need, but to do that, with the same timer, you can set a start time and end time (press-->release) and just subtract the end time from the start time and now you have the duration of how long the key was pressed
EDIT: here is a quick example of what I was referring to in my original post: http://ronnieswietek.com/piano/piano_example.swf
the source: http://ronnieswietek.com/piano/piano_example.fla

Synchronize dynamic audio and code in AS3

I'm currently programming a little game which involved that a dynamically created music is playing, and on a specific tone, a function is called to update the game.
I have no problem with dynamically creating music, either using SampleDataEvent.SAMPLE_DATA or the wonderful standingwave2 lib, but I can't find out how to synchronize sound with code.
I know the "sync" note play every X ms (let's say 500), so I've tried to start a timer which ticks every 500ms right after starting the sound, but it gets eventually out of sync. I'm not sure if the timer isn't good enough to follow the path
I know there's a way to put music on Adobe IDE Frames, play sound as "stream" and then put some code on each frame so I can know where it's called, but I can't dynamically create music that way.
So, does anyone knows a way to synchronize my function call with the sound I'm creating ?
I think this depends on when and how does the music generation takes place. If you are generating that music prior to running the game, then you can yield time offset list in that music when the particular tone is generated into that music, then you make a sorted array out of those values, then when the music is actively started, you take flash.utils.getTimer() value and store it as your base time. After this, each frame you check if current getTimer() value is greater than current array position, and if so, the function you want is called, and you advance one position in the array, to be ready for the next pre-set occurrence of your desired tone.
If, on the other hand, you generate music on the fly, a couple of frames length each, then you have to lock getTimer() value at the start of the game and (supposedly) music generation, so that each pair of values you put into sampleData are exactly 1/44100 second of music played. You then count those pairs (on the fly, of course) until it'll be time to insert your desired tone into the generated music, then you'll have an offset from sound start. Convert it to milliseconds, then check each frame if current getTimer() minus stored tick count is greater or equal to discovered offset, and if true, call the function.
As I know sounds playing correlates with frames even if you add them dynamicaly. Try to use Event.ENTER_FRAME. If you know framerate (by default it's equal to 24 fps) and delay (X ms; when a "sync" note plays) then you can get a "sync" frame's index: index = fps * delay. Because for syncronization of a sound and frames important only a nominal fps, not real. Count frames in the Event.ENTER_FRAME handler. When you will achieve the "sync" frame then you can execute your code.
Why don't you just inform your mechanics code about what happens with music when you do render the music handling SampleDataEvent.SAMPLE_DATA? It should be pretty accurate, and you'll never be out of sync for more than one sound chunk (which is usually 2048-4096 float pairs as far as I remember, means 2048/44100 - 4096/44100 ~= 1/22 - 1/11 seconds). Also, I haven't checked this, but I believe, SAMPLE_DATA is fired right after the existing sound chunk started to play, so you can have the next one after it finishes ready, which would mean, if you write down the time of sound render start, then the actual sound will be played the exact that time later(if your system isn't overloaded), so you can calculate it very precisely, down to milliseconds.
You need to enapsulate that WAV generated music within a FLV stream (using only audio tags). Between the FLV audio tags insert FLV metadata tags, which you will receive through onMetaData just when that portion is playing. Since you are generating music on the fly, you might wanna use NetStream.appendBytes() instead of just passing WAV files to NetStream.
You need to familiarize yourself with how FLV works, how appendBytes works and how to create a FLV (which you write into appendBytes() as if you are writing it to a file) which contains WAV audio.

AS3 SampleDataEvent from microphone

I'm writing a recorder for website with flash using the flash.events.SampleDataEvent from the Microphone. But there is one strange thing:
At the beginning the SampleEvent occurs approximately every second. That's really slow. But after waiting a while in front of the browser and starting it again, it's very fast.
So 2 questions:
Is there a way to influence the time between the events
Why is this happening?
Thanks in advance
That is kind of strange. There's no way to tell the event when to dispatch. It just gets triggered when the microphone has sound data in the buffer. For some reason, it doesn't seem like your microphone is recording very much data at first. Try adjusting Microphone.gain and also Microphone.rate. Higher gain will amplify what you are recording to hopefully trigger the event faster and increasing the rate will give you more samples per event.

Syncing two AS3 NetStreams

I'm writing an app that requires an audio stream to be recording while a backing track is played. I have this working, but there is an inconsistent gap in between playback and record starting.
I don't know if I can do anything to make the sync perfect every time, so I've been trying to track what time each stream starts so I can calculate the delay and trim it server-side. This also has proved to be a challenge as no events seem to be sent when a connection starts (as far as I know). I've tried using various properties like the streams' buffer sizes, etc.
I'm thinking now that as my recorded audio is only mono, I may be able to put some kind of 'control signal' on the second stereo track which I could use to determine exactly when a sound starts recording (or stick the whole backing track in that channel so I can sync them that way). This leaves me with the new problem of properly injecting this sound into the NetStream.
If anyone has any idea whether or not any of these ideas will work, how to execute them, or some alternatives, that would be extremely helpful! Been working on this issue for awhile
The only thing that comes to mind is to try and use metadata, flash media streams support metadata and the onMetaData callback. I assume you're using flash media server for the audio coming in and to record the audio going out. If you use the send method while your streaming the audio back to the server, you can put the listening audio track's playhead timestamp in it, so when you get the 2 streams back to the server you can mux them together properly. You can also try encoding the audio that is streamed to the client with metadata and try and use onMetaData to sync them up. I'm not sure how to do this, but a second approach is to try and combine the 2 streams together as the audio goes back so that you don't need to mux them later, or attach it to a blank video stream with 2 audio tracks...
If you're to inject something into the NetStream... As complex as SOUND... I guess here it would be better to go with Socket instead. You'll be directly reading bytes. It's possible there's a compression on the NetStream, so the data sent is not raw sound data - some class for decompressing the codec there would be needed. When you finally get the raw sound data, add the input in there, using Socket.readUnsignedByte() or Socket.readFloat(), and write back the modified data using Socket.writeByte(), or Socket.writeFloat().
This is the alternative with injecting the back into the audio.
For syncing, it is actually quite simple. Even though the data might not be sent instantly, one thing still stays the same - time. So, when user's audio is finished, just mix it without anything else to the back track - the time should stay the same.
IF the user has slow internet DOWNLOAD, so that his backtrack has unwanted breaks - check in the SWF if the data is buffered enough to add the next sound buffer (usually 4096 bytes if I remember correctly). If yes, continue streaming user's audio.
If not, do NOT stream, and start as soon as the data catches back on.
In my experience NetStream is one of the most inaccurate and dirty features of Flash (NetStream:play2 ?!!), which btw is quite ironic seeing how Flash's primary use is probably video playback.
Trying to sync it with anything else in a reliable way is very hard... events and statuses are not very straight forward, and there are multiple issues that can spoil your syncing.
Luckily however, netStream.time will tell you quite accurately the current playhead position, so you can eventually use that to determine starting time, delays, dropped frames, etc... Notice that determining the actual starting time is a bit tricky though. When you start loading a netStream, the time value is zero, but when it shows the first frame and is waiting for the buffer to fill (not playing yet) the time value is something like 0.027 (depends on the video), so you need to very carefully monitor this value to accurately determine events.
An alternative to using NetStream is embedding the video in a SWF file, which should make synchronization much easier (specially if you use frequent keyframes on encoding). But you will lose quality/filesize ratio (If I remember correctly you can only use FLV, not h264).
no events seem to be sent when a connection starts
sure there does.. NetStatusEvent.NET_STATUS fires for a multitude of reasons for NetConnections and Netstreams, you just have to add a listener and process the contents of NET_STATUS.info
the as3 reference docs here and you're looking for NET_STATUS.info