VJAI / musquito

An audio engine for HTML5 based games and interactive websites
http://musquitojs.com/
MIT License
50 stars 9 forks source link

Record audio output to mediastream? #4

Closed chadananda closed 4 years ago

chadananda commented 4 years ago

I'm wondering if it is possible to output everything to a mediastream for recording. Say, for example, were I to create a keyboard with sprites and drum samples. Could I record my audio production to a stream?

VJAI commented 4 years ago

Currently musquito doesn't support this directly. I googled and see there is a library called Recorderjs that might help. https://stackoverflow.com/questions/14418530/record-sounds-from-audiocontext-web-audio-api

I'll check that library out and update you how we can use it with musquito for recording.

chadananda commented 4 years ago

I'm not asking about recording from a microphone, but recording the Musquito output.

VJAI commented 4 years ago

The RecorderJs library is used to record the output from any Web Audio Node.

var rec = new Recorder(source [, config]);
rec.record()
rec.stop()

I haven't tried the library yet but I believe you should be passing the audio context destination as the source to the Recorder.

https://github.com/mattdiamond/Recorderjs

In musquito, you could retrieve the audio context from the engine class and pass the respective node to Recorder. Let me know if there is any challenge in doing so.

chadananda commented 4 years ago

Oh, I see. That makes sense. Thanks.

Now with Howler, there is a Howler.masterGain which everything goes through to allow for a global volume control. One can plug in RecorderJs or MediaRecorder to that in order to record all output.

Is there an equivalent single source point for Musquito output?

Here's a wired up example with Howler demonstrating hooking into masterGain: https://jsfiddle.net/chadananda/kvzrsx5t/

VJAI commented 4 years ago

I've added the method to $buzz to expose the master gain node.

// To get Audio Context
var context = $buzz.context();
// To get master gain node
var masterGain = $buzz.masterGain();

It's available in version 1.1.3 in npm. Let me know if you need more help.

chadananda commented 4 years ago

And here is a working example of recording audio from masterGain

https://jsfiddle.net/chadananda/2yo93v04/

// ** Successful example of capturing Musquito output to mediaRecorder 
const audioURL = 'https://cdn.glitch.com/02dcea11-9bd2-4462-ac38-eeb6a5ad9530%2F331_full_beautiful-minds_0171_preview.mp3'

// example of recording one sound looping for 3 seconds 
let sound = $buzz({ src: audioURL, onerror: (err) => console.log('Error', err), volume:0.05 }) 

// connect MediaStreamDestination to Howler.masterGain  
let streamDest = $buzz.context().createMediaStreamDestination() 
$buzz.masterGain().connect(streamDest) 

// set up media recorder to record output
let chunks = [] 
let mediaRecorder = new MediaRecorder(streamDest.stream, {mimeType: 'audio/webm'})
mediaRecorder.onstart = ()=>{ console.log('Started recording Musquito output...') }
mediaRecorder.ondataavailable = (e)=>{ chunks.push(e.data) }
mediaRecorder.onstop = ()=>{ 
  console.log("Done recording. Now let's try playback...")
  let fileReader = new FileReader() // to convert blob to data url
  fileReader.onload = (e)=>{   
    $buzz({ src: e.target.result, format: "webm", 
       onerror: (err) => console.log('Error', err) }).play()
  } 
  fileReader.readAsDataURL(new Blob(chunks)) // sends url to onLoad
}

// start sound and recording 
sound.play(); mediaRecorder.start()  

// stop in a few seconds 
setTimeout( ()=>{ mediaRecorder.stop(); sound.stop() }, 5000)