Revision 0:02467299402e CollidoscopeApp
| CollidoscopeApp/include/AudioEngine.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
#include <array> |
| ... | ... | |
| 35 | 14 |
#include "Config.h" |
| 36 | 15 |
|
| 37 | 16 |
|
| 38 |
/** |
|
| 39 |
* Audio engine of the application. It uses the Cinder library to process audio in input and output. |
|
| 40 |
* The audio engine manages both waves. All methods have a waveIndx parameter to address a specific wave. |
|
| 41 |
*/ |
|
| 42 | 17 |
class AudioEngine |
| 43 | 18 |
{
|
| 44 | 19 |
public: |
| ... | ... | |
| 51 | 26 |
AudioEngine( const AudioEngine © ) = delete; |
| 52 | 27 |
AudioEngine & operator=(const AudioEngine ©) = delete; |
| 53 | 28 |
|
| 54 |
/** |
|
| 55 |
* Set up of the audio engine. |
|
| 56 |
*/ |
|
| 57 | 29 |
void setup( const Config& Config ); |
| 58 | 30 |
|
| 59 | 31 |
size_t getSampleRate(); |
| ... | ... | |
| 68 | 40 |
|
| 69 | 41 |
void noteOff( size_t waveIdx, int note ); |
| 70 | 42 |
|
| 71 |
/** |
|
| 72 |
* Returns the number of elements available to read in the wave ring buffer. |
|
| 73 |
* The wave ring buffer is used to pass the size of the wave chunks from the audio thread to the graphic thread, |
|
| 74 |
* when a new wave is recorded. |
|
| 75 |
*/ |
|
| 76 | 43 |
size_t getRecordWaveAvailable( size_t index ); |
| 77 |
/** |
|
| 78 |
* Called from the graphic thread. Reads \a count elements from the wave ring buffer into \a buffer. |
|
| 79 |
* The wave ring buffer is used to pass the size of the wave chunks from the audio thread to the graphic thread, |
|
| 80 |
* when a new wave is recorded. |
|
| 81 |
* |
|
| 82 |
*/ |
|
| 83 |
bool readRecordWave( size_t waveIdx, RecordWaveMsg* buffer, size_t count ); |
|
| 44 |
|
|
| 45 |
bool readRecordWave( size_t waveIdx, RecordWaveMsg*, size_t count ); |
|
| 84 | 46 |
|
| 85 | 47 |
void setSelectionSize( size_t waveIdx, size_t size ); |
| 86 | 48 |
|
| ... | ... | |
| 92 | 54 |
|
| 93 | 55 |
void checkCursorTriggers( size_t waveIdx, std::vector<CursorTriggerMsg>& cursorTriggers ); |
| 94 | 56 |
|
| 95 |
/** |
|
| 96 |
* Returns a const reference to the audio output buffer. This is the buffer that is sent off to the audio interface at each audio cycle. |
|
| 97 |
* It is used in the graphic thread to draw the oscilloscope. |
|
| 98 |
*/ |
|
| 99 | 57 |
const ci::audio::Buffer& getAudioOutputBuffer( size_t waveIdx ) const; |
| 100 | 58 |
|
| 101 | 59 |
|
| ... | ... | |
| 106 | 64 |
// nodes for recording audio input into buffer. Also sends chunks information through |
| 107 | 65 |
// non-blocking queue |
| 108 | 66 |
std::array< BufferToWaveRecorderNodeRef, NUM_WAVES > mBufferRecorderNodes; |
| 109 |
// pgranulars wrapped in a Cinder::Node
|
|
| 67 |
// pgranulars for loop synths
|
|
| 110 | 68 |
std::array< PGranularNodeRef, NUM_WAVES > mPGranularNodes; |
| 111 | 69 |
|
| 112 | 70 |
|
| ... | ... | |
| 118 | 76 |
|
| 119 | 77 |
std::array< std::unique_ptr< RingBufferPack<CursorTriggerMsg> >, NUM_WAVES > mCursorTriggerRingBufferPacks; |
| 120 | 78 |
|
| 121 |
}; |
|
| 79 |
}; |
|
| CollidoscopeApp/include/BufferToWaveRecorderNode.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
|
|
| 21 |
This file incorporates work covered by the following copyright and permission notice: |
|
| 22 |
|
|
| 23 |
Copyright (c) 2014, The Cinder Project |
|
| 24 |
|
|
| 25 |
This code is intended to be used with the Cinder C++ library, http://libcinder.org |
|
| 26 |
|
|
| 27 |
Redistribution and use in source and binary forms, with or without modification, are permitted provided that |
|
| 28 |
the following conditions are met: |
|
| 29 |
|
|
| 30 |
* Redistributions of source code must retain the above copyright notice, this list of conditions and |
|
| 31 |
the following disclaimer. |
|
| 32 |
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and |
|
| 33 |
the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
| 34 |
|
|
| 35 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED |
|
| 36 |
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
| 37 |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
|
| 38 |
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
|
| 39 |
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
| 40 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
| 41 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
| 42 |
POSSIBILITY OF SUCH DAMAGE. |
|
| 43 |
|
|
| 44 |
*/ |
|
| 45 |
|
|
| 46 | 1 |
#pragma once |
| 47 | 2 |
|
| 48 | 3 |
#include "cinder/Cinder.h" |
| ... | ... | |
| 53 | 8 |
|
| 54 | 9 |
#include "Messages.h" |
| 55 | 10 |
|
| 56 |
typedef std::shared_ptr<class BufferToWaveRecorderNode> BufferToWaveRecorderNodeRef;
|
|
| 11 |
typedef std::shared_ptr<class BufferToWaveRecorderNode> BufferToWaveRecorderNodeRef;
|
|
| 57 | 12 |
|
| 58 | 13 |
typedef ci::audio::dsp::RingBufferT<RecordWaveMsg> RecordWaveMsgRingBuffer; |
| 59 | 14 |
|
| 60 |
/** |
|
| 61 |
* A \a Node in the audio graph of the Cinder audio library that records input in a buffer. |
|
| 62 |
* |
|
| 63 |
* This class is similar to \a cinder::audio::BufferRecorderNode (it's a derivative work of this class indeed) but it has an additional feature: |
|
| 64 |
* when recording, it uses the audio input samples to compute the size values of the visual chunks. |
|
| 65 |
* The chunks values are stored in a ring buffer and fetched by the graphic thread to paint the wave as it gets recorded. |
|
| 66 |
* |
|
| 67 |
*/ |
|
| 15 |
|
|
| 68 | 16 |
class BufferToWaveRecorderNode : public ci::audio::SampleRecorderNode {
|
| 69 | 17 |
public: |
| 70 | 18 |
|
| ... | ... | |
| 88 | 36 |
void setNumSeconds(double numSeconds, bool shrinkToFit = false); |
| 89 | 37 |
|
| 90 | 38 |
//! Returns the length of the recording buffer in frames. |
| 91 |
size_t getNumFrames() const { return mRecorderBuffer.getNumFrames(); }
|
|
| 39 |
size_t getNumFrames() const { return mRecorderBuffer.getNumFrames(); }
|
|
| 92 | 40 |
//! Returns the length of the recording buffer in seconds. |
| 93 |
double getNumSeconds() const;
|
|
| 41 |
double getNumSeconds() const;
|
|
| 94 | 42 |
|
| 95 | 43 |
//! \brief Returns a copy of the recored samples, up to the current write position. |
| 96 | 44 |
//! |
| 97 | 45 |
//! This method is non locking, and as such any resizing calls must be performed on the same thread or be otherwise synchronized. |
| 98 |
ci::audio::BufferRef getRecordedCopy() const;
|
|
| 46 |
ci::audio::BufferRef getRecordedCopy() const;
|
|
| 99 | 47 |
|
| 100 | 48 |
//! \brief Writes the currently recorded samples to a file at \a filePath |
| 101 | 49 |
//! |
| ... | ... | |
| 106 | 54 |
//! Returns the frame of the last buffer overrun or 0 if none since the last time this method was called. When this happens, it means the recorded buffer probably has skipped some frames. |
| 107 | 55 |
uint64_t getLastOverrun(); |
| 108 | 56 |
|
| 109 |
//! returns a reference to the ring buffer when the size values of the chunks is stored, when a new wave is recorder |
|
| 110 | 57 |
RecordWaveMsgRingBuffer& getRingBuffer() { return mRingBuffer; }
|
| 111 | 58 |
|
| 112 |
//!returns a pointer to the buffer where the audio is recorder. This is used by the PGranular to create the granular synthesis |
|
| 113 | 59 |
ci::audio::Buffer* getRecorderBuffer() { return &mRecorderBuffer; }
|
| 114 | 60 |
|
| 115 | 61 |
|
| 116 | 62 |
protected: |
| 117 |
void initialize() override;
|
|
| 118 |
void process(ci::audio::Buffer *buffer) override;
|
|
| 63 |
void initialize() override;
|
|
| 64 |
void process(ci::audio::Buffer *buffer) override;
|
|
| 119 | 65 |
|
| 120 | 66 |
void initBuffers(size_t numFrames); |
| 121 | 67 |
|
| 122 | 68 |
static const float kMinAudioVal; |
| 123 | 69 |
static const float kMaxAudioVal; |
| 124 | 70 |
|
| 125 |
ci::audio::BufferDynamic mRecorderBuffer;
|
|
| 126 |
ci::audio::BufferDynamicRef mCopiedBuffer;
|
|
| 127 |
std::atomic<uint64_t> mLastOverrun;
|
|
| 71 |
ci::audio::BufferDynamic mRecorderBuffer;
|
|
| 72 |
ci::audio::BufferDynamicRef mCopiedBuffer;
|
|
| 73 |
std::atomic<uint64_t> mLastOverrun;
|
|
| 128 | 74 |
|
| 129 | 75 |
RecordWaveMsgRingBuffer mRingBuffer; |
| 130 | 76 |
|
| CollidoscopeApp/include/Chunk.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2015 Fiore Martin |
|
| 4 |
Copyright (C) 2016 Queen Mary University of London |
|
| 5 |
Author: Fiore Martin |
|
| 6 |
|
|
| 7 |
This file is part of Collidoscope. |
|
| 8 |
|
|
| 9 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 10 |
it under the terms of the GNU General Public License as published by |
|
| 11 |
the Free Software Foundation, either version 3 of the License, or |
|
| 12 |
(at your option) any later version. |
|
| 13 |
|
|
| 14 |
This program is distributed in the hope that it will be useful, |
|
| 15 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 16 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 17 |
GNU General Public License for more details. |
|
| 18 |
|
|
| 19 |
You should have received a copy of the GNU General Public License |
|
| 20 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 21 |
|
|
| 22 |
*/ |
|
| 23 |
|
|
| 24 | 1 |
|
| 25 | 2 |
#pragma once |
| 26 | 3 |
|
| ... | ... | |
| 29 | 6 |
|
| 30 | 7 |
class DrawInfo; |
| 31 | 8 |
|
| 32 |
/** |
|
| 33 |
* |
|
| 34 |
* A chunk of audio in Collidoscope low-fi visual wave. |
|
| 35 |
* |
|
| 36 |
* The visual wave of Collidoscope is made out of a number of bars that mimic, in a low-fi fashion, the typical waveform-based representation of audio. |
|
| 37 |
* A Chunk is one of the bars of the visual wave. |
|
| 38 |
* |
|
| 39 |
*/ |
|
| 40 |
|
|
| 41 | 9 |
class Chunk |
| 42 | 10 |
{
|
| 43 | 11 |
|
| ... | ... | |
| 46 | 14 |
const static float kWidth; |
| 47 | 15 |
const static float kHalfWidth; |
| 48 | 16 |
|
| 49 |
/** |
|
| 50 |
* Constructor, takes as argument the index of this chunk in the wave that contains it |
|
| 51 |
*/ |
|
| 52 |
Chunk( size_t index ); |
|
| 17 |
Chunk( size_t index ); |
|
| 53 | 18 |
|
| 54 |
/** |
|
| 55 |
* Sets the top value of this chunk. The value is passed in audio coordinates : [-1.0, 1.0] |
|
| 56 |
*/ |
|
| 57 | 19 |
void inline setTop(float t) { mAudioTop = t; mAnimate = 0.0f; mResetting = false; /* startes the animation to crate a chunk */ }
|
| 58 |
/** |
|
| 59 |
* Sets the bottom value of this chunk. The value is passed in audio coordinates : [-1.0, 1.0] |
|
| 60 |
*/ |
|
| 61 | 20 |
void inline setBottom(float b) { mAudioBottom = b; mAnimate = 0.0f; mResetting = false; }
|
| 62 |
/** |
|
| 63 |
* Get the top value of this chunk. The value is returned in audio coordinates : [-1.0, 1.0] |
|
| 64 |
*/ |
|
| 65 | 21 |
float inline getTop() const { return mAudioTop; }
|
| 66 |
/** |
|
| 67 |
* Get the bottom value of this chunk. The value is returned in audio coordinates : [-1.0, 1.0] |
|
| 68 |
*/ |
|
| 69 | 22 |
float inline getBottom() const { return mAudioBottom; }
|
| 70 | 23 |
|
| 71 |
/** |
|
| 72 |
* Reset this chunks. When a chunk is reset, it starts shrinking until it disappears or setTop/setBottom are called again |
|
| 73 |
* |
|
| 74 |
*/ |
|
| 75 |
void reset(){
|
|
| 76 |
mResetting = true; |
|
| 77 |
} |
|
| 24 |
void reset(){
|
|
| 25 |
mResetting = true; |
|
| 26 |
} |
|
| 78 | 27 |
|
| 79 |
/** |
|
| 80 |
* Called in the graphic loop. It update this chunk. |
|
| 81 |
*/ |
|
| 82 | 28 |
void update( const DrawInfo& di ); |
| 83 | 29 |
|
| 84 |
/** |
|
| 85 |
* Called in the graphic loop. It draws this chunk. |
|
| 86 |
*/ |
|
| 87 | 30 |
void draw( const DrawInfo& di, ci::gl::BatchRef &batch ); |
| 88 | 31 |
|
| 89 |
/** |
|
| 90 |
* Called in the graphic loop. It draws this chunk all the way to the bottom of the screen. |
|
| 91 |
* This method is called when the chunk is the first or last in a selection. |
|
| 92 |
*/ |
|
| 93 | 32 |
void drawBar( const DrawInfo& di, ci::gl::BatchRef &batch ); |
| 94 | 33 |
|
| 95 |
/** |
|
| 96 |
* Informs this chunk that it's the first chunk of the selection. |
|
| 97 |
*/ |
|
| 98 |
void setAsSelectionStart(bool start){
|
|
| 99 |
isSelectionStart = start; |
|
| 100 |
} |
|
| 34 |
void setAsSelectionStart(bool start){
|
|
| 35 |
isSelectionStart = start; |
|
| 36 |
} |
|
| 101 | 37 |
|
| 102 |
/** |
|
| 103 |
* Informs this chunk that it's the last chunk of the selection. |
|
| 104 |
*/ |
|
| 105 |
void setAsSelectionEnd(bool end){
|
|
| 106 |
isSelectionEnd = end; |
|
| 107 |
} |
|
| 38 |
void setAsSelectionEnd(bool end){
|
|
| 39 |
isSelectionEnd = end; |
|
| 40 |
} |
|
| 108 | 41 |
|
| 109 | 42 |
private: |
| 110 | 43 |
|
| CollidoscopeApp/include/Config.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
#include <string> |
| ... | ... | |
| 27 | 6 |
#include "cinder/Xml.h" |
| 28 | 7 |
|
| 29 | 8 |
|
| 30 |
/** |
|
| 31 |
* Configuration class gathers in one place all the values recided at runtime |
|
| 32 |
* |
|
| 33 |
* Reading the configuration from an XML file is partially implemented but not used at the moment |
|
| 34 |
* |
|
| 35 |
*/ |
|
| 36 | 9 |
class Config |
| 37 | 10 |
{
|
| 38 | 11 |
public: |
| ... | ... | |
| 48 | 21 |
|
| 49 | 22 |
std::string getInputDeviceKey() const |
| 50 | 23 |
{
|
| 51 |
return mAudioInputDeviceKey; |
|
| 24 |
return mAudioInputDeviceKey; // Komplete 1/2 |
|
| 25 |
//return "{0.0.1.00000000}.{a043bc8c-1dd1-4c94-82b4-ad8320cac5a5}"; // Komplete 3/4
|
|
| 26 |
//return "{0.0.1.00000000}.{828b681b-cc0c-44e1-93c9-5f1f46f5926f}"; // Realtek
|
|
| 52 | 27 |
} |
| 53 | 28 |
|
| 54 |
/** |
|
| 55 |
* Returns number of chunks in a wave |
|
| 56 |
*/ |
|
| 57 | 29 |
std::size_t getNumChunks() const |
| 58 | 30 |
{
|
| 59 | 31 |
return mNumChunks; |
| 60 | 32 |
} |
| 61 | 33 |
|
| 62 |
/** returns wave lenght in seconds */
|
|
| 34 |
/* return wave lenght in seconds */
|
|
| 63 | 35 |
double getWaveLen() const |
| 64 | 36 |
{
|
| 65 | 37 |
return mWaveLen; |
| 66 | 38 |
} |
| 67 | 39 |
|
| 68 |
/** |
|
| 69 |
* Returns wave selection color |
|
| 70 |
*/ |
|
| 71 | 40 |
ci::Color getWaveSelectionColor(size_t waveIdx) const |
| 72 | 41 |
{
|
| 73 | 42 |
if (waveIdx == 0){
|
| ... | ... | |
| 78 | 47 |
} |
| 79 | 48 |
} |
| 80 | 49 |
|
| 81 |
/** |
|
| 82 |
* The size of the ring buffer used to trigger a visual cursor from the audio thread when a new grain is created |
|
| 83 |
*/ |
|
| 84 | 50 |
std::size_t getCursorTriggerMessageBufSize() const |
| 85 | 51 |
{
|
| 86 | 52 |
return 512; |
| 87 | 53 |
} |
| 88 | 54 |
|
| 89 |
/** returns the index of the wave associated to the MIDI channel passed as argument */
|
|
| 55 |
// returns the index of the wave associated to the MIDI channel passed as argument
|
|
| 90 | 56 |
size_t getWaveForMIDIChannel( unsigned char channelIdx ) |
| 91 | 57 |
{
|
| 92 | 58 |
return channelIdx; |
| 59 |
/*for ( int i = 0; i < NUM_WAVES; i++ ){
|
|
| 60 |
if ( channelIdx == mMidiChannels[i] ) |
|
| 61 |
return i; |
|
| 62 |
}*/ |
|
| 93 | 63 |
} |
| 94 | 64 |
|
| 95 | 65 |
double getMaxGrainDurationCoeff() const |
| ... | ... | |
| 112 | 82 |
return 6; |
| 113 | 83 |
} |
| 114 | 84 |
|
| 115 |
/** |
|
| 116 |
* Returns the maximum size of a wave selection in number of chunks. |
|
| 117 |
*/ |
|
| 118 | 85 |
size_t getMaxSelectionNumChunks() const |
| 119 | 86 |
{
|
| 120 | 87 |
return 37; |
| 121 | 88 |
} |
| 122 | 89 |
|
| 123 |
/** |
|
| 124 |
* The value returned is used when creating the oscilloscope. |
|
| 125 |
* The oscilloscope represents the audio output buffer graphically. However it doesn't need to be as refined as the |
|
| 126 |
* audio wave and it's downsampled using the following formula : (number of oscilloscope points) = (size of audio output buffer) / getOscilloscopeNumPointsDivider() |
|
| 127 |
*/ |
|
| 128 | 90 |
size_t getOscilloscopeNumPointsDivider() const |
| 129 | 91 |
{
|
| 130 | 92 |
return 4; |
| CollidoscopeApp/include/DrawInfo.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
#include "cinder/Area.h" |
| 25 | 4 |
|
| 26 |
/** |
|
| 27 |
* The DrawInfo class holds size information for drawing the waves in the screen. |
|
| 28 |
* Every time the screen is resized the draw info is updated with the new information about the window size. |
|
| 29 |
* |
|
| 30 |
* Every wave has its own drawInfo. |
|
| 31 |
* |
|
| 32 |
*/ |
|
| 33 | 5 |
class DrawInfo |
| 34 | 6 |
{
|
| 35 | 7 |
public: |
| 36 | 8 |
|
| 37 |
/** |
|
| 38 |
* Constructor. Takes the index of the wave as argument. |
|
| 39 |
*/ |
|
| 40 | 9 |
DrawInfo( size_t waveIndex ): |
| 41 | 10 |
mWaveIndex( waveIndex ), |
| 42 | 11 |
mWindowWidth(0), |
| ... | ... | |
| 45 | 14 |
mShrinkFactor(1) |
| 46 | 15 |
{}
|
| 47 | 16 |
|
| 48 |
/** |
|
| 49 |
* Reset this DrawInfo using the new bounding area for the wave. \a shrinkFactor |
|
| 50 |
* makes the wave shrink on the y axis with respect to the area. A factor 1 makes the wave as big as the area, whereas a factor >1 makes it shrink. |
|
| 51 |
*/ |
|
| 52 | 17 |
void reset( const ci::Area &bounds, float shrinkFactor ) |
| 53 | 18 |
{
|
| 54 | 19 |
mWindowWidth = bounds.getWidth(); |
| ... | ... | |
| 57 | 22 |
mShrinkFactor = shrinkFactor; |
| 58 | 23 |
} |
| 59 | 24 |
|
| 60 |
/** |
|
| 61 |
* Maps a value in the audio space [-1.0, 1.0] to a position on the y axis of this DrawInfo's bounding area. |
|
| 62 |
* |
|
| 63 |
*/ |
|
| 64 |
float audioToHeigt(float audioSample) const {
|
|
| 25 |
float audioToHeigt(float audioSample) const {
|
|
| 65 | 26 |
/* clip into range [-1.1] */ |
| 66 | 27 |
if (audioSample < -1.0f) {
|
| 67 | 28 |
audioSample = -1.0f; |
| ... | ... | |
| 71 | 32 |
} |
| 72 | 33 |
|
| 73 | 34 |
/* map from [-1,1] to [0,1] */ |
| 74 |
float ratio = (audioSample - (-1.0f)) * 0.5f; // 2 = 1 - (-1)
|
|
| 35 |
float ratio = (audioSample - (-1.0f)) * 0.5f; // 2 = 1 - (-1)
|
|
| 75 | 36 |
|
| 76 |
/* get bottom and add the scaled height */
|
|
| 37 |
/* get bottom and add the scaled height */
|
|
| 77 | 38 |
return ratio * mSelectionBarHeight; //remove bounds.getY1() bound only needed for size of tier |
| 78 |
}
|
|
| 39 |
}
|
|
| 79 | 40 |
|
| 80 | 41 |
float getMaxChunkHeight() const |
| 81 | 42 |
{
|
| ... | ... | |
| 87 | 48 |
return mSelectionBarHeight; |
| 88 | 49 |
} |
| 89 | 50 |
|
| 90 |
/** |
|
| 91 |
* Returns the center position on the y axis of this DrawInfo's the bounding area. |
|
| 92 |
*/ |
|
| 93 | 51 |
int32_t getWaveCenterY() const |
| 94 | 52 |
{
|
| 95 | 53 |
if ( mWaveIndex == 0 ) |
| 96 |
return mWindowHeight - ( mWindowHeight / ( 2 * NUM_WAVES ) ) + 1;
|
|
| 54 |
return mWindowHeight * 0.75f + 1;
|
|
| 97 | 55 |
else |
| 98 | 56 |
return mWindowHeight / (NUM_WAVES * 2); |
| 99 | 57 |
} |
| 100 | 58 |
|
| 101 |
/** |
|
| 102 |
* Flips y according to the index of the wave. It is needed because the second wave in collidoscope is drawn upside down in the screen. |
|
| 103 |
*/ |
|
| 104 |
int flipY(int y) const |
|
| 59 |
int flipY(int y) const |
|
| 105 | 60 |
{
|
| 106 | 61 |
if ( mWaveIndex == 0) |
| 107 |
return mWindowHeight - y;
|
|
| 62 |
return mWindowHeight - y /*+ 24*/;
|
|
| 108 | 63 |
else |
| 109 |
return y; |
|
| 110 |
}
|
|
| 64 |
return y /*- 24*/;
|
|
| 65 |
}
|
|
| 111 | 66 |
|
| 112 |
/** |
|
| 113 |
* Returns x. not used at the moment. |
|
| 114 |
* |
|
| 115 |
*/ |
|
| 116 |
int flipX(int x) const |
|
| 67 |
int flipX(int x) const |
|
| 117 | 68 |
{
|
| 118 | 69 |
return x; |
| 119 |
}
|
|
| 70 |
}
|
|
| 120 | 71 |
|
| 121 | 72 |
|
| 122 | 73 |
// how much the wave is shrunk on the y axis with respect to the wave's tier |
| ... | ... | |
| 135 | 86 |
return mWindowHeight; |
| 136 | 87 |
} |
| 137 | 88 |
|
| 138 |
/** |
|
| 139 |
* Draw infos cannot be copied and should be passed as const reference. |
|
| 140 |
*/ |
|
| 141 | 89 |
DrawInfo( const DrawInfo &original ) = delete; |
| 142 | 90 |
DrawInfo & operator=( const DrawInfo &original ) = delete; |
| 143 | 91 |
|
| CollidoscopeApp/include/EnvASR.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin, based on CCRMA STK ADSR.h (https://ccrma.stanford.edu/software/stk/classstk_1_1ADSR.html) |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
|
|
| 21 |
This file incorporates work covered by the following copyright and permission notice: |
|
| 22 |
|
|
| 23 |
The Synthesis ToolKit in C++ (STK) |
|
| 24 |
|
|
| 25 |
Copyright (c) 1995--2016 Perry R. Cook and Gary P. Scavone |
|
| 26 |
|
|
| 27 |
Permission is hereby granted, free of charge, to any person obtaining |
|
| 28 |
a copy of this software and associated documentation files (the |
|
| 29 |
"Software"), to deal in the Software without restriction, including |
|
| 30 |
without limitation the rights to use, copy, modify, merge, publish, |
|
| 31 |
distribute, sublicense, and/or sell copies of the Software, and to |
|
| 32 |
permit persons to whom the Software is furnished to do so, subject to |
|
| 33 |
the following conditions: |
|
| 34 |
|
|
| 35 |
The above copyright notice and this permission notice shall be |
|
| 36 |
included in all copies or substantial portions of the Software. |
|
| 37 |
|
|
| 38 |
Any person wishing to distribute modifications to the Software is |
|
| 39 |
asked to send the modifications to the original developer so that they |
|
| 40 |
can be incorporated into the canonical version. This is, however, not |
|
| 41 |
a binding provision of this license. |
|
| 42 |
|
|
| 43 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
| 44 |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
| 45 |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
| 46 |
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR |
|
| 47 |
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
|
| 48 |
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
| 49 |
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
| 50 |
|
|
| 51 |
*/ |
|
| 52 |
|
|
| 53 | 1 |
#pragma once |
| 54 | 2 |
|
| 55 | 3 |
namespace collidoscope {
|
| 56 | 4 |
|
| 57 |
|
|
| 58 |
/* |
|
| 59 |
* An ASR envelope with linear shape. It is modeled after the STK envelope classes. |
|
| 60 |
* The tick() method advances the computation of the envelope one sample and returns the computed sample |
|
| 61 |
* The class is templated for the type of the samples that each tick of the envelope produces. |
|
| 62 |
* |
|
| 63 |
* Client classes can set/get the current state of the envelope with the |
|
| 64 |
* respective getter/setter methods |
|
| 65 |
* |
|
| 66 |
*/ |
|
| 67 | 5 |
template <typename T> |
| 68 | 6 |
class EnvASR |
| 69 | 7 |
{
|
| 70 | 8 |
public: |
| 71 | 9 |
|
| 72 |
/** Possible states of the envelope. Idle means the envelope ouputs 0 */ |
|
| 73 | 10 |
enum class State {
|
| 74 | 11 |
eAttack, |
| 75 | 12 |
eSustain, |
| ... | ... | |
| 93 | 30 |
mReleaseRate = T( 1.0 ) / (releaseTime * sampleRate); |
| 94 | 31 |
} |
| 95 | 32 |
|
| 96 |
/** Produces one sample worth of envelope */ |
|
| 97 | 33 |
T tick() |
| 98 | 34 |
{
|
| 99 | 35 |
|
| ... | ... | |
| 152 | 88 |
}; |
| 153 | 89 |
|
| 154 | 90 |
|
| 155 |
} |
|
| 91 |
} |
|
| CollidoscopeApp/include/Log.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
|
| 25 |
/** |
|
| 26 |
* Utility function to log errors using the cinder::log library. |
|
| 27 |
* Errors are logged to collidoscope_error.log file. |
|
| 28 |
* |
|
| 29 |
*/ |
|
| 4 |
|
|
| 30 | 5 |
void logError( const std::string &errorMsg ); |
| 31 | 6 |
|
| 32 | 7 |
|
| 33 |
/** |
|
| 34 |
* Utility function to log info using the cinder::log library. |
|
| 35 |
* Errors are logged to the terminal. Used only for debugging. |
|
| 36 |
* |
|
| 37 |
*/ |
|
| 38 |
void logInfo( const std::string &infoMsg ); |
|
| 8 |
void logInfo( const std::string &infoMsg ); |
|
| CollidoscopeApp/include/MIDI.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
#include "RtMidi.h" |
| ... | ... | |
| 31 | 10 |
|
| 32 | 11 |
namespace collidoscope {
|
| 33 | 12 |
|
| 34 |
// Exception thrown by MIDI system |
|
| 13 |
|
|
| 35 | 14 |
class MIDIException : public std::exception |
| 36 | 15 |
{
|
| 37 | 16 |
public: |
| ... | ... | |
| 50 | 29 |
std::string mMessage; |
| 51 | 30 |
}; |
| 52 | 31 |
|
| 53 |
/** |
|
| 54 |
* A MIDI message |
|
| 55 |
*/ |
|
| 56 | 32 |
class MIDIMessage |
| 57 | 33 |
{
|
| 58 | 34 |
friend class MIDI; |
| ... | ... | |
| 64 | 40 |
|
| 65 | 41 |
unsigned char getChannel() { return mChannel; }
|
| 66 | 42 |
|
| 67 |
/** |
|
| 68 |
* First byte of MIDI data |
|
| 69 |
*/ |
|
| 70 | 43 |
unsigned char getData_1() { return mData1; }
|
| 71 | 44 |
|
| 72 |
/** |
|
| 73 |
* Second byte of MIDI data |
|
| 74 |
*/ |
|
| 75 | 45 |
unsigned char getData_2() { return mData2; }
|
| 76 | 46 |
|
| 77 | 47 |
private: |
| ... | ... | |
| 84 | 54 |
|
| 85 | 55 |
}; |
| 86 | 56 |
|
| 87 |
/** |
|
| 88 |
* Handles MIDI messages from the keyboards and Teensy. It uses RtMidi library. |
|
| 89 |
* |
|
| 90 |
*/ |
|
| 57 |
|
|
| 91 | 58 |
class MIDI |
| 92 | 59 |
{
|
| 93 | 60 |
|
| ... | ... | |
| 98 | 65 |
|
| 99 | 66 |
void setup( const Config& ); |
| 100 | 67 |
|
| 101 |
/** |
|
| 102 |
* Check new incoming messages and stores them into the vector passed as argument by reference. |
|
| 103 |
*/ |
|
| 104 | 68 |
void checkMessages( std::vector< MIDIMessage >& ); |
| 105 | 69 |
|
| 106 | 70 |
private: |
| 107 | 71 |
|
| 108 |
// callback passed to RtMidi library |
|
| 109 | 72 |
static void RtMidiInCallback( double deltatime, std::vector<unsigned char> *message, void *userData ); |
| 110 | 73 |
|
| 111 |
// parse RtMidi messages and turns them into more readable collidoscope::MIDIMessages |
|
| 112 | 74 |
MIDIMessage parseRtMidiMessage( std::vector<unsigned char> *message ); |
| 113 | 75 |
|
| 114 |
// messages to pass to checkMessages caller
|
|
| 76 |
// messages to pass to checkMessages caller |
|
| 115 | 77 |
std::vector< MIDIMessage > mMIDIMessages; |
| 116 |
// use specific variables for pitch bend messages. Pitch bend messages are coming |
|
| 117 |
// from the strip sensors that are very jerky and send a lot of values. So instead |
|
| 118 |
// of saving all the messages in mMIDIMessages just save the last received in mPitchBendMessages |
|
| 119 |
// and optimize away redundant messages. |
|
| 120 | 78 |
std::array< MIDIMessage, NUM_WAVES > mPitchBendMessages; |
| 121 |
// Same principle as mPitchBendMessages |
|
| 122 | 79 |
std::array< MIDIMessage, NUM_WAVES > mFilterMessages; |
| 123 | 80 |
|
| 124 |
// vector containing all the MIDI input devices detected. |
|
| 81 |
|
|
| 82 |
|
|
| 125 | 83 |
std::vector< std::unique_ptr <RtMidiIn> > mInputs; |
| 126 |
// Used for mutual access to the MIDI messages by the MIDI thread and the graphic thread. |
|
| 127 | 84 |
std::mutex mMutex; |
| 128 | 85 |
}; |
| 129 | 86 |
|
| CollidoscopeApp/include/Messages.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 |
/** |
|
| 25 |
* Enumeration of all the possible commands exchanged between audio thread and graphic thread. |
|
| 26 |
* |
|
| 27 |
*/ |
|
| 3 |
|
|
| 28 | 4 |
enum class Command {
|
| 29 | 5 |
// message carrying info about one chunk of recorder audio. |
| 30 | 6 |
WAVE_CHUNK, |
| 31 | 7 |
// message sent when a new recording starts. The gui resets the wave upon receiving it. |
| 32 | 8 |
WAVE_START, |
| 33 | 9 |
|
| 34 |
// new grain created |
|
| 35 | 10 |
TRIGGER_UPDATE, |
| 36 |
// synth became idle |
|
| 37 | 11 |
TRIGGER_END, |
| 38 | 12 |
|
| 39 | 13 |
NOTE_ON, |
| ... | ... | |
| 43 | 17 |
LOOP_OFF |
| 44 | 18 |
}; |
| 45 | 19 |
|
| 46 |
/** Message sent from the audio thread to the graphic wave when a new wave is recorded. |
|
| 47 |
* |
|
| 48 |
* The graphic thread sets the chunks of the wave to reflect the level of the recorded audio. |
|
| 49 |
* The algorithm takes the maximum and minimum value of a group of samples and this becomes the top and bottom of the chunk. |
|
| 50 |
* The message carries also the index of the chunk it refers to |
|
| 51 |
*/ |
|
| 20 |
/* Messages sent from the audio thread to the graphic wave. |
|
| 21 |
This includes the wave chunks when the audio is recorder in the buffer and |
|
| 22 |
the cursor position when the grains are reset. |
|
| 23 |
*/ |
|
| 52 | 24 |
struct RecordWaveMsg |
| 53 | 25 |
{
|
| 54 |
Command cmd; // WAVE_CHUNK or WAVE_START
|
|
| 26 |
Command cmd; |
|
| 55 | 27 |
std::size_t index; |
| 56 | 28 |
float arg1; |
| 57 | 29 |
float arg2; |
| 58 | 30 |
}; |
| 59 | 31 |
|
| 60 |
/** |
|
| 61 |
* Utility function to create a new RecordWaveMsg. |
|
| 62 |
*/ |
|
| 32 |
|
|
| 63 | 33 |
inline RecordWaveMsg makeRecordWaveMsg( Command cmd, std::size_t index, float arg1, float arg2 ) |
| 64 | 34 |
{
|
| 65 | 35 |
RecordWaveMsg msg; |
| ... | ... | |
| 71 | 41 |
return msg; |
| 72 | 42 |
} |
| 73 | 43 |
|
| 74 |
/** |
|
| 75 |
* Message sent from the audio thread to the graphic thread when a new grain is triggered in the granular synthesizer. |
|
| 76 |
* This creates a new cursor that travels from the beginning to the end of the selection to graphically represent the evolution of the grain in time. |
|
| 77 |
* |
|
| 78 |
*/ |
|
| 44 |
|
|
| 79 | 45 |
struct CursorTriggerMsg |
| 80 | 46 |
{
|
| 81 |
Command cmd; // TRIGGER_UPDATE or TRIGGER_END
|
|
| 47 |
Command cmd; |
|
| 82 | 48 |
int synthID; |
| 83 | 49 |
}; |
| 84 | 50 |
|
| 85 |
/** |
|
| 86 |
* Utility function to create a new CursorTriggerMsg. |
|
| 87 |
*/ |
|
| 88 | 51 |
inline CursorTriggerMsg makeCursorTriggerMsg( Command cmd, std::uint8_t synthID ) |
| 89 | 52 |
{
|
| 90 | 53 |
CursorTriggerMsg msg; |
| ... | ... | |
| 95 | 58 |
return msg; |
| 96 | 59 |
} |
| 97 | 60 |
|
| 98 |
/** |
|
| 99 |
* Message sent from the graphic (main) thread to the audio thread to start a new voice of the granular synthesizer. |
|
| 100 |
*/ |
|
| 101 | 61 |
struct NoteMsg |
| 102 | 62 |
{
|
| 103 |
Command cmd; // NOTE_ON/OFF ot LOOP_ON/OFF
|
|
| 63 |
Command cmd; |
|
| 104 | 64 |
int midiNote; |
| 105 | 65 |
double rate; |
| 106 | 66 |
}; |
| 107 | 67 |
|
| 108 |
/** |
|
| 109 |
* Utility function to create a new NoteMsg. |
|
| 110 |
*/ |
|
| 111 | 68 |
inline NoteMsg makeNoteMsg( Command cmd, int midiNote, double rate ) |
| 112 | 69 |
{
|
| 113 | 70 |
NoteMsg msg; |
| ... | ... | |
| 117 | 74 |
msg.rate = rate; |
| 118 | 75 |
|
| 119 | 76 |
return msg; |
| 120 |
} |
|
| 77 |
} |
|
| CollidoscopeApp/include/Oscilloscope.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
#include "cinder/gl/gl.h" |
| 25 | 4 |
|
| 26 | 5 |
#include "DrawInfo.h" |
| 27 | 6 |
|
| 28 |
|
|
| 29 |
|
|
| 30 |
/** |
|
| 31 |
* The oscilloscope that oscillates when Collidoscope is played |
|
| 32 |
*/ |
|
| 33 | 7 |
class Oscilloscope |
| 34 | 8 |
{
|
| 35 | 9 |
|
| 36 | 10 |
public: |
| 37 | 11 |
|
| 38 |
/** |
|
| 39 |
* Constructor, accepts as argument the number of points that make up the oscilloscope line |
|
| 40 |
*/ |
|
| 41 | 12 |
Oscilloscope( size_t numPoints ): |
| 42 | 13 |
mNumPoints( numPoints ), |
| 43 | 14 |
mLine( std::vector<ci::vec2>( numPoints, ci::vec2() ) ) |
| 44 | 15 |
{}
|
| 45 | 16 |
|
| 46 |
/** |
|
| 47 |
* Sets the value of a point of the oscilloscope. The value is passed in audio coordinates [-1.0, 1.0]. |
|
| 48 |
* A reference to DrawInfo is passed to calculate the graphic coordinate of the point based on the audio values passed. |
|
| 49 |
*/ |
|
| 50 | 17 |
void setPoint( int index, float audioVal, const DrawInfo &di ){
|
| 51 | 18 |
|
| 52 | 19 |
if ( audioVal > 1.0f ){
|
| ... | ... | |
| 57 | 24 |
} |
| 58 | 25 |
|
| 59 | 26 |
audioVal *= 0.8f; |
| 60 |
// map audio val from [-1.0, 1.0] to [0.0, 1.0]
|
|
| 61 |
// then map the value obtained to the height of the wave tier ( window height / NUM_WAVES )
|
|
| 27 |
// this yRatio is for the bottom scope, the top will be drawn with a translation/4
|
|
| 28 |
// because it's half of the half of the tier where the wave is drawn
|
|
| 62 | 29 |
float yRatio = ((1 + audioVal) / 2.0f) * (di.getWindowHeight() / NUM_WAVES ); |
| 63 | 30 |
float xRatio = index * (di.getWindowWidth() / (float)mLine.size()); |
| 64 | 31 |
|
| 65 |
// this flips the coordinates for the second wave |
|
| 66 | 32 |
mLine.getPoints()[index].x = float( di.flipX( int(xRatio) ) ); |
| 67 | 33 |
mLine.getPoints()[index].y = float( di.flipY( int(yRatio) ) ); |
| 68 | 34 |
|
| 69 |
// add the missing line to reach the right of the window.
|
|
| 70 |
// Indeed, the scope starts from 0 to size-1 and adds xRatio
|
|
| 71 |
// to each new point. The line from n-1 to n is therefore missing.
|
|
| 35 |
// add the missing line to reach the right of the window |
|
| 36 |
// indeed the scope starts from 0 to size -1 and adds xRatio
|
|
| 37 |
// to each new point to the line from n-1 to n is missing
|
|
| 72 | 38 |
if (index == mNumPoints - 1){
|
| 73 | 39 |
xRatio += ( di.getWindowWidth() / mNumPoints ); |
| 74 | 40 |
xRatio = ceil( xRatio ); // ceil because the division might left one pixel out |
| ... | ... | |
| 79 | 45 |
|
| 80 | 46 |
} |
| 81 | 47 |
|
| 82 |
/** |
|
| 83 |
* Draws this oscilloscope as a cinder::PolyLine2f |
|
| 84 |
*/ |
|
| 85 | 48 |
void draw() |
| 86 | 49 |
{
|
| 87 | 50 |
ci::gl::color(1.0f, 1.0f, 1.0f); |
| CollidoscopeApp/include/PGranular.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2002 James McCartney. |
|
| 4 |
Copyright (C) 2016 Queen Mary University of London |
|
| 5 |
Author: Fiore Martin, based on Supercollider's (http://supercollider.github.io) TGrains code and Ross Bencina's "Implementing Real-Time Granular Synthesis" |
|
| 6 |
|
|
| 7 |
This file is part of Collidoscope. |
|
| 8 |
|
|
| 9 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 10 |
it under the terms of the GNU General Public License as published by |
|
| 11 |
the Free Software Foundation, either version 3 of the License, or |
|
| 12 |
(at your option) any later version. |
|
| 13 |
|
|
| 14 |
This program is distributed in the hope that it will be useful, |
|
| 15 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 16 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 17 |
GNU General Public License for more details. |
|
| 18 |
|
|
| 19 |
You should have received a copy of the GNU General Public License |
|
| 20 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 21 |
*/ |
|
| 22 |
|
|
| 23 | 1 |
#pragma once |
| 24 | 2 |
|
| 25 | 3 |
#include <array> |
| ... | ... | |
| 32 | 10 |
|
| 33 | 11 |
using std::size_t; |
| 34 | 12 |
|
| 35 |
/** |
|
| 36 |
* The very core of the Collidoscope audio engine: the granular synthesizer. |
|
| 37 |
* Based on SuperCollider's TGrains and Ross Bencina's "Implementing Real-Time Granular Synthesis" |
|
| 38 |
* |
|
| 39 |
* It implements Collidoscope's selection-based approach to granular synthesis. |
|
| 40 |
* A grain is basically a selection of a recorded sample of audio. |
|
| 41 |
* Grains are played in a loop: they are re-triggered each time they reach the end of the selection. |
|
| 42 |
* However, if the duration coefficient is greater than one, a new grain is re-triggered before the previous one is done, |
|
| 43 |
* the grains start to overlap with each other and create the typical eerie sound of grnular synthesis. |
|
| 44 |
* Also every time a new grain is triggered, it is offset of a few samples from the initial position to make the timbre more interesting. |
|
| 45 |
* |
|
| 46 |
* |
|
| 47 |
* PGranular uses a linear ASR envelope with 10 milliseconds attack and 50 milliseconds release. |
|
| 48 |
* |
|
| 49 |
* Note that PGranular is header based and only depends on std library and on "EnvASR.h" (also header based). |
|
| 50 |
* This means you can embedd it in two your project just by copying these two files over. |
|
| 51 |
* |
|
| 52 |
* Template arguments: |
|
| 53 |
* T: type of the audio samples (normally float or double) |
|
| 54 |
* RandOffsetFunc: type of the callable passed as argument to the contructor |
|
| 55 |
* TriggerCallbackFunc: type of the callable passed as argument to the contructor |
|
| 56 |
* |
|
| 57 |
*/ |
|
| 58 | 13 |
template <typename T, typename RandOffsetFunc, typename TriggerCallbackFunc> |
| 59 | 14 |
class PGranular |
| 60 | 15 |
{
|
| ... | ... | |
| 69 | 24 |
return static_cast<T> ((1 - decimal) * xn + decimal * xn_1); |
| 70 | 25 |
} |
| 71 | 26 |
|
| 72 |
/** |
|
| 73 |
* A single grain of the granular synthesis |
|
| 74 |
*/ |
|
| 75 | 27 |
struct PGrain |
| 76 | 28 |
{
|
| 77 | 29 |
double phase; // read pointer to mBuffer of this grain |
| 78 | 30 |
double rate; // rate of the grain. e.g. rate = 2 the grain will play twice as fast |
| 79 |
bool alive; // whether this grain is alive. Not alive means it has been processed and can be replaced by another grain |
|
| 31 |
bool alive; // whether this grain is alive. Not alive means it has been processed and can be replanced by another grain
|
|
| 80 | 32 |
size_t age; // age of this grain in samples |
| 81 | 33 |
size_t duration; // duration of this grain in samples. minimum = 4 |
| 82 | 34 |
|
| 83 |
double b1; // hann envelope from Ross Becina's "Implementing real time Granular Synthesis"
|
|
| 35 |
double b1; // hann envelope from Ross Becina "Implementing real time Granular Synthesis" |
|
| 84 | 36 |
double y1; |
| 85 | 37 |
double y2; |
| 86 | 38 |
}; |
| 87 | 39 |
|
| 88 | 40 |
|
| 89 | 41 |
|
| 90 |
/** |
|
| 91 |
* Constructor. |
|
| 92 |
* |
|
| 93 |
* \param buffer a pointer to an array of T that contains the original sample that will be granulized |
|
| 94 |
* \param bufferLen length of buffer in samples |
|
| 95 |
* \rand function of type size_t ()(void) that is called back each time a new grain is generated. The returned value is used |
|
| 96 |
* to offset the starting sample of the grain. This adds more colour to the sound especially with small selections. |
|
| 97 |
* \triggerCallback function of type void ()(char, int) that is called back each time a new grain is generated. |
|
| 98 |
* The function is passed the character 't' as first parameter when a new grain is triggered and the characted 'e' when the synth becomes idle (no sound). |
|
| 99 |
* \ID id of this PGrain. Passed to the triggerCallback function as second parameter to identify this PGranular as the caller. |
|
| 100 |
*/ |
|
| 101 | 42 |
PGranular( const T* buffer, size_t bufferLen, size_t sampleRate, RandOffsetFunc & rand, TriggerCallbackFunc & triggerCallback, int ID ) : |
| 102 | 43 |
mBuffer( buffer ), |
| 103 | 44 |
mBufferLen( bufferLen ), |
| ... | ... | |
| 130 | 71 |
|
| 131 | 72 |
~PGranular(){}
|
| 132 | 73 |
|
| 133 |
/** Sets multiplier of duration of grains in seconds */
|
|
| 74 |
/* sets multiplier of duration of grains in seconds */
|
|
| 134 | 75 |
void setGrainsDurationCoeff( double coeff ) |
| 135 | 76 |
{
|
| 136 | 77 |
mGrainsDurationCoeff = coeff; |
| 137 | 78 |
|
| 138 |
mGrainsDuration = std::lround( mTriggerRate * coeff ); |
|
| 79 |
mGrainsDuration = std::lround( mTriggerRate * coeff ); // FIXME check if right rounding
|
|
| 139 | 80 |
|
| 140 | 81 |
if ( mGrainsDuration < kMinGrainsDuration ) |
| 141 | 82 |
mGrainsDuration = kMinGrainsDuration; |
| 142 | 83 |
} |
| 143 | 84 |
|
| 144 |
/** Sets rate of grains. e.g rate = 2 means one octave higer */
|
|
| 85 |
/* sets rate of grains. e.g rate = 2 means one octave higer */
|
|
| 145 | 86 |
void setGrainsRate( double rate ) |
| 146 | 87 |
{
|
| 147 | 88 |
mGrainsRate = rate; |
| 148 | 89 |
} |
| 149 | 90 |
|
| 150 |
/** sets the selection start in samples */
|
|
| 91 |
// sets trigger rate in samples
|
|
| 151 | 92 |
void setSelectionStart( size_t start ) |
| 152 | 93 |
{
|
| 153 | 94 |
mGrainsStart = start; |
| 154 | 95 |
} |
| 155 | 96 |
|
| 156 |
/** Sets the selection size ( and therefore the trigger rate) in samples */ |
|
| 157 | 97 |
void setSelectionSize( size_t size ) |
| 158 | 98 |
{
|
| 159 | 99 |
|
| ... | ... | |
| 167 | 107 |
|
| 168 | 108 |
} |
| 169 | 109 |
|
| 170 |
/** Sets the attenuation of the grains with respect to the level of the recorded sample |
|
| 171 |
* attenuation is in amp value and defaule value is 0.25118864315096 (-12dB) */ |
|
| 172 | 110 |
void setAttenuation( T attenuation ) |
| 173 | 111 |
{
|
| 174 | 112 |
mAttenuation = attenuation; |
| 175 | 113 |
} |
| 176 | 114 |
|
| 177 |
/** Starts the synthesis engine */ |
|
| 178 | 115 |
void noteOn( double rate ) |
| 179 | 116 |
{
|
| 180 | 117 |
if ( mEnvASR.getState() == EnvASR<T>::State::eIdle ){
|
| ... | ... | |
| 188 | 125 |
} |
| 189 | 126 |
} |
| 190 | 127 |
|
| 191 |
/** Stops the synthesis engine */ |
|
| 192 | 128 |
void noteOff() |
| 193 | 129 |
{
|
| 194 | 130 |
if ( mEnvASR.getState() != EnvASR<T>::State::eIdle ){
|
| ... | ... | |
| 196 | 132 |
} |
| 197 | 133 |
} |
| 198 | 134 |
|
| 199 |
/** Whether the synthesis engine is active or not. After noteOff is called the synth stays active until the envelope decays to 0 */ |
|
| 200 | 135 |
bool isIdle() |
| 201 | 136 |
{
|
| 202 | 137 |
return mEnvASR.getState() == EnvASR<T>::State::eIdle; |
| 203 | 138 |
} |
| 204 | 139 |
|
| 205 |
/** |
|
| 206 |
* Runs the granular engine and stores the output in \a audioOut |
|
| 207 |
* |
|
| 208 |
* \param pointer to an array of T. This will be filled with the output of PGranular. It needs to be at least \a numSamples long |
|
| 209 |
* \param tempBuffer a temporary buffer used to store the envelope value. It needs to be at least \a numSamples long |
|
| 210 |
* \param numSamples number of samples to be processed |
|
| 211 |
*/ |
|
| 212 | 140 |
void process( T* audioOut, T* tempBuffer, size_t numSamples ) |
| 213 | 141 |
{
|
| 214 | 142 |
|
| ... | ... | |
| 216 | 144 |
size_t envSamples = 0; |
| 217 | 145 |
bool becameIdle = false; |
| 218 | 146 |
|
| 219 |
// process the envelope first and store it in the tempBuffer
|
|
| 147 |
// do the envelope first and store it in the tempBuffer
|
|
| 220 | 148 |
for ( size_t i = 0; i < numSamples; i++ ){
|
| 221 | 149 |
tempBuffer[i] = mEnvASR.tick(); |
| 222 | 150 |
envSamples++; |
| ... | ... | |
| 228 | 156 |
} |
| 229 | 157 |
} |
| 230 | 158 |
|
| 231 |
// does the actual grains processing |
|
| 232 | 159 |
processGrains( audioOut, tempBuffer, envSamples ); |
| 233 | 160 |
|
| 234 |
// becomes idle if the envelope goes to idle state |
|
| 235 | 161 |
if ( becameIdle ){
|
| 236 | 162 |
mTriggerCallback( 'e', mID ); |
| 237 | 163 |
reset(); |
| ... | ... | |
| 248 | 174 |
synthesizeGrain( mGrains[grainIdx], audioOut, envelopeValues, numSamples ); |
| 249 | 175 |
|
| 250 | 176 |
if ( !mGrains[grainIdx].alive ){
|
| 251 |
// this grain is dead so copy the last of the active grains here |
|
| 177 |
// this grain is dead so copyu the last of the active grains here
|
|
| 252 | 178 |
// so as to keep all active grains at the beginning of the array |
| 253 | 179 |
// don't increment grainIdx so the last active grain is processed next cycle |
| 254 | 180 |
// if this grain is the last active grain then mNumAliveGrains is decremented |
| ... | ... | |
| 317 | 243 |
} |
| 318 | 244 |
} |
| 319 | 245 |
|
| 320 |
// synthesize a single grain |
|
| 321 | 246 |
// audioOut = pointer to audio block to fill |
| 322 |
// numSamples = number of samples to process for this block |
|
| 247 |
// numSamples = numpber of samples to process for this block
|
|
| 323 | 248 |
void synthesizeGrain( PGrain &grain, T* audioOut, T* envelopeValues, size_t numSamples ) |
| 324 | 249 |
{
|
| 325 | 250 |
|
| 326 |
// copy all grain data into local variable for faster processing
|
|
| 251 |
// copy all grain data into local variable for faster porcessing
|
|
| 327 | 252 |
const auto rate = grain.rate; |
| 328 | 253 |
auto phase = grain.phase; |
| 329 | 254 |
auto age = grain.age; |
| ... | ... | |
| 365 | 290 |
} |
| 366 | 291 |
|
| 367 | 292 |
if ( age == duration ){
|
| 368 |
// if it processed all the samples left to leave ( numSamplesToOut = duration-age) |
|
| 369 |
// then the grain is finished |
|
| 293 |
// if it porocessed all the samples left to leave ( numSamplesToOut = duration-age)
|
|
| 294 |
// then the grain is had finished
|
|
| 370 | 295 |
grain.alive = false; |
| 371 | 296 |
} |
| 372 | 297 |
else{
|
| ... | ... | |
| 399 | 324 |
// length of mBuffer in samples |
| 400 | 325 |
const size_t mBufferLen; |
| 401 | 326 |
|
| 402 |
// offset in the buffer where the grains start. a.k.a. selection start
|
|
| 327 |
// offset in the buffer where the grains start. a.k.a. seleciton start
|
|
| 403 | 328 |
size_t mGrainsStart; |
| 404 | 329 |
|
| 405 |
// attenuates signal prevents clipping of grains (to some degree)
|
|
| 330 |
// attenuates signal prevents clipping of grains |
|
| 406 | 331 |
T mAttenuation; |
| 407 | 332 |
|
| 408 | 333 |
// grain duration in samples |
| 409 | 334 |
double mGrainsDurationCoeff; |
| 410 |
// duration of grains is selection size * duration coeff |
|
| 335 |
// duration of grains is selcection size * duration coeff
|
|
| 411 | 336 |
size_t mGrainsDuration; |
| 412 | 337 |
// rate of grain, affects pitch |
| 413 | 338 |
double mGrainsRate; |
| CollidoscopeApp/include/PGranularNode.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2016 Queen Mary University of London |
|
| 4 |
Author: Fiore Martin |
|
| 5 |
|
|
| 6 |
This file is part of Collidoscope. |
|
| 7 |
|
|
| 8 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 9 |
it under the terms of the GNU General Public License as published by |
|
| 10 |
the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
(at your option) any later version. |
|
| 12 |
|
|
| 13 |
This program is distributed in the hope that it will be useful, |
|
| 14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
GNU General Public License for more details. |
|
| 17 |
|
|
| 18 |
You should have received a copy of the GNU General Public License |
|
| 19 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 20 |
*/ |
|
| 21 |
|
|
| 22 | 1 |
#pragma once |
| 23 | 2 |
|
| 24 | 3 |
#include "cinder/Cinder.h" |
| ... | ... | |
| 40 | 19 |
struct RandomGenerator; |
| 41 | 20 |
|
| 42 | 21 |
/* |
| 43 |
A node in the Cinder audio graph that holds PGranulars for loop and keyboard playing
|
|
| 22 |
A node in the Cinder audio graph that holds a PGranular
|
|
| 44 | 23 |
*/ |
| 45 | 24 |
class PGranularNode : public ci::audio::Node |
| 46 | 25 |
{
|
| ... | ... | |
| 51 | 30 |
explicit PGranularNode( ci::audio::Buffer *grainBuffer, CursorTriggerMsgRingBuffer &triggerRingBuffer ); |
| 52 | 31 |
~PGranularNode(); |
| 53 | 32 |
|
| 54 |
/** Set selection size in samples */
|
|
| 33 |
// set selection size in samples
|
|
| 55 | 34 |
void setSelectionSize( size_t size ) |
| 56 | 35 |
{
|
| 57 | 36 |
mSelectionSize.set( size ); |
| 58 | 37 |
} |
| 59 | 38 |
|
| 60 |
/** Set selection start in samples */ |
|
| 61 | 39 |
void setSelectionStart( size_t start ) |
| 62 | 40 |
{
|
| 63 | 41 |
mSelectionStart.set( start ); |
| ... | ... | |
| 68 | 46 |
mGrainDurationCoeff.set( coeff ); |
| 69 | 47 |
} |
| 70 | 48 |
|
| 71 |
/* PGranularNode passes itself as trigger callback in PGranular */
|
|
| 49 |
// used for trigger callback in PGRanular
|
|
| 72 | 50 |
void operator()( char msgType, int ID ); |
| 73 | 51 |
|
| 74 | 52 |
ci::audio::dsp::RingBufferT<NoteMsg>& getNoteRingBuffer() { return mNoteMsgRingBufferPack.getBuffer(); }
|
| 75 | 53 |
|
| 76 | 54 |
protected: |
| 77 | 55 |
|
| 78 |
void initialize() override;
|
|
| 56 |
void initialize() override;
|
|
| 79 | 57 |
|
| 80 |
void process( ci::audio::Buffer *buffer ) override;
|
|
| 58 |
void process( ci::audio::Buffer *buffer ) override;
|
|
| 81 | 59 |
|
| 82 | 60 |
private: |
| 83 | 61 |
|
| 84 |
// Wraps a std::atomic but get() returns a boost::optional that is set to a real value only when the atomic has changed. |
|
| 85 |
// It is used to avoid calling PGranular setter methods with the same value at each audio callback. |
|
| 86 | 62 |
template< typename T> |
| 87 | 63 |
class LazyAtomic |
| 88 | 64 |
{
|
| ... | ... | |
| 114 | 90 |
T mPreviousVal; |
| 115 | 91 |
}; |
| 116 | 92 |
|
| 117 |
// creates or re-start a PGranular and sets the pitch according to the MIDI note passed as argument |
|
| 118 | 93 |
void handleNoteMsg( const NoteMsg &msg ); |
| 119 | 94 |
|
| 120 |
// pointers to PGranular objects
|
|
| 95 |
// pointer to PGranular object
|
|
| 121 | 96 |
std::unique_ptr < collidoscope::PGranular<float, RandomGenerator, PGranularNode > > mPGranularLoop; |
| 122 | 97 |
std::array<std::unique_ptr < collidoscope::PGranular<float, RandomGenerator, PGranularNode > >, kMaxVoices> mPGranularNotes; |
| 123 |
// maps midi notes to pgranulars. When a noteOff is received makes sure the right PGranular is turned off |
|
| 124 | 98 |
std::array<int, kMaxVoices> mMidiNotes; |
| 125 | 99 |
|
| 126 | 100 |
// pointer to the random generator struct passed over to PGranular |
| 127 | 101 |
std::unique_ptr< RandomGenerator > mRandomOffset; |
| 128 | 102 |
|
| 129 |
// buffer containing the recorded audio, to pass to PGranular in initialize()
|
|
| 103 |
/* buffer containing the recorder audio, to pass to PGranular in initialize() */
|
|
| 130 | 104 |
ci::audio::Buffer *mGrainBuffer; |
| 131 | 105 |
|
| 132 | 106 |
ci::audio::BufferRef mTempBuffer; |
| CollidoscopeApp/include/ParticleController.h | ||
|---|---|---|
| 1 |
/* |
|
| 2 |
|
|
| 3 |
Copyright (C) 2015 Fiore Martin |
|
| 4 |
Copyright (C) 2016 Queen Mary University of London |
|
| 5 |
Author: Fiore Martin |
|
| 6 |
|
|
| 7 |
This file is part of Collidoscope. |
|
| 8 |
|
|
| 9 |
Collidoscope is free software: you can redistribute it and/or modify |
|
| 10 |
it under the terms of the GNU General Public License as published by |
|
| 11 |
the Free Software Foundation, either version 3 of the License, or |
|
| 12 |
(at your option) any later version. |
|
| 13 |
|
|
| 14 |
This program is distributed in the hope that it will be useful, |
|
| 15 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 16 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 17 |
GNU General Public License for more details. |
|
| 18 |
|
|
| 19 |
You should have received a copy of the GNU General Public License |
|
| 20 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
| 21 |
|
|
| 22 |
*/ |
|
| 23 |
|
|
| 24 | 1 |
#pragma once |
| 25 | 2 |
|
| 26 | 3 |
#include "cinder/gl/gl.h" |
| 27 | 4 |
#include <vector> |
| 28 | 5 |
|
| 29 |
/** |
|
| 30 |
* The ParticleController creates/updates/draws and destroys particles |
|
| 31 |
*/ |
|
| 6 |
|
|
| 32 | 7 |
class ParticleController {
|
| 33 | 8 |
|
| 34 | 9 |
struct Particle {
|
| 35 | 10 |
|
| 36 |
ci::vec2 mCloudCenter; // initial positin of the particle |
|
| 37 |
ci::vec2 mVel; // velocity |
|
| 38 |
float mCloudSize; // how big is the area where particle float around. When a particle hits the |
|
| 39 |
// border of the area it gets deflected |
|
| 11 |
ci::vec2 mCloudCenter; |
|
| 12 |
ci::vec2 mVel; |
|
| 13 |
float mCloudSize; |
|
| 40 | 14 |
|
| 41 |
int mAge; // when mAge == mLifeSpan the particle is disposed
|
|
| 42 |
int mLifespan; // how long a particle lives
|
|
| 43 |
bool mFlyOver; // some particles last longer and fly over the screen and reach the other user
|
|
| 15 |
int mAge; |
|
| 16 |
int mLifespan; |
|
| 17 |
bool mFlyOver; |
|
| 44 | 18 |
|
| 45 | 19 |
}; |
| 46 | 20 |
|
| ... | ... | |
| 49 | 23 |
std::vector<Particle> mParticles; |
| 50 | 24 |
std::vector< ci::vec2 > mParticlePositions; |
| 51 | 25 |
|
| 52 |
// current number of active particles |
|
| 53 | 26 |
size_t mNumParticles; |
| 54 | 27 |
|
| 55 |
ci::gl::VboRef mParticleVbo; // virtual buffer object
|
|
| 28 |
ci::gl::VboRef mParticleVbo; |
|
| 56 | 29 |
ci::gl::BatchRef mParticleBatch; |
| 57 | 30 |
|
| 58 | 31 |
public: |
| 59 |
/** |
|
| 60 |
* Every time addParticles is run, up to kMaxParticleAdd are added at once |
|
| 61 |
*/ |
|
| 62 | 32 |
static const int kMaxParticleAdd = 22; |
| 63 | 33 |
|
| 64 | 34 |
ParticleController(); |
| 65 |
|
|
| 66 |
/** |
|
| 67 |
* Adds \a amount particles and places them in \a initialLocation. |
|
| 68 |
* \cloudSize determines how far the particles can go |
|
| 69 |
*/ |
|
| 70 | 35 |
void addParticles(int amount, const ci::vec2 &initialLocation, const float cloudSize); |
| 71 | 36 |
|
| 72 |
/** |
|
| 73 |
* Updates position and age of the particles |
|
| 74 |
*/ |
|
| 75 | 37 |
void updateParticles(); |
| 76 | 38 |
|
| 77 |
/** |
|
| 78 |
* Draws all the particles |
|
| 79 |
*/ |
|
| 80 | 39 |
inline void draw() |
Also available in: Unified diff