gillesdemey / node-record-lpcm16

:microphone: Records a 16-bit signed-integer linear pulse modulation code encoded audio file.
ISC License
212 stars 60 forks source link

2 concurrent recorders on RaspberryPi? #33

Closed 5nyper closed 7 years ago

5nyper commented 7 years ago

I have this code that I want to execute:

let fs = require('fs')
let record = require('node-record-lpcm16');
let {Detector, Models} = require('snowboy');

let models = new Models();

models.add({file: 'resources/francisco.pmdl', sensitivity: '0.5', hotwords : 'francisco'});

const detector = new Detector({
  resource: "resources/common.res",
  models: models,
  audioGain: 2.0
});

detector.on('hotword', function (index, hotword) {
  if(hotword === 'francisco') {
    let file = fs.createWriteStream('command.wav', { encoding: 'binary' })
    record.start({
      sampleRateHertz: 16000,
      threshold: 1,
      silence: '1.0',
      verbose: true
    }).pipe(file);
  }
});

record.start({
  sampleRateHertz: 16000,
  threshold: 0,
}).pipe(detector);

console.log('Listening...');

The recorder thats piped detector works, but when the hot word is detected and the 2nd recorder is initiated, the 2nd recording stops recording immediately (meaning no audio was even recorded). Now there was this one time I was running this script and instead of exiting I stopped it (so it was running in the background) and I went to use rec temp.wav and I got an error saying that the device was busy, yet this script works perfectly fine on my OSX as I was able to initiate both recorders.

So is this an issue with the library, RaspberryPi (3), or my microphone USB?

mreinstein commented 7 years ago

Unfortunately, this isn't going to work because node-record-lpcm16 is essentially a singleton internally.

5nyper commented 7 years ago

Is there a reason why node-record-lpcm16 works with 2 concurrent recordings on OSX if its singleton by design?

mreinstein commented 7 years ago

This logic right now seems to be attempting to save audio to a file when a hotword is detected. Each time a hotword is detected, the code will attempt to overwrite the command.wav file.

I guess I'm not sure what you're trying to accomplish with your code. It might make sense to back up and explain your high level goal.

5nyper commented 7 years ago

It's like Amazon Alexa, You'd say a hot word like 'Alexa' then the script records audio and whatever you say after the hotword is recored to command.wav, then that audio file is your command

I.E:

'Alexa, Whats the Weather?' Then 'Whats the Weather' would be saved in command.wav and the outer recording would continue to hear for more 'Alexa's to record more commands

mreinstein commented 7 years ago

@Vikaton this is pseudo code, but I think it will give you the type of structure you're looking for. there's an idle mode, which listens for hotword, and a record mode, which streams wav audio to a file. It ping pongs back and forth between these 2 modes:

const fs = require('fs')
// TODO: snowboy setup here

function idleMode() {
  console.log('listening for hotword')
  let detector = snowboy()

  detector.on('hotword', function(index, hotword) {
    record.stop()
    console.log('detected hotword, recording audio')
    recordingMode()
  }))

  record.start().pipe(detector)
}

function recordingMode() {
  const out = fs.createWriteStream('out.wav')

  record
    .start()
    .on('close', function() {
      console.log('finished recording audio')
      idleMode()
    })
    .pipe(out)
}

idleMode()
5nyper commented 7 years ago

I think I tried this earlier with my rPi but didnt wait for the recording to stop so it exited the application, thanks! Will try again but with better device handling

5nyper commented 7 years ago

Issue was that I needed the declaration of detector in idle() Thank you!

mreinstein commented 7 years ago

glad it worked! :)

stursby commented 7 years ago

@Vikaton Would you mind posting you working code? I'm trying to achieve something very similar (on Mac right now, but eventually Pi or something close) and the process is exiting on its own after around 5 seconds or so. (cc @mreinstein)

Here's my current code

// Dependencies
const fs = require('fs')
const record = require('node-record-lpcm16')
const { Detector, Models } = require('snowboy')

// Setup
const models = new Models()

// Add 'jeeves' model
models.add({
  file: 'resources/jeeves.pmdl',
  sensitivity: '0.5',
  hotwords: 'jeeves'
})

// Idle Mode
function idleMode() {
  console.log('listening for hotword')

  let detector = new Detector({
    resource: 'resources/common.res',
    models: models,
    audioGain: 2.0
  })

  detector.on('silence', () => {
    console.log('silence')
  })

  detector.on('sound', () => {
    console.log('sound')
  })

  detector.on('error', () => {
    console.log('error')
  })

  detector.on('hotword', (index, hotword) => {
    if (hotword === 'jeeves') {
      record.stop()
      console.log('detected hotword, recording audio')
      recordingMode()
    }
  })

  record.start().pipe(detector)
}

// Recording Mode
function recordingMode() {
  const out = fs.createWriteStream('out.wav')

  record
    .start()
    .on('close', () => {
      console.log('finished recording audio')
      idleMode()
    })
    .pipe(out)
}

// Start! (in Idle Mode)
idleMode()

And here's a sample output (exiting on its own 3 times in a row)

image

And the out.wav works, but still the same exiting issue.

5nyper commented 7 years ago

I just tried your exact code and its not exiting, maybe an issue with the recording program itself?