Search code examples
expressmp3pcmlamenode-lame

Why does node-lame module saves mp3 file with a high pitched/fast playback speed?


I am trying to record audio from the browser and stream it as raw audio (PCM) to my node server where I want to save to it in .mp3 format. I am using node-lame module on my server for creating an mp3 file from the PCM audio stream. The problem here is that the mp3 file is always high pitched and playing at a fast speed. I have tried both sending the data from the browser(client side) as int16 and as float32 and setting the appropriate lame.Encoder for them :

stream.pipe(new lame.Encoder({channels:2, bitDepth: 32, float:true,})) //float32
.pipe(fs.createWriteStream(path.resolve(__dirname, 'demo.mp3')))

stream.pipe(new lame.Encoder({channels:2, bitDepth: 16, sampleRate:44100,})) // int16
    .pipe(fs.createWriteStream(path.resolve(__dirname, 'demo.mp3')))

Here is the code for the client side

  (function(window) {
  var client = new BinaryClient('ws://localhost:9001');

  client.on('open', function() {
    window.Stream = client.createStream();

    if (!navigator.getUserMedia)
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia || navigator.msGetUserMedia;

    if (navigator.getUserMedia) {
      navigator.getUserMedia({audio:true}, success, function(e) {
        alert('Error capturing audio.');
      });
    } else alert('getUserMedia not supported in this browser.');

    var recording = false;

    window.startRecording = function() {
      recording = true;
    }

    window.stopRecording = function() {
      recording = false;
      window.Stream.end();
    }

    function success(e) {
      audioContext = window.AudioContext || window.webkitAudioContext;
      context = new audioContext();

      // the sample rate is in context.sampleRate
      audioInput = context.createMediaStreamSource(e);

      var bufferSize = 2048;
      recorder = context.createScriptProcessor(bufferSize, 1, 1);

      recorder.onaudioprocess = function(e){
        if(!recording) return;
        console.log ('recording');
        var left = e.inputBuffer.getChannelData(0);
        window.Stream.write(left); //trying it with float32
      }

      audioInput.connect(recorder)
      recorder.connect(context.destination);
    }

    function convertoFloat32ToInt16(buffer) {
      var l = buffer.length;
      var buf = new Int16Array(l)

      while (l--) {
        buf[l] = buffer[l]*0xFFFF;    //convert to 16 bit
      }
      return buf.buffer
    }
  });
})(this);

Here is the node app

    var express = require('express');
var BinaryServer = require('binaryjs').BinaryServer;
var fs = require('fs');
var lame = require("lame");
var path = require('path');
var KalmanFilter = require('kalmanjs').default;
var buffer = [];


var port = 3700;
var outFile = 'demo.mp3';
var app = express();

app.set('views', __dirname + '/tpl');
app.set('view engine', 'jade');
app.engine('jade', require('jade').__express);
app.use(express.static(__dirname + '/public'))

app.get('/', function(req, res){
  res.render('index');
});

app.listen(port);

console.log('server open on port ' + port);

binaryServer = BinaryServer({port: 9001});

binaryServer.on('connection', function(client) {
  console.log('new connection');


  client.on('stream', function(stream, meta) {
    console.log('new stream');

       stream.pipe(new lame.Encoder({channels:2, bitDepth: 32, float:true}))
.pipe(fs.createWriteStream(path.resolve(__dirname, 'demo.mp3')))
    .on('close',function () {
      console.log('done?');
    })

    stream.on('end', function() {
      console.log('wrote to file ' + outFile);
    });
  });
});

Both of these snippets are taken from https://github.com/gabrielpoca/browser-pcm-stream except for the mp3 part.


Solution

  • The default sampling rate in the browser is 48000hz, while you are encoding your mp3 files with a sampling rate of 44100hz. You either need to resample your PCM data or set the recording sampling rate to 44100hz.