Code Monkey home page Code Monkey logo

Comments (12)

mudcube avatar mudcube commented on August 22, 2024

This might not be very helpful. This takes a OGG blob and converts it into audio buffers:

var worker = new Worker('./oggopusDecoder.js')
worker.postMessage(recorder.config); // uses same config as for recording
worker.addEventListener("error", function(e) {
    console.log(e);
});
worker.addEventListener("message", function(e) {
    console.log(e.data);
});
///
var reader = new FileReader();
reader.onload = function(event) {
    worker.postMessage({
        command: "decode",
        pages: new Uint8Array(this.result)
    });
};
reader.readAsArrayBuffer(blob);

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

Thanks for the snippet. I have started an example in a seperate repo, but it's not complete.

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

@super-coder I've removed comments unrelated to this issue. Please open a new issue if you have an issue or questions about the lib.

from opus-recorder.

brancusi avatar brancusi commented on August 22, 2024

Hi,

Would it be possible to outline how to go from encoded blob to playing back via a AudioContext destination? I would like to connect to a gain node and playback through there.

I have tried getting this example working as well as the other repo. I see the output from the decoder is a Float32Array is returned, what is the next step to get this actually playing though?

Thank you

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

@brancusi: The decoder returns an array of buffers (one for each channel)

  • Configure the decoder to decode at your context sample rate using config option { outputBufferSampleRate : audioContext.sampleRate }
  • Store each buffer as it is decoded (it will send a message with null payload when it is finished)
  • Create an audioContext buffer with appropriate length (number of decoded buffers * decoded buffer length)
  • Fill audioContext buffer with decoded data
  • Playback audioContext buffer
  • Sample code at MDN

from opus-recorder.

brancusi avatar brancusi commented on August 22, 2024

Thanks @chris-rudmin, got it working!

This returns a promise and resolves with a source that can be started. A little lengthy but works for now. Does anything pop out at you as being a potential problem?

Thanks again for the great library!

/**
   * Create a buffer source from an ogg blob
   * @param {Blob} The ogg blob created by recorderjs
   * @param {AudioContext} An instance of an AudioContext to create the bufferSource with
   * @param {Integer} Numbers of channels, defaults to 2
   * @returns {Promise} A promise that will resolve with an AudioBufferSourceNode prefilled with the ogg blob data, ready for playback
   */
  createBufferSource ( blob, audioContext, channels = 2 ) {
    return new Promise((res, rej) => {
      const decoder = new OpusDecoderWorker();
      const buffers = [];
      const config = {
        outputBufferSampleRate : audioContext.sampleRate,
        bufferLength : 4096
      }

      decoder.onmessage = e => {
        if (e.data === null) {

          var frameCount = buffers.length * config.bufferLength;
          var audioBuffer = audioContext.createBuffer(channels, frameCount, audioContext.sampleRate);

          // Fill the channel data
          for (let channel = 0; channel < channels; channel++) {
            var channgelBuffer = audioBuffer.getChannelData(channel);
            buffers
              .map((buffer, i) => {
                (buffer[channel] || buffer[0])
                  .forEach((frame, j) => {
                    channgelBuffer[(i*config.bufferLength)+j] = frame;
                  });
              });
          }

          const source = audioContext.createBufferSource();
          source.buffer = audioBuffer;
          source.connect(audioContext.destination);

          // Resolve the promise
          res(source);
        } else {
          buffers.push(e.data);
        }
      };

      // Initialize the decoder
      decoder.postMessage({ command: "init", config: config });

      // Load blob
      const reader = new FileReader();
      reader.onload = e => {
        decoder.postMessage({ command: "decode", pages: new Uint8Array(reader.result)});
        decoder.postMessage({ command: 'done' });
      };
      reader.readAsArrayBuffer(blob);

    });
  }

P.S. This is working in a react app using the worker-loader to wrap the worker scripts in case anyone wonders about that new worker line.

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

@brancusi Looks good. Is this pure ECMASCript 6 code? I'm unfamiliar with => syntax. Does defining a value as const make it immutable? Seems strange to make an array which you push to a constant.

from opus-recorder.

brancusi avatar brancusi commented on August 22, 2024

@chris-rudmin ok cool. Yes this is es6 syntax. The => is a new way to declare an anonymous function that will bind any this references to current outer scope. Gets us away from having to do, var self = this;

As for Const, it just makes the reference read-only but you can still mutate the underlying array in our case. I think it adds some clarity of intend mostly, none of the refs will be redeclared inside that promise.

Under the hood right now this all gets compiled to es5 any way, so const become var. Babel

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

@brancusi One thing I might add, you could get better performance and higher fidelity playback (at the expense of more memory) if you can create the buffer source at with a sample rate of 48000. This is the native decoder rate of opus and it will avoid you using my lo-fi resampler.

from opus-recorder.

brancusi avatar brancusi commented on August 22, 2024

Thanks @chris-rudmin, I will definitely swap that out. Will it matter if the audioContext's rate is different? Or should that be set (can it be set?) before hand to 48000 as well?

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

My understanding is that it will use the browsers internal resampling algorithm which should be faster and of higher quality than a resampler implemented in js. However I have not tested this.

from opus-recorder.

chris-rudmin avatar chris-rudmin commented on August 22, 2024

Added a decoder example in the examples folder!

from opus-recorder.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.