Audi oplayback and Recording from buffer


#1

Okay, so I have gotten my code to record to the buffer and play from it. The issue I have now is when I go back to record a second time it starts playing back as it’s recording even though the play boolean is set to false

#ifndef MAINCOMPONENT_H_INCLUDED
#define MAINCOMPONENT_H_INCLUDED

#include "../JuceLibraryCode/JuceHeader.h"
#include "Display.h"
#include "AudioVisual.h"


//==============================================================================
/*
    This component lives inside our window, and this is where you should put all
    your controls and content.
*/

class recorda   :   public AudioIODeviceCallback
{

public:
    recorda (AudioThumbnail& thumbnailToUpdate)
        :   thumbnail(thumbnailToUpdate),
            backgroundThread ("Audio Recorder Thread"),
            sampleRate(0), nextSampleNum (0), activeWriter(nullptr)
    
    {
        backgroundThread.startThread();
        
        trackOne.setSize(2, 0, false, true, false);
    }
    
    ~recorda()
    {
        stop();
    }
    
    
    void startAD()
    {
        deviceManager.addAudioCallback(this);
        deviceManager.initialise(2, 2, 0, true, "Headphones", nullptr);
    }
    void startRec()
    {
        playing=false;
        startAD();
        if (sampleRate > 0)
        {
            trackOne.clear();
          
           
        }
    }
    void closeAD()
    {
        deviceManager.closeAudioDevice();
        audioDeviceStopped();
        std::cout<<"recording: " << recording<<std::endl;
        std::cout<<"playing " << playing<<std::endl;
    }
    
    void stop()
    {
        recording = false;
        closeAD();
       
    }

    
    bool playing;
    bool recording;
  
    
    void audioDeviceAboutToStart (AudioIODevice* device) override
    {
        
        sampleRate = device -> getCurrentSampleRate();
    }
    
    void audioDeviceStopped() override
    {
        sampleRate = 0;
    }
    

    //AudioIODevice, AudioDeviceManager, getCurrentSampleRate
        
    void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels,
                                float** outputChannelData, int numOutputChannels,
                                int numSamples) override
   {
       std::cout<<"recording: " << recording<<std::endl;
       std::cout<<"playing " << playing<<std::endl;
       
       
       int oldSampleSize = trackOne.getNumSamples();
       int channelNumber = trackOne.getNumChannels();
if (recording == true)
{
    
       trackOne.setSize( trackOne.getNumChannels(),
                        oldSampleSize + numSamples,
                        true,
                        true,
                        false);
       trackOneOutput.setSize(trackOneOutput.getNumChannels(),
                              oldSampleSize + numSamples,
                              true,
                              true,
                              false);
       
       for(int j = 0; j < channelNumber; ++j){
           
           trackOne.copyFrom(j, oldSampleSize, inputChannelData[j], numSamples);
       }
        for(int i=0; i<numOutputChannels; ++i)
        {
            if(outputChannelData[i] != nullptr)
            {
                FloatVectorOperations::clear(outputChannelData[i], numSamples);
            }
        }

    }
       
if(playing == true)
{

   
      for (int i = 0; i < numOutputChannels; ++i)
            {
               if (outputChannelData[i] != nullptr)
                {
                    for(int samples=0; samples<numSamples; ++samples)
                    {
                        if(position >= trackOne.getNumSamples())
                        {
                            
                            position = 0;
                        }
                        float sample = trackOne.getSample(i, samples+position);
                        
                        outputChannelData[i][samples] = sample;
                        //std::cout<<sample;
                    }
                
                }
          }
           position += numSamples;
    std::cout<<position<<std::endl;
     }
    }
int position;
    
