|
- /*
- ==============================================================================
-
- This is an automatically generated file created by the Jucer!
-
- Creation date: 13 Nov 2009 3:52:50 pm
-
- 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...
-
- //==============================================================================
- /* This is a rough-and-ready circular buffer, used to allow the audio thread to
- push data quickly into a queue, allowing a background thread to come along and
- write it to disk later.
- */
- class CircularAudioBuffer
- {
- public:
- CircularAudioBuffer (const int numChannels, const int numSamples)
- : buffer (numChannels, numSamples)
- {
- clear();
- }
-
- ~CircularAudioBuffer()
- {
- }
-
- void clear()
- {
- buffer.clear();
-
- const ScopedLock sl (bufferLock);
- bufferValidStart = bufferValidEnd = 0;
- }
-
- void addSamplesToBuffer (const AudioSampleBuffer& sourceBuffer, int numSamples)
- {
- const int bufferSize = buffer.getNumSamples();
-
- bufferLock.enter();
- int newDataStart = bufferValidEnd;
- int newDataEnd = newDataStart + numSamples;
- const int actualNewDataEnd = newDataEnd;
- bufferValidStart = jmax (bufferValidStart, newDataEnd - bufferSize);
- bufferLock.exit();
-
- newDataStart %= bufferSize;
- newDataEnd %= bufferSize;
-
- if (newDataEnd < newDataStart)
- {
- for (int i = jmin (buffer.getNumChannels(), sourceBuffer.getNumChannels()); --i >= 0;)
- {
- buffer.copyFrom (i, newDataStart, sourceBuffer, i, 0, bufferSize - newDataStart);
- buffer.copyFrom (i, 0, sourceBuffer, i, bufferSize - newDataStart, newDataEnd);
- }
- }
- else
- {
- for (int i = jmin (buffer.getNumChannels(), sourceBuffer.getNumChannels()); --i >= 0;)
- buffer.copyFrom (i, newDataStart, sourceBuffer, i, 0, newDataEnd - newDataStart);
- }
-
- const ScopedLock sl (bufferLock);
- bufferValidEnd = actualNewDataEnd;
- }
-
- int readSamplesFromBuffer (AudioSampleBuffer& destBuffer, int numSamples)
- {
- const int bufferSize = buffer.getNumSamples();
-
- bufferLock.enter();
- int availableDataStart = bufferValidStart;
- const int numSamplesDone = jmin (numSamples, bufferValidEnd - availableDataStart);
- int availableDataEnd = availableDataStart + numSamplesDone;
- bufferValidStart = availableDataEnd;
- bufferLock.exit();
-
- availableDataStart %= bufferSize;
- availableDataEnd %= bufferSize;
-
- if (availableDataEnd < availableDataStart)
- {
- for (int i = jmin (buffer.getNumChannels(), destBuffer.getNumChannels()); --i >= 0;)
- {
- destBuffer.copyFrom (i, 0, buffer, i, availableDataStart, bufferSize - availableDataStart);
- destBuffer.copyFrom (i, bufferSize - availableDataStart, buffer, i, 0, availableDataEnd);
- }
- }
- else
- {
- for (int i = jmin (buffer.getNumChannels(), destBuffer.getNumChannels()); --i >= 0;)
- destBuffer.copyFrom (i, 0, buffer, i, availableDataStart, numSamplesDone);
- }
-
- return numSamplesDone;
- }
-
- private:
- CriticalSection bufferLock;
- AudioSampleBuffer buffer;
- int bufferValidStart, bufferValidEnd;
- };
-
- //==============================================================================
- class AudioRecorder : public AudioIODeviceCallback,
- public Thread
- {
- public:
- AudioRecorder()
- : Thread ("audio recorder"),
- circularBuffer (2, 48000),
- recording (false),
- sampleRate (0)
- {
- }
-
- ~AudioRecorder()
- {
- stop();
- }
-
- //==============================================================================
- void startRecording (const File& file)
- {
- stop();
-
- if (sampleRate > 0)
- {
- fileToRecord = file;
- startThread();
-
- circularBuffer.clear();
- recording = true;
- }
- }
-
- void stop()
- {
- recording = false;
-
- stopThread (5000);
- }
-
- bool isRecording() const
- {
- return isThreadRunning() && recording;
- }
-
- //==============================================================================
- void audioDeviceAboutToStart (AudioIODevice* device)
- {
- sampleRate = device->getCurrentSampleRate();
- }
-
- void audioDeviceStopped()
- {
- sampleRate = 0;
- }
-
- void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels,
- float** outputChannelData, int numOutputChannels,
- int numSamples)
- {
- if (recording)
- {
- const AudioSampleBuffer incomingData ((float**) inputChannelData, numInputChannels, numSamples);
- circularBuffer.addSamplesToBuffer (incomingData, 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);
- }
-
- //==============================================================================
- void run()
- {
- fileToRecord.deleteFile();
-
- OutputStream* outStream = fileToRecord.createOutputStream();
- if (outStream == 0)
- return;
-
- WavAudioFormat wavFormat;
- AudioFormatWriter* writer = wavFormat.createWriterFor (outStream, sampleRate, 1, 16, StringPairArray(), 0);
-
- if (writer == 0)
- {
- delete outStream;
- return;
- }
-
- AudioSampleBuffer tempBuffer (2, 8192);
-
- while (! threadShouldExit())
- {
- int numSamplesReady = circularBuffer.readSamplesFromBuffer (tempBuffer, tempBuffer.getNumSamples());
-
- if (numSamplesReady > 0)
- tempBuffer.writeToAudioWriter (writer, 0, numSamplesReady);
-
- Thread::sleep (1);
- }
-
- delete writer;
- }
-
- File fileToRecord;
- double sampleRate;
- bool recording;
-
- CircularAudioBuffer circularBuffer;
- };
-
- //[/MiscUserDefs]
-
- //==============================================================================
- AudioDemoRecordPage::AudioDemoRecordPage (AudioDeviceManager& deviceManager_)
- : deviceManager (deviceManager_),
- liveAudioDisplayComp (0),
- explanationLabel (0),
- recordButton (0)
- {
- addAndMakeVisible (liveAudioDisplayComp = new LiveAudioInputDisplayComp());
-
- addAndMakeVisible (explanationLabel = new Label (String::empty,
- T("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 (T("Record"));
- recordButton->addButtonListener (this);
- recordButton->setColour (TextButton::buttonColourId, Colour (0xffff5c5c));
- recordButton->setColour (TextButton::textColourOffId, 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..
- recorder->stop();
- deviceManager.removeAudioCallback (recorder);
- delete recorder;
- deviceManager.removeAudioCallback (liveAudioDisplayComp);
- //[/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
-
- <JUCER_COMPONENT documentType="Component" className="AudioDemoRecordPage" componentName=""
- parentClasses="public Component" constructorParams="AudioDeviceManager& deviceManager_"
- variableInitialisers="deviceManager (deviceManager_)" snapPixels="8"
- snapActive="1" snapShown="1" overlayOpacity="0.330000013" fixedSize="0"
- initialWidth="600" initialHeight="400">
- <METHODS>
- <METHOD name="visibilityChanged()"/>
- </METHODS>
- <BACKGROUND backgroundColour="ffd3d3d3"/>
- <GENERICCOMPONENT name="" id="7d70eb2617f56220" memberName="liveAudioDisplayComp"
- virtualName="" explicitFocusOrder="0" pos="8 8 16M 64" class="LiveAudioInputDisplayComp"
- params=""/>
- <LABEL name="" id="1162fb2599a768b4" memberName="explanationLabel" virtualName=""
- explicitFocusOrder="0" pos="160 88 169M 216" edTextCol="ff000000"
- edBkgCol="0" labelText="This page demonstrates how to record a wave file from the live audio input.. Pressing record will start recording a file in your "Documents" folder."
- editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0"
- fontname="Default font" fontsize="15" bold="0" italic="0" justification="9"/>
- <TEXTBUTTON name="" id="2c10a0ba9fad39da" memberName="recordButton" virtualName=""
- explicitFocusOrder="0" pos="8 88 136 40" bgColOff="ffff5c5c"
- textCol="ff000000" buttonText="Record" connectedEdges="0" needsCallback="1"
- radioGroupId="0"/>
- </JUCER_COMPONENT>
-
- END_JUCER_METADATA
- */
- #endif
|