Recording audio AudioIODeviceCallback doesn't works


#1

I’m trying to record some audio with a class derived from AudioIODeviceCallback. I’m using the AudioRecordingDemo as a template, but the recording doesn’t works. I’m playing some PureData patches too (that works fine). Maybe could someone say me is still missing? I’m posting here only a part of the code, the classes are big. I tested it on OSX, Windows and Linux with both aiff and wav formats, without results.

AudioRecorder::AudioRecorder() {
    backgroundThread.startThread(); 
}

AudioRecorder::~AudioRecorder() {
    if(isRecording())
        stopRecording();
    closePdResources();
    
    threadedWriter.reset();
}

 void AudioRecorder::startRecording(const juce::File &file) {
    stopRecording();
    
    if (sampleRate > 0) {
        file.deleteFile();
        std::unique_ptr<juce::FileOutputStream> fileStream (file.createOutputStream());
       
        if (fileStream.get() != nullptr) {
    #if JUCE_MAC
                juce::AiffAudioFormat aiffFormat;
                auto* writer = aiffFormat.createWriterFor (fileStream.get(), sampleRate, 1, bitDepth, {}, 0);
 #else
                juce::WavAudioFormat wavFormat;
                auto* writer = wavFormat.createWriterFor (fileStream.get(), sampleRate, 1, bitDepth, {}, 0);
    #endif
 
            if (writer != nullptr) {
                fileStream.release(); 
               threadedWriter.reset (new juce::AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768));
                const juce::ScopedLock sl (writerLock);
                activeWriter = threadedWriter.get();
            }
        }
    }
}

void AudioRecorder::stopRecording() {
    {
        const juce::ScopedLock sl (writerLock);
        activeWriter = nullptr;
    }
    threadedWriter.reset();
}

bool AudioRecorder::isRecording() const {
    return activeWriter.load() != nullptr;
}

void AudioRecorder::audioDeviceAboutToStart(juce::AudioIODevice *device) {
     sampleRate = device->getCurrentSampleRate();
     initPd(sampleRate); //There is no problem here, that works fine
}
void AudioRecorder::audioDeviceIOCallback(const float** inputChannelData, int numInputChannels, float** outputChannelData, int numOutputChannels, int numSamples) {
    if(!isRecording()) {
        fillPdOutput(outputChannelData, numOutputChannels, numSamples);
    }
    else {
        const juce::ScopedLock sl (writerLock);
        if (activeWriter.load() != nullptr ) {
            wrote = activeWriter.load()->write (inputChannelData, numSamples);                
        }
        fillPdOutput(outputChannelData, numOutputChannels, numSamples); //fillPdOutput works fine, it refers to some stuff with Pure Data
        
    }
}

and in the Main Component class:
in Component constructor:
formatManager.registerBasicFormats();
audioDeviceManager.initialise (1, 2, nullptr, true, {}, nullptr);

…more stuff

void MainComponent::initializeAudioResources() {
    recorder = std::make_shared<AudioRecorder>();
    audioDeviceManager.addAudioCallback(recorder.get());
    isAudioInitialized = true;
}

void MainComponent::releaseAudioResources() {
    audioDeviceManager.removeAudioCallback(recorder.get());
    recorder.reset();
    isAudioInitialized = false;
}

void MainComponent::startMicrophoneRecording() {
    isMicrophoneRecord = true;
    auto parentDir = juce::File::getSpecialLocation(juce::File::userDocumentsDirectory);

#if JUCE_MAC
    lastRecording = parentDir.getNonexistentChildFile ("MyRecord", ".aiff");
#else
    lastRecording = parentDir.getNonexistentChildFile("MyRecord", ".wav");
#endif
    recorder->startRecording(lastRecording);
    startMetronome(); //this methode works
}

void MainComponent::stopMicrophoneRecording() {
    recorder->stopRecording();
    lastRecording = juce::File();
    stopMetronome();
    releaseAudioResources();
}

#2

I answer to myself. I didn’t know I have to add the following permissions at the file Info-App.plist:
<key>NSMicrophoneUsageDescription</key>
<string>This app requires requires audio input. If you do not have an audio interface connected it will use the built-in microphone.</string>
<key>NSCameraUsageDescription</key>
<string>This app requires access to the camera function correctly.</string>
This is necessary since OSX Mojave. The recording class was working properly before, I didn’t realize this new requirement.


#3

Yes this is new in Mojave. If you re-build the Projucer from the develop branch then there is now an option to enable this permission in the Xcode exporter.