private:
    AudioFormatManager formatManager;
    AudioThumbnail& thumbnail;
    TimeSliceThread backgroundThread;
    ScopedPointer<AudioFormatWriter::ThreadedWriter> threadedWriter;
    ScopedPointer<AudioFormatReaderSource> currentRecordingSource;
    double sampleRate;
    int64 nextSampleNum;
    AudioSampleBuffer trackOne, trackOneOutput, trackTwo, trackThree, trackFour;
    AudioDeviceManager deviceManager;
    
    
    
    
    
    CriticalSection writerLock;
    AudioFormatWriter::ThreadedWriter* volatile activeWriter;
};
    
class RecordingThumb    : public Component,
                          private ChangeListener
{
public:
    RecordingThumb()
        :thumbnailCache (10),
         thumbnail (512, formatManager, thumbnailCache),
         displayFullThumb(false)
         
    {
        
        formatManager.registerBasicFormats();
        thumbnail.addChangeListener (this);
    }
    
    ~RecordingThumb()
    {
        thumbnail.removeChangeListener (this);
    }
    
    AudioThumbnail& getAudioThumbnail() {return thumbnail;}
    
    void displayFullThumbnail (bool displayFull)
    {
        displayFullThumb = displayFull;
        repaint();
    }
    
    void paint (Graphics& g)override
    {
        g.fillAll (Colours::darkgrey);
        g.setColour (Colours::lightgrey);
        
        if (thumbnail.getTotalLength() > 0.0)
        {
            const double endTime = displayFullThumb ? thumbnail.getTotalLength() : jmax (30.0, thumbnail.getTotalLength());
            
            Rectangle<int> thumbArea (getLocalBounds());
            thumbnail.drawChannels (g, thumbArea.reduced (2), 0.0, endTime, 1.0f);
        }
        else
        {
            g.setFont(14.0f);
            g.drawFittedText("(No file recorded)", getLocalBounds(), Justification::centred, 2);
        }
    }
    
private:

    AudioFormatManager formatManager;
    AudioThumbnailCache thumbnailCache;
    AudioThumbnail thumbnail;

    bool displayFullThumb;

    void changeListenerCallback(ChangeBroadcaster* source) override
        {
            if(source == &thumbnail)
                repaint();
        }
    
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RecordingThumb)
};

