| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,281 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ | ||
| #define __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_MidiMessage.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| A sequence of timestamped midi messages. | ||
| This allows the sequence to be manipulated, and also to be read from and | ||
| written to a standard midi file. | ||
| @see MidiMessage, MidiFile | ||
| */ | ||
| class JUCE_API MidiMessageSequence | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates an empty midi sequence object. */ | ||
| MidiMessageSequence(); | ||
|
|
||
| /** Creates a copy of another sequence. */ | ||
| MidiMessageSequence (const MidiMessageSequence& other); | ||
|
|
||
| /** Replaces this sequence with another one. */ | ||
| MidiMessageSequence& operator= (const MidiMessageSequence& other); | ||
|
|
||
| /** Destructor. */ | ||
| ~MidiMessageSequence(); | ||
|
|
||
| //============================================================================== | ||
| /** Structure used to hold midi events in the sequence. | ||
| These structures act as 'handles' on the events as they are moved about in | ||
| the list, and make it quick to find the matching note-offs for note-on events. | ||
| @see MidiMessageSequence::getEventPointer | ||
| */ | ||
| class MidiEventHolder | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Destructor. */ | ||
| ~MidiEventHolder(); | ||
|
|
||
| /** The message itself, whose timestamp is used to specify the event's time. | ||
| */ | ||
| MidiMessage message; | ||
|
|
||
| /** The matching note-off event (if this is a note-on event). | ||
| If this isn't a note-on, this pointer will be null. | ||
| Use the MidiMessageSequence::updateMatchedPairs() method to keep these | ||
| note-offs up-to-date after events have been moved around in the sequence | ||
| or deleted. | ||
| */ | ||
| MidiEventHolder* noteOffObject; | ||
|
|
||
| private: | ||
| //============================================================================== | ||
| friend class MidiMessageSequence; | ||
| MidiEventHolder (const MidiMessage& message); | ||
| JUCE_LEAK_DETECTOR (MidiEventHolder) | ||
| }; | ||
|
|
||
| //============================================================================== | ||
| /** Clears the sequence. */ | ||
| void clear(); | ||
|
|
||
| /** Returns the number of events in the sequence. */ | ||
| int getNumEvents() const; | ||
|
|
||
| /** Returns a pointer to one of the events. */ | ||
| MidiEventHolder* getEventPointer (int index) const; | ||
|
|
||
| /** Returns the time of the note-up that matches the note-on at this index. | ||
| If the event at this index isn't a note-on, it'll just return 0. | ||
| @see MidiMessageSequence::MidiEventHolder::noteOffObject | ||
| */ | ||
| double getTimeOfMatchingKeyUp (int index) const; | ||
|
|
||
| /** Returns the index of the note-up that matches the note-on at this index. | ||
| If the event at this index isn't a note-on, it'll just return -1. | ||
| @see MidiMessageSequence::MidiEventHolder::noteOffObject | ||
| */ | ||
| int getIndexOfMatchingKeyUp (int index) const; | ||
|
|
||
| /** Returns the index of an event. */ | ||
| int getIndexOf (MidiEventHolder* event) const; | ||
|
|
||
| /** Returns the index of the first event on or after the given timestamp. | ||
| If the time is beyond the end of the sequence, this will return the | ||
| number of events. | ||
| */ | ||
| int getNextIndexAtTime (double timeStamp) const; | ||
|
|
||
| //============================================================================== | ||
| /** Returns the timestamp of the first event in the sequence. | ||
| @see getEndTime | ||
| */ | ||
| double getStartTime() const; | ||
|
|
||
| /** Returns the timestamp of the last event in the sequence. | ||
| @see getStartTime | ||
| */ | ||
| double getEndTime() const; | ||
|
|
||
| /** Returns the timestamp of the event at a given index. | ||
| If the index is out-of-range, this will return 0.0 | ||
| */ | ||
| double getEventTime (int index) const; | ||
|
|
||
| //============================================================================== | ||
| /** Inserts a midi message into the sequence. | ||
| The index at which the new message gets inserted will depend on its timestamp, | ||
| because the sequence is kept sorted. | ||
| Remember to call updateMatchedPairs() after adding note-on events. | ||
| @param newMessage the new message to add (an internal copy will be made) | ||
| @param timeAdjustment an optional value to add to the timestamp of the message | ||
| that will be inserted | ||
| @see updateMatchedPairs | ||
| */ | ||
| MidiEventHolder* addEvent (const MidiMessage& newMessage, | ||
| double timeAdjustment = 0); | ||
|
|
||
| /** Deletes one of the events in the sequence. | ||
| Remember to call updateMatchedPairs() after removing events. | ||
| @param index the index of the event to delete | ||
| @param deleteMatchingNoteUp whether to also remove the matching note-off | ||
| if the event you're removing is a note-on | ||
| */ | ||
| void deleteEvent (int index, bool deleteMatchingNoteUp); | ||
|
|
||
| /** Merges another sequence into this one. | ||
| Remember to call updateMatchedPairs() after using this method. | ||
| @param other the sequence to add from | ||
| @param timeAdjustmentDelta an amount to add to the timestamps of the midi events | ||
| as they are read from the other sequence | ||
| @param firstAllowableDestTime events will not be added if their time is earlier | ||
| than this time. (This is after their time has been adjusted | ||
| by the timeAdjustmentDelta) | ||
| @param endOfAllowableDestTimes events will not be added if their time is equal to | ||
| or greater than this time. (This is after their time has | ||
| been adjusted by the timeAdjustmentDelta) | ||
| */ | ||
| void addSequence (const MidiMessageSequence& other, | ||
| double timeAdjustmentDelta, | ||
| double firstAllowableDestTime, | ||
| double endOfAllowableDestTimes); | ||
|
|
||
| //============================================================================== | ||
| /** Makes sure all the note-on and note-off pairs are up-to-date. | ||
| Call this after moving messages about or deleting/adding messages, and it | ||
| will scan the list and make sure all the note-offs in the MidiEventHolder | ||
| structures are pointing at the correct ones. | ||
| */ | ||
| void updateMatchedPairs(); | ||
|
|
||
| /** Forces a sort of the sequence. | ||
| You may need to call this if you've manually modified the timestamps of some | ||
| events such that the overall order now needs updating. | ||
| */ | ||
| void sort(); | ||
|
|
||
| //============================================================================== | ||
| /** Copies all the messages for a particular midi channel to another sequence. | ||
| @param channelNumberToExtract the midi channel to look for, in the range 1 to 16 | ||
| @param destSequence the sequence that the chosen events should be copied to | ||
| @param alsoIncludeMetaEvents if true, any meta-events (which don't apply to a specific | ||
| channel) will also be copied across. | ||
| @see extractSysExMessages | ||
| */ | ||
| void extractMidiChannelMessages (int channelNumberToExtract, | ||
| MidiMessageSequence& destSequence, | ||
| bool alsoIncludeMetaEvents) const; | ||
|
|
||
| /** Copies all midi sys-ex messages to another sequence. | ||
| @param destSequence this is the sequence to which any sys-exes in this sequence | ||
| will be added | ||
| @see extractMidiChannelMessages | ||
| */ | ||
| void extractSysExMessages (MidiMessageSequence& destSequence) const; | ||
|
|
||
| /** Removes any messages in this sequence that have a specific midi channel. | ||
| @param channelNumberToRemove the midi channel to look for, in the range 1 to 16 | ||
| */ | ||
| void deleteMidiChannelMessages (int channelNumberToRemove); | ||
|
|
||
| /** Removes any sys-ex messages from this sequence. | ||
| */ | ||
| void deleteSysExMessages(); | ||
|
|
||
| /** Adds an offset to the timestamps of all events in the sequence. | ||
| @param deltaTime the amount to add to each timestamp. | ||
| */ | ||
| void addTimeToMessages (double deltaTime); | ||
|
|
||
| //============================================================================== | ||
| /** Scans through the sequence to determine the state of any midi controllers at | ||
| a given time. | ||
| This will create a sequence of midi controller changes that can be | ||
| used to set all midi controllers to the state they would be in at the | ||
| specified time within this sequence. | ||
| As well as controllers, it will also recreate the midi program number | ||
| and pitch bend position. | ||
| @param channelNumber the midi channel to look for, in the range 1 to 16. Controllers | ||
| for other channels will be ignored. | ||
| @param time the time at which you want to find out the state - there are | ||
| no explicit units for this time measurement, it's the same units | ||
| as used for the timestamps of the messages | ||
| @param resultMessages an array to which midi controller-change messages will be added. This | ||
| will be the minimum number of controller changes to recreate the | ||
| state at the required time. | ||
| */ | ||
| void createControllerUpdatesForTime (int channelNumber, double time, | ||
| OwnedArray<MidiMessage>& resultMessages); | ||
|
|
||
| //============================================================================== | ||
| /** Swaps this sequence with another one. */ | ||
| void swapWith (MidiMessageSequence& other) noexcept; | ||
|
|
||
| private: | ||
| //============================================================================== | ||
| friend class MidiFile; | ||
| OwnedArray <MidiEventHolder> list; | ||
|
|
||
| JUCE_LEAK_DETECTOR (MidiMessageSequence) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_AUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "../buffers/juce_AudioSampleBuffer.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| Used by AudioSource::getNextAudioBlock(). | ||
| */ | ||
| struct JUCE_API AudioSourceChannelInfo | ||
| { | ||
| /** Creates an uninitialised AudioSourceChannelInfo. */ | ||
| AudioSourceChannelInfo() noexcept | ||
| { | ||
| } | ||
|
|
||
| /** Creates an AudioSourceChannelInfo. */ | ||
| AudioSourceChannelInfo (AudioSampleBuffer* bufferToUse, | ||
| int startSampleOffset, int numSamplesToUse) noexcept | ||
| : buffer (bufferToUse), | ||
| startSample (startSampleOffset), | ||
| numSamples (numSamplesToUse) | ||
| { | ||
| } | ||
|
|
||
| /** Creates an AudioSourceChannelInfo that uses the whole of a buffer. | ||
| Note that the buffer provided must not be deleted while the | ||
| AudioSourceChannelInfo is still using it. | ||
| */ | ||
| explicit AudioSourceChannelInfo (AudioSampleBuffer& bufferToUse) noexcept | ||
| : buffer (&bufferToUse), | ||
| startSample (0), | ||
| numSamples (bufferToUse.getNumSamples()) | ||
| { | ||
| } | ||
|
|
||
| /** The destination buffer to fill with audio data. | ||
| When the AudioSource::getNextAudioBlock() method is called, the active section | ||
| of this buffer should be filled with whatever output the source produces. | ||
| Only the samples specified by the startSample and numSamples members of this structure | ||
| should be affected by the call. | ||
| The contents of the buffer when it is passed to the the AudioSource::getNextAudioBlock() | ||
| method can be treated as the input if the source is performing some kind of filter operation, | ||
| but should be cleared if this is not the case - the clearActiveBufferRegion() is | ||
| a handy way of doing this. | ||
| The number of channels in the buffer could be anything, so the AudioSource | ||
| must cope with this in whatever way is appropriate for its function. | ||
| */ | ||
| AudioSampleBuffer* buffer; | ||
|
|
||
| /** The first sample in the buffer from which the callback is expected | ||
| to write data. */ | ||
| int startSample; | ||
|
|
||
| /** The number of samples in the buffer which the callback is expected to | ||
| fill with data. */ | ||
| int numSamples; | ||
|
|
||
| /** Convenient method to clear the buffer if the source is not producing any data. */ | ||
| void clearActiveBufferRegion() const | ||
| { | ||
| if (buffer != nullptr) | ||
| buffer->clear (startSample, numSamples); | ||
| } | ||
| }; | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| Base class for objects that can produce a continuous stream of audio. | ||
| An AudioSource has two states: 'prepared' and 'unprepared'. | ||
| When a source needs to be played, it is first put into a 'prepared' state by a call to | ||
| prepareToPlay(), and then repeated calls will be made to its getNextAudioBlock() method to | ||
| process the audio data. | ||
| Once playback has finished, the releaseResources() method is called to put the stream | ||
| back into an 'unprepared' state. | ||
| @see AudioFormatReaderSource, ResamplingAudioSource | ||
| */ | ||
| class JUCE_API AudioSource | ||
| { | ||
| protected: | ||
| //============================================================================== | ||
| /** Creates an AudioSource. */ | ||
| AudioSource() noexcept {} | ||
|
|
||
| public: | ||
| /** Destructor. */ | ||
| virtual ~AudioSource() {} | ||
|
|
||
| //============================================================================== | ||
| /** Tells the source to prepare for playing. | ||
| An AudioSource has two states: prepared and unprepared. | ||
| The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' | ||
| source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). | ||
| This callback allows the source to initialise any resources it might need when playing. | ||
| Once playback has finished, the releaseResources() method is called to put the stream | ||
| back into an 'unprepared' state. | ||
| Note that this method could be called more than once in succession without | ||
| a matching call to releaseResources(), so make sure your code is robust and | ||
| can handle that kind of situation. | ||
| @param samplesPerBlockExpected the number of samples that the source | ||
| will be expected to supply each time its | ||
| getNextAudioBlock() method is called. This | ||
| number may vary slightly, because it will be dependent | ||
| on audio hardware callbacks, and these aren't | ||
| guaranteed to always use a constant block size, so | ||
| the source should be able to cope with small variations. | ||
| @param sampleRate the sample rate that the output will be used at - this | ||
| is needed by sources such as tone generators. | ||
| @see releaseResources, getNextAudioBlock | ||
| */ | ||
| virtual void prepareToPlay (int samplesPerBlockExpected, | ||
| double sampleRate) = 0; | ||
|
|
||
| /** Allows the source to release anything it no longer needs after playback has stopped. | ||
| This will be called when the source is no longer going to have its getNextAudioBlock() | ||
| method called, so it should release any spare memory, etc. that it might have | ||
| allocated during the prepareToPlay() call. | ||
| Note that there's no guarantee that prepareToPlay() will actually have been called before | ||
| releaseResources(), and it may be called more than once in succession, so make sure your | ||
| code is robust and doesn't make any assumptions about when it will be called. | ||
| @see prepareToPlay, getNextAudioBlock | ||
| */ | ||
| virtual void releaseResources() = 0; | ||
|
|
||
| /** Called repeatedly to fetch subsequent blocks of audio data. | ||
| After calling the prepareToPlay() method, this callback will be made each | ||
| time the audio playback hardware (or whatever other destination the audio | ||
| data is going to) needs another block of data. | ||
| It will generally be called on a high-priority system thread, or possibly even | ||
| an interrupt, so be careful not to do too much work here, as that will cause | ||
| audio glitches! | ||
| @see AudioSourceChannelInfo, prepareToPlay, releaseResources | ||
| */ | ||
| virtual void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) = 0; | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_AUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,262 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_, | ||
| TimeSliceThread& backgroundThread_, | ||
| const bool deleteSourceWhenDeleted, | ||
| const int numberOfSamplesToBuffer_, | ||
| const int numberOfChannels_) | ||
| : source (source_, deleteSourceWhenDeleted), | ||
| backgroundThread (backgroundThread_), | ||
| numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)), | ||
| numberOfChannels (numberOfChannels_), | ||
| buffer (numberOfChannels_, 0), | ||
| bufferValidStart (0), | ||
| bufferValidEnd (0), | ||
| nextPlayPos (0), | ||
| wasSourceLooping (false), | ||
| isPrepared (false) | ||
| { | ||
| jassert (source_ != nullptr); | ||
|
|
||
| jassert (numberOfSamplesToBuffer_ > 1024); // not much point using this class if you're | ||
| // not using a larger buffer.. | ||
| } | ||
|
|
||
| BufferingAudioSource::~BufferingAudioSource() | ||
| { | ||
| releaseResources(); | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate_) | ||
| { | ||
| const int bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); | ||
|
|
||
| if (sampleRate_ != sampleRate | ||
| || bufferSizeNeeded != buffer.getNumSamples() | ||
| || ! isPrepared) | ||
| { | ||
| backgroundThread.removeTimeSliceClient (this); | ||
|
|
||
| isPrepared = true; | ||
| sampleRate = sampleRate_; | ||
|
|
||
| source->prepareToPlay (samplesPerBlockExpected, sampleRate_); | ||
|
|
||
| buffer.setSize (numberOfChannels, bufferSizeNeeded); | ||
| buffer.clear(); | ||
|
|
||
| bufferValidStart = 0; | ||
| bufferValidEnd = 0; | ||
|
|
||
| backgroundThread.addTimeSliceClient (this); | ||
|
|
||
| while (bufferValidEnd - bufferValidStart < jmin (((int) sampleRate_) / 4, | ||
| buffer.getNumSamples() / 2)) | ||
| { | ||
| backgroundThread.moveToFrontOfQueue (this); | ||
| Thread::sleep (5); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void BufferingAudioSource::releaseResources() | ||
| { | ||
| isPrepared = false; | ||
| backgroundThread.removeTimeSliceClient (this); | ||
|
|
||
| buffer.setSize (numberOfChannels, 0); | ||
| source->releaseResources(); | ||
| } | ||
|
|
||
| void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | ||
| { | ||
| const ScopedLock sl (bufferStartPosLock); | ||
|
|
||
| const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); | ||
| const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); | ||
|
|
||
| if (validStart == validEnd) | ||
| { | ||
| // total cache miss | ||
| info.clearActiveBufferRegion(); | ||
| } | ||
| else | ||
| { | ||
| if (validStart > 0) | ||
| info.buffer->clear (info.startSample, validStart); // partial cache miss at start | ||
|
|
||
| if (validEnd < info.numSamples) | ||
| info.buffer->clear (info.startSample + validEnd, | ||
| info.numSamples - validEnd); // partial cache miss at end | ||
|
|
||
| if (validStart < validEnd) | ||
| { | ||
| for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;) | ||
| { | ||
| jassert (buffer.getNumSamples() > 0); | ||
| const int startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples()); | ||
| const int endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples()); | ||
|
|
||
| if (startBufferIndex < endBufferIndex) | ||
| { | ||
| info.buffer->copyFrom (chan, info.startSample + validStart, | ||
| buffer, | ||
| chan, startBufferIndex, | ||
| validEnd - validStart); | ||
| } | ||
| else | ||
| { | ||
| const int initialSize = buffer.getNumSamples() - startBufferIndex; | ||
|
|
||
| info.buffer->copyFrom (chan, info.startSample + validStart, | ||
| buffer, | ||
| chan, startBufferIndex, | ||
| initialSize); | ||
|
|
||
| info.buffer->copyFrom (chan, info.startSample + validStart + initialSize, | ||
| buffer, | ||
| chan, 0, | ||
| (validEnd - validStart) - initialSize); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| nextPlayPos += info.numSamples; | ||
| } | ||
| } | ||
|
|
||
| int64 BufferingAudioSource::getNextReadPosition() const | ||
| { | ||
| jassert (source->getTotalLength() > 0); | ||
| return (source->isLooping() && nextPlayPos > 0) | ||
| ? nextPlayPos % source->getTotalLength() | ||
| : nextPlayPos; | ||
| } | ||
|
|
||
| void BufferingAudioSource::setNextReadPosition (int64 newPosition) | ||
| { | ||
| const ScopedLock sl (bufferStartPosLock); | ||
|
|
||
| nextPlayPos = newPosition; | ||
| backgroundThread.moveToFrontOfQueue (this); | ||
| } | ||
|
|
||
| bool BufferingAudioSource::readNextBufferChunk() | ||
| { | ||
| int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd; | ||
|
|
||
| { | ||
| const ScopedLock sl (bufferStartPosLock); | ||
|
|
||
| if (wasSourceLooping != isLooping()) | ||
| { | ||
| wasSourceLooping = isLooping(); | ||
| bufferValidStart = 0; | ||
| bufferValidEnd = 0; | ||
| } | ||
|
|
||
| newBVS = jmax ((int64) 0, nextPlayPos); | ||
| newBVE = newBVS + buffer.getNumSamples() - 4; | ||
| sectionToReadStart = 0; | ||
| sectionToReadEnd = 0; | ||
|
|
||
| const int maxChunkSize = 2048; | ||
|
|
||
| if (newBVS < bufferValidStart || newBVS >= bufferValidEnd) | ||
| { | ||
| newBVE = jmin (newBVE, newBVS + maxChunkSize); | ||
|
|
||
| sectionToReadStart = newBVS; | ||
| sectionToReadEnd = newBVE; | ||
|
|
||
| bufferValidStart = 0; | ||
| bufferValidEnd = 0; | ||
| } | ||
| else if (std::abs ((int) (newBVS - bufferValidStart)) > 512 | ||
| || std::abs ((int) (newBVE - bufferValidEnd)) > 512) | ||
| { | ||
| newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize); | ||
|
|
||
| sectionToReadStart = bufferValidEnd; | ||
| sectionToReadEnd = newBVE; | ||
|
|
||
| bufferValidStart = newBVS; | ||
| bufferValidEnd = jmin (bufferValidEnd, newBVE); | ||
| } | ||
| } | ||
|
|
||
| if (sectionToReadStart != sectionToReadEnd) | ||
| { | ||
| jassert (buffer.getNumSamples() > 0); | ||
| const int bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples()); | ||
| const int bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples()); | ||
|
|
||
| if (bufferIndexStart < bufferIndexEnd) | ||
| { | ||
| readBufferSection (sectionToReadStart, | ||
| (int) (sectionToReadEnd - sectionToReadStart), | ||
| bufferIndexStart); | ||
| } | ||
| else | ||
| { | ||
| const int initialSize = buffer.getNumSamples() - bufferIndexStart; | ||
|
|
||
| readBufferSection (sectionToReadStart, | ||
| initialSize, | ||
| bufferIndexStart); | ||
|
|
||
| readBufferSection (sectionToReadStart + initialSize, | ||
| (int) (sectionToReadEnd - sectionToReadStart) - initialSize, | ||
| 0); | ||
| } | ||
|
|
||
| const ScopedLock sl2 (bufferStartPosLock); | ||
|
|
||
| bufferValidStart = newBVS; | ||
| bufferValidEnd = newBVE; | ||
|
|
||
| return true; | ||
| } | ||
| else | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| void BufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset) | ||
| { | ||
| if (source->getNextReadPosition() != start) | ||
| source->setNextReadPosition (start); | ||
|
|
||
| AudioSourceChannelInfo info (&buffer, bufferOffset, length); | ||
| source->getNextAudioBlock (info); | ||
| } | ||
|
|
||
| int BufferingAudioSource::useTimeSlice() | ||
| { | ||
| return readNextBufferChunk() ? 1 : 100; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_PositionableAudioSource.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| An AudioSource which takes another source as input, and buffers it using a thread. | ||
| Create this as a wrapper around another thread, and it will read-ahead with | ||
| a background thread to smooth out playback. You can either create one of these | ||
| directly, or use it indirectly using an AudioTransportSource. | ||
| @see PositionableAudioSource, AudioTransportSource | ||
| */ | ||
| class JUCE_API BufferingAudioSource : public PositionableAudioSource, | ||
| private TimeSliceClient | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates a BufferingAudioSource. | ||
| @param source the input source to read from | ||
| @param backgroundThread a background thread that will be used for the | ||
| background read-ahead. This object must not be deleted | ||
| until after any BufferedAudioSources that are using it | ||
| have been deleted! | ||
| @param deleteSourceWhenDeleted if true, then the input source object will | ||
| be deleted when this object is deleted | ||
| @param numberOfSamplesToBuffer the size of buffer to use for reading ahead | ||
| @param numberOfChannels the number of channels that will be played | ||
| */ | ||
| BufferingAudioSource (PositionableAudioSource* source, | ||
| TimeSliceThread& backgroundThread, | ||
| bool deleteSourceWhenDeleted, | ||
| int numberOfSamplesToBuffer, | ||
| int numberOfChannels = 2); | ||
|
|
||
| /** Destructor. | ||
| The input source may be deleted depending on whether the deleteSourceWhenDeleted | ||
| flag was set in the constructor. | ||
| */ | ||
| ~BufferingAudioSource(); | ||
|
|
||
| //============================================================================== | ||
| /** Implementation of the AudioSource method. */ | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
|
|
||
| /** Implementation of the AudioSource method. */ | ||
| void releaseResources(); | ||
|
|
||
| /** Implementation of the AudioSource method. */ | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
| //============================================================================== | ||
| /** Implements the PositionableAudioSource method. */ | ||
| void setNextReadPosition (int64 newPosition); | ||
|
|
||
| /** Implements the PositionableAudioSource method. */ | ||
| int64 getNextReadPosition() const; | ||
|
|
||
| /** Implements the PositionableAudioSource method. */ | ||
| int64 getTotalLength() const { return source->getTotalLength(); } | ||
|
|
||
| /** Implements the PositionableAudioSource method. */ | ||
| bool isLooping() const { return source->isLooping(); } | ||
|
|
||
| private: | ||
| //============================================================================== | ||
| OptionalScopedPointer<PositionableAudioSource> source; | ||
| TimeSliceThread& backgroundThread; | ||
| int numberOfSamplesToBuffer, numberOfChannels; | ||
| AudioSampleBuffer buffer; | ||
| CriticalSection bufferStartPosLock; | ||
| int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos; | ||
| double volatile sampleRate; | ||
| bool wasSourceLooping, isPrepared; | ||
|
|
||
| bool readNextBufferChunk(); | ||
| void readBufferSection (int64 start, int length, int bufferOffset); | ||
| int useTimeSlice(); | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferingAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| ChannelRemappingAudioSource::ChannelRemappingAudioSource (AudioSource* const source_, | ||
| const bool deleteSourceWhenDeleted) | ||
| : source (source_, deleteSourceWhenDeleted), | ||
| requiredNumberOfChannels (2), | ||
| buffer (2, 16) | ||
| { | ||
| remappedInfo.buffer = &buffer; | ||
| remappedInfo.startSample = 0; | ||
| } | ||
|
|
||
| ChannelRemappingAudioSource::~ChannelRemappingAudioSource() {} | ||
|
|
||
| //============================================================================== | ||
| void ChannelRemappingAudioSource::setNumberOfChannelsToProduce (const int requiredNumberOfChannels_) | ||
| { | ||
| const ScopedLock sl (lock); | ||
| requiredNumberOfChannels = requiredNumberOfChannels_; | ||
| } | ||
|
|
||
| void ChannelRemappingAudioSource::clearAllMappings() | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| remappedInputs.clear(); | ||
| remappedOutputs.clear(); | ||
| } | ||
|
|
||
| void ChannelRemappingAudioSource::setInputChannelMapping (const int destIndex, const int sourceIndex) | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| while (remappedInputs.size() < destIndex) | ||
| remappedInputs.add (-1); | ||
|
|
||
| remappedInputs.set (destIndex, sourceIndex); | ||
| } | ||
|
|
||
| void ChannelRemappingAudioSource::setOutputChannelMapping (const int sourceIndex, const int destIndex) | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| while (remappedOutputs.size() < sourceIndex) | ||
| remappedOutputs.add (-1); | ||
|
|
||
| remappedOutputs.set (sourceIndex, destIndex); | ||
| } | ||
|
|
||
| int ChannelRemappingAudioSource::getRemappedInputChannel (const int inputChannelIndex) const | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| if (inputChannelIndex >= 0 && inputChannelIndex < remappedInputs.size()) | ||
| return remappedInputs.getUnchecked (inputChannelIndex); | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| int ChannelRemappingAudioSource::getRemappedOutputChannel (const int outputChannelIndex) const | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| if (outputChannelIndex >= 0 && outputChannelIndex < remappedOutputs.size()) | ||
| return remappedOutputs .getUnchecked (outputChannelIndex); | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void ChannelRemappingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) | ||
| { | ||
| source->prepareToPlay (samplesPerBlockExpected, sampleRate); | ||
| } | ||
|
|
||
| void ChannelRemappingAudioSource::releaseResources() | ||
| { | ||
| source->releaseResources(); | ||
| } | ||
|
|
||
| void ChannelRemappingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| buffer.setSize (requiredNumberOfChannels, bufferToFill.numSamples, false, false, true); | ||
|
|
||
| const int numChans = bufferToFill.buffer->getNumChannels(); | ||
|
|
||
| for (int i = 0; i < buffer.getNumChannels(); ++i) | ||
| { | ||
| const int remappedChan = getRemappedInputChannel (i); | ||
|
|
||
| if (remappedChan >= 0 && remappedChan < numChans) | ||
| { | ||
| buffer.copyFrom (i, 0, *bufferToFill.buffer, | ||
| remappedChan, | ||
| bufferToFill.startSample, | ||
| bufferToFill.numSamples); | ||
| } | ||
| else | ||
| { | ||
| buffer.clear (i, 0, bufferToFill.numSamples); | ||
| } | ||
| } | ||
|
|
||
| remappedInfo.numSamples = bufferToFill.numSamples; | ||
|
|
||
| source->getNextAudioBlock (remappedInfo); | ||
|
|
||
| bufferToFill.clearActiveBufferRegion(); | ||
|
|
||
| for (int i = 0; i < requiredNumberOfChannels; ++i) | ||
| { | ||
| const int remappedChan = getRemappedOutputChannel (i); | ||
|
|
||
| if (remappedChan >= 0 && remappedChan < numChans) | ||
| { | ||
| bufferToFill.buffer->addFrom (remappedChan, bufferToFill.startSample, | ||
| buffer, i, 0, bufferToFill.numSamples); | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| //============================================================================== | ||
| XmlElement* ChannelRemappingAudioSource::createXml() const | ||
| { | ||
| XmlElement* e = new XmlElement ("MAPPINGS"); | ||
| String ins, outs; | ||
|
|
||
| const ScopedLock sl (lock); | ||
|
|
||
| for (int i = 0; i < remappedInputs.size(); ++i) | ||
| ins << remappedInputs.getUnchecked(i) << ' '; | ||
|
|
||
| for (int i = 0; i < remappedOutputs.size(); ++i) | ||
| outs << remappedOutputs.getUnchecked(i) << ' '; | ||
|
|
||
| e->setAttribute ("inputs", ins.trimEnd()); | ||
| e->setAttribute ("outputs", outs.trimEnd()); | ||
|
|
||
| return e; | ||
| } | ||
|
|
||
| void ChannelRemappingAudioSource::restoreFromXml (const XmlElement& e) | ||
| { | ||
| if (e.hasTagName ("MAPPINGS")) | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| clearAllMappings(); | ||
|
|
||
| StringArray ins, outs; | ||
| ins.addTokens (e.getStringAttribute ("inputs"), false); | ||
| outs.addTokens (e.getStringAttribute ("outputs"), false); | ||
|
|
||
| for (int i = 0; i < ins.size(); ++i) | ||
| remappedInputs.add (ins[i].getIntValue()); | ||
|
|
||
| for (int i = 0; i < outs.size(); ++i) | ||
| remappedOutputs.add (outs[i].getIntValue()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| An AudioSource that takes the audio from another source, and re-maps its | ||
| input and output channels to a different arrangement. | ||
| You can use this to increase or decrease the number of channels that an | ||
| audio source uses, or to re-order those channels. | ||
| Call the reset() method before using it to set up a default mapping, and then | ||
| the setInputChannelMapping() and setOutputChannelMapping() methods to | ||
| create an appropriate mapping, otherwise no channels will be connected and | ||
| it'll produce silence. | ||
| @see AudioSource | ||
| */ | ||
| class ChannelRemappingAudioSource : public AudioSource | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates a remapping source that will pass on audio from the given input. | ||
| @param source the input source to use. Make sure that this doesn't | ||
| get deleted before the ChannelRemappingAudioSource object | ||
| @param deleteSourceWhenDeleted if true, the input source will be deleted | ||
| when this object is deleted, if false, the caller is | ||
| responsible for its deletion | ||
| */ | ||
| ChannelRemappingAudioSource (AudioSource* source, | ||
| bool deleteSourceWhenDeleted); | ||
|
|
||
| /** Destructor. */ | ||
| ~ChannelRemappingAudioSource(); | ||
|
|
||
| //============================================================================== | ||
| /** Specifies a number of channels that this audio source must produce from its | ||
| getNextAudioBlock() callback. | ||
| */ | ||
| void setNumberOfChannelsToProduce (int requiredNumberOfChannels); | ||
|
|
||
| /** Clears any mapped channels. | ||
| After this, no channels are mapped, so this object will produce silence. Create | ||
| some mappings with setInputChannelMapping() and setOutputChannelMapping(). | ||
| */ | ||
| void clearAllMappings(); | ||
|
|
||
| /** Creates an input channel mapping. | ||
| When the getNextAudioBlock() method is called, the data in channel sourceChannelIndex of the incoming | ||
| data will be sent to destChannelIndex of our input source. | ||
| @param destChannelIndex the index of an input channel in our input audio source (i.e. the | ||
| source specified when this object was created). | ||
| @param sourceChannelIndex the index of the input channel in the incoming audio data buffer | ||
| during our getNextAudioBlock() callback | ||
| */ | ||
| void setInputChannelMapping (int destChannelIndex, | ||
| int sourceChannelIndex); | ||
|
|
||
| /** Creates an output channel mapping. | ||
| When the getNextAudioBlock() method is called, the data returned in channel sourceChannelIndex by | ||
| our input audio source will be copied to channel destChannelIndex of the final buffer. | ||
| @param sourceChannelIndex the index of an output channel coming from our input audio source | ||
| (i.e. the source specified when this object was created). | ||
| @param destChannelIndex the index of the output channel in the incoming audio data buffer | ||
| during our getNextAudioBlock() callback | ||
| */ | ||
| void setOutputChannelMapping (int sourceChannelIndex, | ||
| int destChannelIndex); | ||
|
|
||
| /** Returns the channel from our input that will be sent to channel inputChannelIndex of | ||
| our input audio source. | ||
| */ | ||
| int getRemappedInputChannel (int inputChannelIndex) const; | ||
|
|
||
| /** Returns the output channel to which channel outputChannelIndex of our input audio | ||
| source will be sent to. | ||
| */ | ||
| int getRemappedOutputChannel (int outputChannelIndex) const; | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** Returns an XML object to encapsulate the state of the mappings. | ||
| @see restoreFromXml | ||
| */ | ||
| XmlElement* createXml() const; | ||
|
|
||
| /** Restores the mappings from an XML object created by createXML(). | ||
| @see createXml | ||
| */ | ||
| void restoreFromXml (const XmlElement& e); | ||
|
|
||
| //============================================================================== | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
| void releaseResources(); | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
|
|
||
| private: | ||
| //============================================================================== | ||
| OptionalScopedPointer<AudioSource> source; | ||
| Array <int> remappedInputs, remappedOutputs; | ||
| int requiredNumberOfChannels; | ||
|
|
||
| AudioSampleBuffer buffer; | ||
| AudioSourceChannelInfo remappedInfo; | ||
|
|
||
| CriticalSection lock; | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChannelRemappingAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| IIRFilterAudioSource::IIRFilterAudioSource (AudioSource* const inputSource, | ||
| const bool deleteInputWhenDeleted) | ||
| : input (inputSource, deleteInputWhenDeleted) | ||
| { | ||
| jassert (inputSource != nullptr); | ||
|
|
||
| for (int i = 2; --i >= 0;) | ||
| iirFilters.add (new IIRFilter()); | ||
| } | ||
|
|
||
| IIRFilterAudioSource::~IIRFilterAudioSource() {} | ||
|
|
||
| //============================================================================== | ||
| void IIRFilterAudioSource::setFilterParameters (const IIRFilter& newSettings) | ||
| { | ||
| for (int i = iirFilters.size(); --i >= 0;) | ||
| iirFilters.getUnchecked(i)->copyCoefficientsFrom (newSettings); | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void IIRFilterAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) | ||
| { | ||
| input->prepareToPlay (samplesPerBlockExpected, sampleRate); | ||
|
|
||
| for (int i = iirFilters.size(); --i >= 0;) | ||
| iirFilters.getUnchecked(i)->reset(); | ||
| } | ||
|
|
||
| void IIRFilterAudioSource::releaseResources() | ||
| { | ||
| input->releaseResources(); | ||
| } | ||
|
|
||
| void IIRFilterAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) | ||
| { | ||
| input->getNextAudioBlock (bufferToFill); | ||
|
|
||
| const int numChannels = bufferToFill.buffer->getNumChannels(); | ||
|
|
||
| while (numChannels > iirFilters.size()) | ||
| iirFilters.add (new IIRFilter (*iirFilters.getUnchecked (0))); | ||
|
|
||
| for (int i = 0; i < numChannels; ++i) | ||
| iirFilters.getUnchecked(i) | ||
| ->processSamples (bufferToFill.buffer->getSampleData (i, bufferToFill.startSample), | ||
| bufferToFill.numSamples); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
| #include "../effects/juce_IIRFilter.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| An AudioSource that performs an IIR filter on another source. | ||
| */ | ||
| class JUCE_API IIRFilterAudioSource : public AudioSource | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates a IIRFilterAudioSource for a given input source. | ||
| @param inputSource the input source to read from - this must not be null | ||
| @param deleteInputWhenDeleted if true, the input source will be deleted when | ||
| this object is deleted | ||
| */ | ||
| IIRFilterAudioSource (AudioSource* inputSource, | ||
| bool deleteInputWhenDeleted); | ||
|
|
||
| /** Destructor. */ | ||
| ~IIRFilterAudioSource(); | ||
|
|
||
| //============================================================================== | ||
| /** Changes the filter to use the same parameters as the one being passed in. */ | ||
| void setFilterParameters (const IIRFilter& newSettings); | ||
|
|
||
| //============================================================================== | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
| void releaseResources(); | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
| private: | ||
| //============================================================================== | ||
| OptionalScopedPointer<AudioSource> input; | ||
| OwnedArray <IIRFilter> iirFilters; | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IIRFilterAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| MixerAudioSource::MixerAudioSource() | ||
| : tempBuffer (2, 0), | ||
| currentSampleRate (0.0), | ||
| bufferSizeExpected (0) | ||
| { | ||
| } | ||
|
|
||
| MixerAudioSource::~MixerAudioSource() | ||
| { | ||
| removeAllInputs(); | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void MixerAudioSource::addInputSource (AudioSource* input, const bool deleteWhenRemoved) | ||
| { | ||
| if (input != nullptr && ! inputs.contains (input)) | ||
| { | ||
| double localRate; | ||
| int localBufferSize; | ||
|
|
||
| { | ||
| const ScopedLock sl (lock); | ||
| localRate = currentSampleRate; | ||
| localBufferSize = bufferSizeExpected; | ||
| } | ||
|
|
||
| if (localRate > 0.0) | ||
| input->prepareToPlay (localBufferSize, localRate); | ||
|
|
||
| const ScopedLock sl (lock); | ||
|
|
||
| inputsToDelete.setBit (inputs.size(), deleteWhenRemoved); | ||
| inputs.add (input); | ||
| } | ||
| } | ||
|
|
||
| void MixerAudioSource::removeInputSource (AudioSource* const input) | ||
| { | ||
| if (input != nullptr) | ||
| { | ||
| ScopedPointer<AudioSource> toDelete; | ||
|
|
||
| { | ||
| const ScopedLock sl (lock); | ||
| const int index = inputs.indexOf (input); | ||
|
|
||
| if (index < 0) | ||
| return; | ||
|
|
||
| if (inputsToDelete [index]) | ||
| toDelete = input; | ||
|
|
||
| inputsToDelete.shiftBits (-1, index); | ||
| inputs.remove (index); | ||
| } | ||
|
|
||
| input->releaseResources(); | ||
| } | ||
| } | ||
|
|
||
| void MixerAudioSource::removeAllInputs() | ||
| { | ||
| OwnedArray<AudioSource> toDelete; | ||
|
|
||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| for (int i = inputs.size(); --i >= 0;) | ||
| if (inputsToDelete[i]) | ||
| toDelete.add (inputs.getUnchecked(i)); | ||
|
|
||
| inputs.clear(); | ||
| } | ||
|
|
||
| for (int i = toDelete.size(); --i >= 0;) | ||
| toDelete.getUnchecked(i)->releaseResources(); | ||
| } | ||
|
|
||
| void MixerAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) | ||
| { | ||
| tempBuffer.setSize (2, samplesPerBlockExpected); | ||
|
|
||
| const ScopedLock sl (lock); | ||
|
|
||
| currentSampleRate = sampleRate; | ||
| bufferSizeExpected = samplesPerBlockExpected; | ||
|
|
||
| for (int i = inputs.size(); --i >= 0;) | ||
| inputs.getUnchecked(i)->prepareToPlay (samplesPerBlockExpected, sampleRate); | ||
| } | ||
|
|
||
| void MixerAudioSource::releaseResources() | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| for (int i = inputs.size(); --i >= 0;) | ||
| inputs.getUnchecked(i)->releaseResources(); | ||
|
|
||
| tempBuffer.setSize (2, 0); | ||
|
|
||
| currentSampleRate = 0; | ||
| bufferSizeExpected = 0; | ||
| } | ||
|
|
||
| void MixerAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| if (inputs.size() > 0) | ||
| { | ||
| inputs.getUnchecked(0)->getNextAudioBlock (info); | ||
|
|
||
| if (inputs.size() > 1) | ||
| { | ||
| tempBuffer.setSize (jmax (1, info.buffer->getNumChannels()), | ||
| info.buffer->getNumSamples()); | ||
|
|
||
| AudioSourceChannelInfo info2 (&tempBuffer, 0, info.numSamples); | ||
|
|
||
| for (int i = 1; i < inputs.size(); ++i) | ||
| { | ||
| inputs.getUnchecked(i)->getNextAudioBlock (info2); | ||
|
|
||
| for (int chan = 0; chan < info.buffer->getNumChannels(); ++chan) | ||
| info.buffer->addFrom (chan, info.startSample, tempBuffer, chan, 0, info.numSamples); | ||
| } | ||
| } | ||
| } | ||
| else | ||
| { | ||
| info.clearActiveBufferRegion(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| An AudioSource that mixes together the output of a set of other AudioSources. | ||
| Input sources can be added and removed while the mixer is running as long as their | ||
| prepareToPlay() and releaseResources() methods are called before and after adding | ||
| them to the mixer. | ||
| */ | ||
| class JUCE_API MixerAudioSource : public AudioSource | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates a MixerAudioSource. */ | ||
| MixerAudioSource(); | ||
|
|
||
| /** Destructor. */ | ||
| ~MixerAudioSource(); | ||
|
|
||
| //============================================================================== | ||
| /** Adds an input source to the mixer. | ||
| If the mixer is running you'll need to make sure that the input source | ||
| is ready to play by calling its prepareToPlay() method before adding it. | ||
| If the mixer is stopped, then its input sources will be automatically | ||
| prepared when the mixer's prepareToPlay() method is called. | ||
| @param newInput the source to add to the mixer | ||
| @param deleteWhenRemoved if true, then this source will be deleted when | ||
| no longer needed by the mixer. | ||
| */ | ||
| void addInputSource (AudioSource* newInput, bool deleteWhenRemoved); | ||
|
|
||
| /** Removes an input source. | ||
| If the source was added by calling addInputSource() with the deleteWhenRemoved | ||
| flag set, it will be deleted by this method. | ||
| */ | ||
| void removeInputSource (AudioSource* input); | ||
|
|
||
| /** Removes all the input sources. | ||
| Any sources which were added by calling addInputSource() with the deleteWhenRemoved | ||
| flag set will be deleted by this method. | ||
| */ | ||
| void removeAllInputs(); | ||
|
|
||
| //============================================================================== | ||
| /** Implementation of the AudioSource method. | ||
| This will call prepareToPlay() on all its input sources. | ||
| */ | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
|
|
||
| /** Implementation of the AudioSource method. | ||
| This will call releaseResources() on all its input sources. | ||
| */ | ||
| void releaseResources(); | ||
|
|
||
| /** Implementation of the AudioSource method. */ | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
|
|
||
| private: | ||
| //============================================================================== | ||
| Array <AudioSource*> inputs; | ||
| BigInteger inputsToDelete; | ||
| CriticalSection lock; | ||
| AudioSampleBuffer tempBuffer; | ||
| double currentSampleRate; | ||
| int bufferSizeExpected; | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MixerAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| A type of AudioSource which can be repositioned. | ||
| The basic AudioSource just streams continuously with no idea of a current | ||
| time or length, so the PositionableAudioSource is used for a finite stream | ||
| that has a current read position. | ||
| @see AudioSource, AudioTransportSource | ||
| */ | ||
| class JUCE_API PositionableAudioSource : public AudioSource | ||
| { | ||
| protected: | ||
| //============================================================================== | ||
| /** Creates the PositionableAudioSource. */ | ||
| PositionableAudioSource() noexcept {} | ||
|
|
||
| public: | ||
| /** Destructor */ | ||
| ~PositionableAudioSource() {} | ||
|
|
||
| //============================================================================== | ||
| /** Tells the stream to move to a new position. | ||
| Calling this indicates that the next call to AudioSource::getNextAudioBlock() | ||
| should return samples from this position. | ||
| Note that this may be called on a different thread to getNextAudioBlock(), | ||
| so the subclass should make sure it's synchronised. | ||
| */ | ||
| virtual void setNextReadPosition (int64 newPosition) = 0; | ||
|
|
||
| /** Returns the position from which the next block will be returned. | ||
| @see setNextReadPosition | ||
| */ | ||
| virtual int64 getNextReadPosition() const = 0; | ||
|
|
||
| /** Returns the total length of the stream (in samples). */ | ||
| virtual int64 getTotalLength() const = 0; | ||
|
|
||
| /** Returns true if this source is actually playing in a loop. */ | ||
| virtual bool isLooping() const = 0; | ||
|
|
||
| /** Tells the source whether you'd like it to play in a loop. */ | ||
| virtual void setLooping (bool shouldLoop) { (void) shouldLoop; } | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,254 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource, | ||
| const bool deleteInputWhenDeleted, | ||
| const int numChannels_) | ||
| : input (inputSource, deleteInputWhenDeleted), | ||
| ratio (1.0), | ||
| lastRatio (1.0), | ||
| buffer (numChannels_, 0), | ||
| sampsInBuffer (0), | ||
| numChannels (numChannels_) | ||
| { | ||
| jassert (input != nullptr); | ||
| } | ||
|
|
||
| ResamplingAudioSource::~ResamplingAudioSource() {} | ||
|
|
||
| void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample) | ||
| { | ||
| jassert (samplesInPerOutputSample > 0); | ||
|
|
||
| const SpinLock::ScopedLockType sl (ratioLock); | ||
| ratio = jmax (0.0, samplesInPerOutputSample); | ||
| } | ||
|
|
||
| void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, | ||
| double sampleRate) | ||
| { | ||
| const SpinLock::ScopedLockType sl (ratioLock); | ||
|
|
||
| input->prepareToPlay (samplesPerBlockExpected, sampleRate); | ||
|
|
||
| buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); | ||
| buffer.clear(); | ||
| sampsInBuffer = 0; | ||
| bufferPos = 0; | ||
| subSampleOffset = 0.0; | ||
|
|
||
| filterStates.calloc ((size_t) numChannels); | ||
| srcBuffers.calloc ((size_t) numChannels); | ||
| destBuffers.calloc ((size_t) numChannels); | ||
| createLowPass (ratio); | ||
| resetFilters(); | ||
| } | ||
|
|
||
| void ResamplingAudioSource::releaseResources() | ||
| { | ||
| input->releaseResources(); | ||
| buffer.setSize (numChannels, 0); | ||
| } | ||
|
|
||
| void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | ||
| { | ||
| double localRatio; | ||
|
|
||
| { | ||
| const SpinLock::ScopedLockType sl (ratioLock); | ||
| localRatio = ratio; | ||
| } | ||
|
|
||
| if (lastRatio != localRatio) | ||
| { | ||
| createLowPass (localRatio); | ||
| lastRatio = localRatio; | ||
| } | ||
|
|
||
| const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 2; | ||
|
|
||
| int bufferSize = buffer.getNumSamples(); | ||
|
|
||
| if (bufferSize < sampsNeeded + 8) | ||
| { | ||
| bufferPos %= bufferSize; | ||
| bufferSize = sampsNeeded + 32; | ||
| buffer.setSize (buffer.getNumChannels(), bufferSize, true, true); | ||
| } | ||
|
|
||
| bufferPos %= bufferSize; | ||
|
|
||
| int endOfBufferPos = bufferPos + sampsInBuffer; | ||
| const int channelsToProcess = jmin (numChannels, info.buffer->getNumChannels()); | ||
|
|
||
| while (sampsNeeded > sampsInBuffer) | ||
| { | ||
| endOfBufferPos %= bufferSize; | ||
|
|
||
| int numToDo = jmin (sampsNeeded - sampsInBuffer, | ||
| bufferSize - endOfBufferPos); | ||
|
|
||
| AudioSourceChannelInfo readInfo (&buffer, endOfBufferPos, numToDo); | ||
| input->getNextAudioBlock (readInfo); | ||
|
|
||
| if (localRatio > 1.0001) | ||
| { | ||
| // for down-sampling, pre-apply the filter.. | ||
|
|
||
| for (int i = channelsToProcess; --i >= 0;) | ||
| applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]); | ||
| } | ||
|
|
||
| sampsInBuffer += numToDo; | ||
| endOfBufferPos += numToDo; | ||
| } | ||
|
|
||
| for (int channel = 0; channel < channelsToProcess; ++channel) | ||
| { | ||
| destBuffers[channel] = info.buffer->getSampleData (channel, info.startSample); | ||
| srcBuffers[channel] = buffer.getSampleData (channel, 0); | ||
| } | ||
|
|
||
| int nextPos = (bufferPos + 1) % bufferSize; | ||
| for (int m = info.numSamples; --m >= 0;) | ||
| { | ||
| const float alpha = (float) subSampleOffset; | ||
|
|
||
| for (int channel = 0; channel < channelsToProcess; ++channel) | ||
| *destBuffers[channel]++ = srcBuffers[channel][bufferPos] | ||
| + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]); | ||
|
|
||
| subSampleOffset += localRatio; | ||
|
|
||
| jassert (sampsInBuffer > 0); | ||
|
|
||
| while (subSampleOffset >= 1.0) | ||
| { | ||
| if (++bufferPos >= bufferSize) | ||
| bufferPos = 0; | ||
|
|
||
| --sampsInBuffer; | ||
|
|
||
| nextPos = (bufferPos + 1) % bufferSize; | ||
| subSampleOffset -= 1.0; | ||
| } | ||
| } | ||
|
|
||
| if (localRatio < 0.9999) | ||
| { | ||
| // for up-sampling, apply the filter after transposing.. | ||
| for (int i = channelsToProcess; --i >= 0;) | ||
| applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]); | ||
| } | ||
| else if (localRatio <= 1.0001 && info.numSamples > 0) | ||
| { | ||
| // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities | ||
| for (int i = channelsToProcess; --i >= 0;) | ||
| { | ||
| const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1); | ||
| FilterState& fs = filterStates[i]; | ||
|
|
||
| if (info.numSamples > 1) | ||
| { | ||
| fs.y2 = fs.x2 = *(endOfBuffer - 1); | ||
| } | ||
| else | ||
| { | ||
| fs.y2 = fs.y1; | ||
| fs.x2 = fs.x1; | ||
| } | ||
|
|
||
| fs.y1 = fs.x1 = *endOfBuffer; | ||
| } | ||
| } | ||
|
|
||
| jassert (sampsInBuffer >= 0); | ||
| } | ||
|
|
||
| void ResamplingAudioSource::createLowPass (const double frequencyRatio) | ||
| { | ||
| const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio | ||
| : 0.5 * frequencyRatio; | ||
|
|
||
| const double n = 1.0 / std::tan (double_Pi * jmax (0.001, proportionalRate)); | ||
| const double nSquared = n * n; | ||
| const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | ||
|
|
||
| setFilterCoefficients (c1, | ||
| c1 * 2.0f, | ||
| c1, | ||
| 1.0, | ||
| c1 * 2.0 * (1.0 - nSquared), | ||
| c1 * (1.0 - std::sqrt (2.0) * n + nSquared)); | ||
| } | ||
|
|
||
| void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6) | ||
| { | ||
| const double a = 1.0 / c4; | ||
|
|
||
| c1 *= a; | ||
| c2 *= a; | ||
| c3 *= a; | ||
| c5 *= a; | ||
| c6 *= a; | ||
|
|
||
| coefficients[0] = c1; | ||
| coefficients[1] = c2; | ||
| coefficients[2] = c3; | ||
| coefficients[3] = c4; | ||
| coefficients[4] = c5; | ||
| coefficients[5] = c6; | ||
| } | ||
|
|
||
| void ResamplingAudioSource::resetFilters() | ||
| { | ||
| filterStates.clear ((size_t) numChannels); | ||
| } | ||
|
|
||
| void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs) | ||
| { | ||
| while (--num >= 0) | ||
| { | ||
| const double in = *samples; | ||
|
|
||
| double out = coefficients[0] * in | ||
| + coefficients[1] * fs.x1 | ||
| + coefficients[2] * fs.x2 | ||
| - coefficients[4] * fs.y1 | ||
| - coefficients[5] * fs.y2; | ||
|
|
||
| #if JUCE_INTEL | ||
| if (! (out < -1.0e-8 || out > 1.0e-8)) | ||
| out = 0; | ||
| #endif | ||
|
|
||
| fs.x2 = fs.x1; | ||
| fs.x1 = in; | ||
| fs.y2 = fs.y1; | ||
| fs.y1 = out; | ||
|
|
||
| *samples++ = (float) out; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| A type of AudioSource that takes an input source and changes its sample rate. | ||
| @see AudioSource | ||
| */ | ||
| class JUCE_API ResamplingAudioSource : public AudioSource | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates a ResamplingAudioSource for a given input source. | ||
| @param inputSource the input source to read from | ||
| @param deleteInputWhenDeleted if true, the input source will be deleted when | ||
| this object is deleted | ||
| @param numChannels the number of channels to process | ||
| */ | ||
| ResamplingAudioSource (AudioSource* inputSource, | ||
| bool deleteInputWhenDeleted, | ||
| int numChannels = 2); | ||
|
|
||
| /** Destructor. */ | ||
| ~ResamplingAudioSource(); | ||
|
|
||
| /** Changes the resampling ratio. | ||
| (This value can be changed at any time, even while the source is running). | ||
| @param samplesInPerOutputSample if set to 1.0, the input is passed through; higher | ||
| values will speed it up; lower values will slow it | ||
| down. The ratio must be greater than 0 | ||
| */ | ||
| void setResamplingRatio (double samplesInPerOutputSample); | ||
|
|
||
| /** Returns the current resampling ratio. | ||
| This is the value that was set by setResamplingRatio(). | ||
| */ | ||
| double getResamplingRatio() const noexcept { return ratio; } | ||
|
|
||
| //============================================================================== | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
| void releaseResources(); | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
| private: | ||
| //============================================================================== | ||
| OptionalScopedPointer<AudioSource> input; | ||
| double ratio, lastRatio; | ||
| AudioSampleBuffer buffer; | ||
| int bufferPos, sampsInBuffer; | ||
| double subSampleOffset; | ||
| double coefficients[6]; | ||
| SpinLock ratioLock; | ||
| const int numChannels; | ||
| HeapBlock<float*> destBuffers, srcBuffers; | ||
|
|
||
| void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); | ||
| void createLowPass (double proportionalRate); | ||
|
|
||
| struct FilterState | ||
| { | ||
| double x1, x2, y1, y2; | ||
| }; | ||
|
|
||
| HeapBlock<FilterState> filterStates; | ||
| void resetFilters(); | ||
|
|
||
| void applyFilter (float* samples, int num, FilterState& fs); | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResamplingAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| ReverbAudioSource::ReverbAudioSource (AudioSource* const inputSource, const bool deleteInputWhenDeleted) | ||
| : input (inputSource, deleteInputWhenDeleted), | ||
| bypass (false) | ||
| { | ||
| jassert (inputSource != nullptr); | ||
| } | ||
|
|
||
| ReverbAudioSource::~ReverbAudioSource() {} | ||
|
|
||
| void ReverbAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) | ||
| { | ||
| const ScopedLock sl (lock); | ||
| input->prepareToPlay (samplesPerBlockExpected, sampleRate); | ||
| reverb.setSampleRate (sampleRate); | ||
| } | ||
|
|
||
| void ReverbAudioSource::releaseResources() {} | ||
|
|
||
| void ReverbAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) | ||
| { | ||
| const ScopedLock sl (lock); | ||
|
|
||
| input->getNextAudioBlock (bufferToFill); | ||
|
|
||
| if (! bypass) | ||
| { | ||
| float* const firstChannel = bufferToFill.buffer->getSampleData (0, bufferToFill.startSample); | ||
|
|
||
| if (bufferToFill.buffer->getNumChannels() > 1) | ||
| { | ||
| reverb.processStereo (firstChannel, | ||
| bufferToFill.buffer->getSampleData (1, bufferToFill.startSample), | ||
| bufferToFill.numSamples); | ||
| } | ||
| else | ||
| { | ||
| reverb.processMono (firstChannel, bufferToFill.numSamples); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void ReverbAudioSource::setParameters (const Reverb::Parameters& newParams) | ||
| { | ||
| const ScopedLock sl (lock); | ||
| reverb.setParameters (newParams); | ||
| } | ||
|
|
||
| void ReverbAudioSource::setBypassed (bool b) noexcept | ||
| { | ||
| if (bypass != b) | ||
| { | ||
| const ScopedLock sl (lock); | ||
| bypass = b; | ||
| reverb.reset(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
| #include "../effects/juce_Reverb.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| An AudioSource that uses the Reverb class to apply a reverb to another AudioSource. | ||
| @see Reverb | ||
| */ | ||
| class JUCE_API ReverbAudioSource : public AudioSource | ||
| { | ||
| public: | ||
| /** Creates a ReverbAudioSource to process a given input source. | ||
| @param inputSource the input source to read from - this must not be null | ||
| @param deleteInputWhenDeleted if true, the input source will be deleted when | ||
| this object is deleted | ||
| */ | ||
| ReverbAudioSource (AudioSource* inputSource, | ||
| bool deleteInputWhenDeleted); | ||
|
|
||
| /** Destructor. */ | ||
| ~ReverbAudioSource(); | ||
|
|
||
| //============================================================================== | ||
| /** Returns the parameters from the reverb. */ | ||
| const Reverb::Parameters& getParameters() const noexcept { return reverb.getParameters(); } | ||
|
|
||
| /** Changes the reverb's parameters. */ | ||
| void setParameters (const Reverb::Parameters& newParams); | ||
|
|
||
| void setBypassed (bool isBypassed) noexcept; | ||
| bool isBypassed() const noexcept { return bypass; } | ||
|
|
||
| //============================================================================== | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
| void releaseResources(); | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
| private: | ||
| //============================================================================== | ||
| CriticalSection lock; | ||
| OptionalScopedPointer<AudioSource> input; | ||
| Reverb reverb; | ||
| volatile bool bypass; | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReverbAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| ToneGeneratorAudioSource::ToneGeneratorAudioSource() | ||
| : frequency (1000.0), | ||
| sampleRate (44100.0), | ||
| currentPhase (0.0), | ||
| phasePerSample (0.0), | ||
| amplitude (0.5f) | ||
| { | ||
| } | ||
|
|
||
| ToneGeneratorAudioSource::~ToneGeneratorAudioSource() | ||
| { | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void ToneGeneratorAudioSource::setAmplitude (const float newAmplitude) | ||
| { | ||
| amplitude = newAmplitude; | ||
| } | ||
|
|
||
| void ToneGeneratorAudioSource::setFrequency (const double newFrequencyHz) | ||
| { | ||
| frequency = newFrequencyHz; | ||
| phasePerSample = 0.0; | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void ToneGeneratorAudioSource::prepareToPlay (int /*samplesPerBlockExpected*/, | ||
| double sampleRate_) | ||
| { | ||
| currentPhase = 0.0; | ||
| phasePerSample = 0.0; | ||
| sampleRate = sampleRate_; | ||
| } | ||
|
|
||
| void ToneGeneratorAudioSource::releaseResources() | ||
| { | ||
| } | ||
|
|
||
| void ToneGeneratorAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | ||
| { | ||
| if (phasePerSample == 0.0) | ||
| phasePerSample = double_Pi * 2.0 / (sampleRate / frequency); | ||
|
|
||
| for (int i = 0; i < info.numSamples; ++i) | ||
| { | ||
| const float sample = amplitude * (float) std::sin (currentPhase); | ||
| currentPhase += phasePerSample; | ||
|
|
||
| for (int j = info.buffer->getNumChannels(); --j >= 0;) | ||
| *info.buffer->getSampleData (j, info.startSample + i) = sample; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-11 by Raw Material Software Ltd. | ||
| ------------------------------------------------------------------------------ | ||
| JUCE can be redistributed and/or modified under the terms of the GNU General | ||
| Public License (Version 2), as published by the Free Software Foundation. | ||
| A copy of the license is included in the JUCE distribution, or can be found | ||
| online at www.gnu.org/licenses. | ||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
| ------------------------------------------------------------------------------ | ||
| To release a closed-source product which uses JUCE, commercial licenses are | ||
| available: visit www.rawmaterialsoftware.com/juce for more information. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ | ||
| #define __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ | ||
|
|
||
| #include "juce_AudioSource.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| A simple AudioSource that generates a sine wave. | ||
| */ | ||
| class JUCE_API ToneGeneratorAudioSource : public AudioSource | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| /** Creates a ToneGeneratorAudioSource. */ | ||
| ToneGeneratorAudioSource(); | ||
|
|
||
| /** Destructor. */ | ||
| ~ToneGeneratorAudioSource(); | ||
|
|
||
| //============================================================================== | ||
| /** Sets the signal's amplitude. */ | ||
| void setAmplitude (float newAmplitude); | ||
|
|
||
| /** Sets the signal's frequency. */ | ||
| void setFrequency (double newFrequencyHz); | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** Implementation of the AudioSource method. */ | ||
| void prepareToPlay (int samplesPerBlockExpected, double sampleRate); | ||
|
|
||
| /** Implementation of the AudioSource method. */ | ||
| void releaseResources(); | ||
|
|
||
| /** Implementation of the AudioSource method. */ | ||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); | ||
|
|
||
|
|
||
| private: | ||
| //============================================================================== | ||
| double frequency, sampleRate; | ||
| double currentPhase, phasePerSample; | ||
| float amplitude; | ||
|
|
||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToneGeneratorAudioSource) | ||
| }; | ||
|
|
||
|
|
||
| #endif // __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ |