/* ============================================================================== This is an automatically generated file created by the Jucer! Creation date: 1 May 2011 12:08:25pm Be careful when adding custom code to these files, as only the code within the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded and re-saved. Jucer version: 1.12 ------------------------------------------------------------------------------ The Jucer is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-6 by Raw Material Software ltd. ============================================================================== */ //[Headers] You can add your own extra header files here... //[/Headers] #include "AudioDemoRecordPage.h" //[MiscUserDefs] You can add your own user definitions and misc code here... //============================================================================== /** A simple class that acts as an AudioIODeviceCallback and writes the incoming audio data to a WAV file. */ class AudioRecorder : public AudioIODeviceCallback { public: AudioRecorder() : backgroundThread ("Audio Recorder Thread"), sampleRate (0), activeWriter (0) { backgroundThread.startThread(); } ~AudioRecorder() { stop(); } //============================================================================== void startRecording (const File& file) { stop(); if (sampleRate > 0) { // Create an OutputStream to write to our destination file... file.deleteFile(); ScopedPointer fileStream (file.createOutputStream()); if (fileStream != 0) { // Now create a WAV writer object that writes to our output stream... WavAudioFormat wavFormat; AudioFormatWriter* writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0); if (writer != 0) { fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it) // Now we'll create one of these helper objects which will act as a FIFO buffer, and will // write the data to disk on our background thread. threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768); // And now, swap over our active writer pointer so that the audio callback will start using it.. const ScopedLock sl (writerLock); activeWriter = threadedWriter; } } } } void stop() { // First, clear this pointer to stop the audio callback from using our writer object.. { const ScopedLock sl (writerLock); activeWriter = 0; } // Now we can delete the writer object. It's done in this order because the deletion could // take a little time while remaining data gets flushed to disk, so it's best to avoid blocking // the audio callback while this happens. threadedWriter = 0; } bool isRecording() const { return activeWriter != 0; } //============================================================================== void audioDeviceAboutToStart (AudioIODevice* device) { sampleRate = device->getCurrentSampleRate(); } void audioDeviceStopped() { sampleRate = 0; } void audioDeviceIOCallback (const float** inputChannelData, int /*numInputChannels*/, float** outputChannelData, int numOutputChannels, int numSamples) { const ScopedLock sl (writerLock); if (activeWriter != 0) activeWriter->write (inputChannelData, numSamples); // We need to clear the output buffers, in case they're full of junk.. for (int i = 0; i < numOutputChannels; ++i) if (outputChannelData[i] != 0) zeromem (outputChannelData[i], sizeof (float) * numSamples); } private: TimeSliceThread backgroundThread; // the thread that will write our audio data to disk ScopedPointer threadedWriter; // the FIFO used to buffer the incoming data double sampleRate; CriticalSection writerLock; AudioFormatWriter::ThreadedWriter* volatile activeWriter; }; //[/MiscUserDefs] //============================================================================== AudioDemoRecordPage::AudioDemoRecordPage (AudioDeviceManager& deviceManager_) : deviceManager (deviceManager_), liveAudioDisplayComp (0), explanationLabel (0), recordButton (0) { addAndMakeVisible (liveAudioDisplayComp = new LiveAudioInputDisplayComp()); addAndMakeVisible (explanationLabel = new Label (String::empty, L"This page demonstrates how to record a wave file from the live audio input..\n\nPressing record will start recording a file in your \"Documents\" folder.")); explanationLabel->setFont (Font (15.0000f, Font::plain)); explanationLabel->setJustificationType (Justification::topLeft); explanationLabel->setEditable (false, false, false); explanationLabel->setColour (TextEditor::textColourId, Colours::black); explanationLabel->setColour (TextEditor::backgroundColourId, Colour (0x0)); addAndMakeVisible (recordButton = new TextButton (String::empty)); recordButton->setButtonText (L"Record"); recordButton->addListener (this); recordButton->setColour (TextButton::buttonColourId, Colour (0xffff5c5c)); recordButton->setColour (TextButton::textColourOnId, Colours::black); //[UserPreSize] //[/UserPreSize] setSize (600, 400); //[Constructor] You can add your own custom stuff here.. recorder = new AudioRecorder(); deviceManager.addAudioCallback (recorder); deviceManager.addAudioCallback (liveAudioDisplayComp); //[/Constructor] } AudioDemoRecordPage::~AudioDemoRecordPage() { //[Destructor_pre]. You can add your own custom destruction code here.. deviceManager.removeAudioCallback (recorder); deviceManager.removeAudioCallback (liveAudioDisplayComp); recorder = 0; //[/Destructor_pre] deleteAndZero (liveAudioDisplayComp); deleteAndZero (explanationLabel); deleteAndZero (recordButton); //[Destructor]. You can add your own custom destruction code here.. //[/Destructor] } //============================================================================== void AudioDemoRecordPage::paint (Graphics& g) { //[UserPrePaint] Add your own custom painting code here.. //[/UserPrePaint] g.fillAll (Colours::lightgrey); //[UserPaint] Add your own custom painting code here.. //[/UserPaint] } void AudioDemoRecordPage::resized() { liveAudioDisplayComp->setBounds (8, 8, getWidth() - 16, 64); explanationLabel->setBounds (160, 88, getWidth() - 169, 216); recordButton->setBounds (8, 88, 136, 40); //[UserResized] Add your own custom resize handling here.. //[/UserResized] } void AudioDemoRecordPage::buttonClicked (Button* buttonThatWasClicked) { //[UserbuttonClicked_Pre] //[/UserbuttonClicked_Pre] if (buttonThatWasClicked == recordButton) { //[UserButtonCode_recordButton] -- add your button handler code here.. if (recorder->isRecording()) { recorder->stop(); } else { File file (File::getSpecialLocation (File::userDocumentsDirectory) .getNonexistentChildFile ("Juce Demo Audio Recording", ".wav")); recorder->startRecording (file); } if (recorder->isRecording()) recordButton->setButtonText ("Stop"); else recordButton->setButtonText ("Record"); //[/UserButtonCode_recordButton] } //[UserbuttonClicked_Post] //[/UserbuttonClicked_Post] } void AudioDemoRecordPage::visibilityChanged() { //[UserCode_visibilityChanged] -- Add your code here... recorder->stop(); recordButton->setButtonText ("Record"); //[/UserCode_visibilityChanged] } //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... //[/MiscUserCode] //============================================================================== #if 0 /* -- Jucer information section -- This is where the Jucer puts all of its metadata, so don't change anything in here! BEGIN_JUCER_METADATA END_JUCER_METADATA */ #endif