class MainContentComponent   : public AudioAppComponent,
                               public ChangeListener,
                               
                               public Button::Listener
{
public:


    //==============================================================================
    MainContentComponent()
    :
      recorder(recordingThumb.getAudioThumbnail())
      
    {
        setOpaque(true);
        addAndMakeVisible(audioVis);
        
        addAndMakeVisible(recordingThumb);
        
        
        addAndMakeVisible (&playButton);
        playButton.setButtonText("Play");
        playButton.addListener(this);
        playButton.setColour(TextButton::buttonColourId, Colours::green);
        playButton.setEnabled(true);
        
        addAndMakeVisible(&stopButton);
        stopButton.setButtonText("Stop");
        stopButton.addListener(this);
        stopButton.setColour(TextButton::buttonColourId, Colours::red);
        stopButton.setEnabled(true);
        
        addAndMakeVisible (recordingButton);
        recordingButton.setButtonText ("Record");
        recordingButton.addListener (this);
        recordingButton.setColour (TextButton::buttonColourId, Colour (0xffff5c6f));
        recordingButton.setColour (TextButton::textColourOnId, Colours::black);
        recordingButton.setEnabled(true);
        
        addAndMakeVisible(stopRecordingButton);
        stopRecordingButton.setButtonText("Stop Recording");
        stopRecordingButton.addListener (this);
        stopRecordingButton.setColour (TextButton::buttonColourId, Colour(0x44444444));
        stopRecordingButton.setColour(TextButton::textColourOnId, Colours::white);
        
        
        
        
        addAndMakeVisible(recordingPlayButton);
        recordingPlayButton.setButtonText("Play");
        recordingPlayButton.addListener(this);
        recordingPlayButton.setColour(TextButton::buttonColourId, Colours::green);
        recordingPlayButton.setEnabled(false);
        
        
        
        
        
        

        setSize (800, 600);
        
        formatManager.registerBasicFormats();
        transportSource.addChangeListener(this);
        deviceManager.removeAudioCallback(&audioVis);
        deviceManager.removeAudioCallback(&recorder);

        
        // specify the number of input and output channels that we want to open
        
    }

    ~MainContentComponent()
    {
        shutdownAudio();
        deviceManager.removeAudioCallback (&recorder);
        deviceManager.removeAudioCallback(&audioVis);
    }
    
    void changeListenerCallback (ChangeBroadcaster* source) override
    {
       
        
    }
    
    

    //=======================================================================
   void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override
    {
       
        
        
    }

    void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
    {
       
      
    }


    void releaseResources() override
    {
        
        
    }

    //=======================================================================
    void paint (Graphics& g) override
    {
        // (Our component is opaque, so we must completely fill the background with a solid colour)
        g.fillAll (Colours::lightblue);


        // You can add your drawing code here!
    }

    void resized() override
    {

        
        Rectangle<int> stuff (getLocalBounds());
        //audioVis.setBounds(stuff.removeFromTop(80).reduced (8));
        recordingThumb.setBounds(stuff.removeFromTop(100).removeFromRight(600).reduced(8));
        recordingButton.setBounds (10, 105, (getWidth()/4) -20, 20);
        stopRecordingButton.setBounds (10, 135, (getWidth()/4) -20, 20);
       
        
        playButton.setBounds(10, 45, (getWidth()/4) - 20, 20);
        stopButton.setBounds(10, 75, (getWidth()/4) -20, 20);
        
         
        
        
    }
    
     void startRecording()
    {
        
        recorder.playing=false;
        recorder.recording=true;
        recorder.startRec();
       
       
       
       
        
        
    }
    void stopRecording()
    {
        recorder.stop();
        recorder.recording = false;
       
       
    }
    
   
    
    void buttonClicked (Button* button) override
    {
        
       
   
        if(button == &playButton) playButtonClicked();
        if(button == &stopButton) stopButtonClicked();
        if (button == &recordingButton) startRecording();
        if (button == &stopRecordingButton) stopRecording();
    }
    
 
    
  
    
    
            
    
    void playButtonClicked()
    {
        setAudioChannels(2,2);
        recorder.startAD();
        recorder.playing=true;
        recorder.recording=false;
        recorder.position = 0;
        
    }
    
    void stopButtonClicked()
    {
        recorder.playing = false;
        recorder.closeAD();
        //recordingThumb.displayFullThumbnail(true);
    }


private:
    //==============================================================================

    // Your private member variables go here...

    AudioFormatManager formatManager;
    
    AudioVisual audioVis;
    RecordingThumb recordingThumb;
    recorda recorder;
    //LiveScrollingAudioDisplay liveAudioScroller;
    ScopedPointer<AudioFormatReaderSource> readerSource;
    AudioTransportSource transportSource;
   
    TextButton openButton;
    TextButton playButton;
    TextButton stopButton;
    TextButton recordingButton;
    TextButton stopRecordingButton;
    TextButton recordingPlayButton;
    
    Display display;
    Display display2;
    Display display3;
    Display display4;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};


// (This function is called by the app startup code to create our main component)
Component* createMainContentComponent()     { return new MainContentComponent(); }


#endif  // MAINCOMPONENT_H_INCLUDED

#2

Not really sure whats happening, but you definitely shouldn’t be allocating any memory in your io callback. You need to allocate enough space audioDeviceAboutToStart method.


#3

This is a really bad approach… We already have a class that solves this problem: AudioFormatWriter::ThreadedWriter. You’d be crazy to try to roll your own version if you don’t really understand how this kind of thing works.

Obviously it’s totally possible to use our class to record to a MemoryOutputStream rather than a file stream, and it’ll also take care of the thumbnail stuff for you.