Revision 3:7fb593d53361 CollidoscopeApp

View differences:

CollidoscopeApp/include/DrawInfo.h
2 2

  
3 3
#include "cinder/Area.h"
4 4

  
5
/**
6
 * The DrawInfo class holds size information for drawing the waves in the screen. 
7
 * Every time the screen is resized the draw info is updated with the new information about the window size.
8
 *
9
 * Every wave has its own drawInfo.
10
 *
11
 */ 
5 12
class DrawInfo
6 13
{
7 14
public:
8 15

  
16
    /**
17
     * Constructor. Takes the index of the wave as argument.
18
     */ 
9 19
    DrawInfo( size_t waveIndex ):
10 20
        mWaveIndex( waveIndex ),
11 21
        mWindowWidth(0),
......
14 24
        mShrinkFactor(1)
15 25
    {}
16 26

  
27
    /**
28
     * Reset this DrawInfo using the new bounding area for the wave.  \a shrinkFactor 
29
     * 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.
30
     */ 
17 31
    void reset( const ci::Area &bounds, float shrinkFactor )
18 32
    {
19 33
        mWindowWidth = bounds.getWidth();
......
22 36
        mShrinkFactor = shrinkFactor;
23 37
    }
24 38

  
39
    /**
40
     * Maps a value in the audio space [-1.0, 1.0] to a position on the y axis of this DrawInf's bounding area.
41
     *
42
     */ 
25 43
	float audioToHeigt(float audioSample) const {
26 44
        /* clip into range [-1.1] */
27 45
        if (audioSample < -1.0f) {
......
48 66
        return mSelectionBarHeight;
49 67
    }
50 68

  
69
    /**
70
     * Returns the center position on the y axis of this DrawInfo's the bounding area. 
71
     */ 
51 72
    int32_t getWaveCenterY() const
52 73
    {
53 74
        if ( mWaveIndex == 0 )
......
56 77
            return mWindowHeight / (NUM_WAVES * 2);
57 78
    }
58 79

  
80
    /**
81
     * Flips y according to the index of the wave. It is needed because the second wave in collidoscope is upside down from the orientation oftthe screen.
82
     */ 
59 83
	int flipY(int y) const 
60 84
    {
61 85
        if ( mWaveIndex == 0)
62
		    return mWindowHeight - y /*+ 24*/;
86
		    return mWindowHeight - y;
63 87
        else
64
            return y /*- 24*/;
88
            return y;
65 89
	}
66 90

  
91
    /**
92
     * Returns x. not used at he moment.
93
     *
94
     */ 
67 95
	int flipX(int x) const
68 96
    {
69 97
        return x;
......
86 114
        return mWindowHeight;
87 115
    }
88 116

  
117
    /**
118
     * Draw infos cannot be copied and should be passed as const reference.
119
     */ 
89 120
    DrawInfo( const DrawInfo &original ) = delete;
90 121
    DrawInfo & operator=( const DrawInfo &original ) = delete;
91 122

  
CollidoscopeApp/include/EnvASR.h
17 17
{
18 18
public:
19 19

  
20
    /** Possible states of the envelope. Idle means the envelope ouputs 0 */
20 21
    enum class State {
21 22
        eAttack,
22 23
        eSustain,
......
40 41
        mReleaseRate = T( 1.0 ) / (releaseTime * sampleRate);
41 42
    }
42 43

  
44
    /** Produces one sample worth of envelope */
43 45
    T tick()
44 46
    {
45 47

  
CollidoscopeApp/include/Log.h
1 1
#pragma once 
2 2

  
3 3

  
4

  
4
/**
5
 * Utility function to log errors using the cinder::log library.
6
 * Errors are logged to collidoscope_error.log file. 
7
 *
8
 */ 
5 9
void logError( const std::string &errorMsg );
6 10

  
7 11

  
8
void logInfo( const std::string &infoMsg );
12
/**
13
 * Utility function to log info using the cinder::log library.
14
 * Errors are logged to the terminal. Used only for debugging.
15
 *
16
 */ 
17
void logInfo( const std::string &infoMsg );
CollidoscopeApp/include/MIDI.h
29 29
    std::string mMessage;
30 30
};
31 31

  
32
/**
33
 * A MIDI message 
34
 */ 
32 35
class MIDIMessage
33 36
{
34 37
    friend class MIDI;
......
40 43

  
41 44
    unsigned char getChannel() { return mChannel; }
42 45

  
46
    /**
47
     * First byte of MIDI data 
48
     */ 
43 49
    unsigned char getData_1() { return mData1; }
44 50

  
51
    /**
52
     * Second byte of MIDI data 
53
     */ 
45 54
    unsigned char getData_2() { return mData2; }
46 55

  
47 56
private:
......
54 63
    
55 64
};
56 65

  
57

  
66
/**
67
 * Handles MIDI messages from the keyboards and Teensy. It uses RtMidi library.
68
 *
69
 */ 
58 70
class MIDI
59 71
{
60 72

  
......
65 77

  
66 78
    void setup( const Config& );
67 79

  
80
    /**
81
     * Check new incoming messages and stores them into the vector passed as argument by reference.
82
     */ 
68 83
    void checkMessages( std::vector< MIDIMessage >&  );
69 84

  
70 85
private:
71 86

  
87
    // callback passed to RtMidi library 
72 88
    static void RtMidiInCallback( double deltatime, std::vector<unsigned char> *message, void *userData );
73 89

  
90
    // parse RtMidi messages and turns them into more readable collidoscope::MIDIMessages
74 91
    MIDIMessage parseRtMidiMessage( std::vector<unsigned char> *message );
75 92

  
76
    // messages to pass to checkMessages caller
93
    // messages to pass to checkMessages caller 
77 94
    std::vector< MIDIMessage > mMIDIMessages;
95
    // use specific variables for pitch bend messages. Pitch bend messages are coming 
96
    // from the strip sensors that are very jerky and send a lot of values. So instead 
97
    // of saving all the messages in mMIDIMessages just save the last received in mPitchBendMessages 
98
    // and optimize away redundant messages.
78 99
    std::array< MIDIMessage, NUM_WAVES > mPitchBendMessages;
100
    // Same principle of pitch bend messages 
79 101
    std::array< MIDIMessage, NUM_WAVES > mFilterMessages;
80 102

  
81

  
82

  
103
    // vecotr containing all the MIDI input devices detected.
83 104
    std::vector< std::unique_ptr <RtMidiIn> > mInputs;
105
    // Used for mutual access to the MIDI messages by the MIDI thread and the graphic thread.  
84 106
    std::mutex mMutex;
85 107
};
86 108

  
CollidoscopeApp/include/Messages.h
1 1
#pragma once
2 2

  
3

  
3
/**
4
 * Enumeration of all the possible commands exchanged between audio thread and graphic thread.
5
 *
6
 */ 
4 7
enum class Command {
5 8
    // message carrying info about one chunk of recorder audio. 
6 9
    WAVE_CHUNK,
......
17 20
    LOOP_OFF
18 21
};
19 22

  
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
*/
23
/** Message sent from the audio thread to the graphic wave when a new wave is recorded. 
24
 *  
25
 *  The graphic thread set the chunks of the wave to reflect the level of the recorded audio. 
26
 *  The algorithm takes the maximum and minimum value of a group of samples and this becomes the top and bottom of the samples.
27
 *  It contains the inde
28
 *  the cursor position when the grains are reset.
29
 */
24 30
struct RecordWaveMsg
25 31
{
26
    Command cmd;
32
    Command cmd; // WAVE_CHUNK or WAVE_START
27 33
    std::size_t index;
28 34
    float arg1;
29 35
    float arg2;
30 36
};
31 37

  
32

  
38
/**
39
 * Utility function to create a new RecordWaveMsg.
40
 */ 
33 41
inline RecordWaveMsg makeRecordWaveMsg( Command cmd, std::size_t index, float arg1, float arg2 )
34 42
{
35 43
    RecordWaveMsg msg;
......
41 49
    return msg;
42 50
}
43 51

  
44

  
52
/**
53
 * Message sent from the audio thread to the graphic thread when a new grain is triggered in the granular synthesizer. 
54
 * 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. 
55
 *
56
 */ 
45 57
struct CursorTriggerMsg
46 58
{
47
    Command cmd;
59
    Command cmd; // TRIGGER_UPDATE or TRIGGER_END
48 60
    int synthID;
49 61
};
50 62

  
63
/**
64
 * Utility function to create a new CursorTriggerMsg.
65
 */ 
51 66
inline CursorTriggerMsg makeCursorTriggerMsg( Command cmd, std::uint8_t synthID )
52 67
{
53 68
    CursorTriggerMsg msg;
......
58 73
    return msg;
59 74
}
60 75

  
76
/**
77
 * Message sent from the graphic (main) thread to the audio thread to start a new voice of the granular synthesizer.
78
 */ 
61 79
struct NoteMsg
62 80
{
63
    Command cmd;
81
    Command cmd; // NOTE_ON/OFF ot LOOP_ON/OFF 
64 82
    int midiNote;
65 83
    double rate;
66 84
};
67 85

  
86
/**
87
 * Utility function to create a new NoteMsg.
88
 */ 
68 89
inline NoteMsg makeNoteMsg( Command cmd, int midiNote, double rate )
69 90
{
70 91
    NoteMsg msg;
......
74 95
    msg.rate = rate;
75 96

  
76 97
    return msg;
77
}
98
}
CollidoscopeApp/include/PGranular.h
10 10

  
11 11
using std::size_t;
12 12

  
13
/**
14
 * The very core of the Collidoscope audio engine: the granular synthesizer.
15
 * Based on SuperCollider's TGrains and Ross Becina's "Implementing Real-Time Granular Synthesis" 
16
 *
17
 * It implements Collidoscope's selection-based approach to granular synthesis. 
18
 * A grain is basically a selection of a recorded sample of audio. 
19
 * Grains are played in a loop: they are retriggered each time they reach the end of the selection.
20
 * However, if the duration coefficient is greater than one, a new grain is re-triggered before the previous one is done. 
21
 * The grains start to overlap with each other and create the typical eerie sound of grnular synthesis.
22
 * 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.
23
 *
24
 *
25
 * PGranular uses a linear ASR envelope with 10 milliseconds attack and 50 milliseconds release.
26
 *
27
 * Note that PGranular is header based and only depends on std library and on "EnvASR.h" (also header based).
28
 * This means you can embedd it in two your project just by copying these two files over.
29
 *
30
 * Template arguments: 
31
 * T: type of the audio samples (normally float or double) 
32
 * RandOffsetFunc: type of the callable passed as argument to the contructor
33
 * TriggerCallbackFunc: type of the callable passed as argument to the contructor
34
 *
35
 */ 
13 36
template <typename T, typename RandOffsetFunc, typename TriggerCallbackFunc>
14 37
class PGranular
15 38
{
......
24 47
        return static_cast<T> ((1 - decimal) * xn + decimal * xn_1);
25 48
    }
26 49

  
50
    /**
51
     * A single grain of the granular synthesis 
52
     */ 
27 53
    struct PGrain
28 54
    {
29 55
        double phase;    // read pointer to mBuffer of this grain 
......
32 58
        size_t age;      // age of this grain in samples 
33 59
        size_t duration; // duration of this grain in samples. minimum = 4
34 60

  
35
        double b1;       // hann envelope from Ross Becina "Implementing real time Granular Synthesis"
61
        double b1;       // hann envelope from Ross Becina's "Implementing real time Granular Synthesis"
36 62
        double y1;
37 63
        double y2;
38 64
    };
39 65

  
40 66

  
41 67

  
68
    /**
69
     * Constructor.
70
     *
71
     * \param buffer a pointer to an array of T that contains the original sample that will be granulized
72
     * \param bufferLen length of buffer in samples 
73
     * \rand function returning of type size_t ()(void) that is called back each time a new grain is generated. The returned value is used 
74
     * to offset the starting sample of the grain. This adds more colour to the sound especially with small selections. 
75
     * \triggerCallback function of type void ()(char, int) that is called back each time a new grain is triggered.
76
     *      The function is passed the character 't' as first parameter when a new grain is triggered and the characted 't' when the synths becomes idle.
77
     * \ID id of this PGrain is passed to the triggerCallback function as second parameter to identify this PGranular as the caller.
78
     */ 
42 79
    PGranular( const T* buffer, size_t bufferLen, size_t sampleRate, RandOffsetFunc & rand, TriggerCallbackFunc & triggerCallback, int ID ) :
43 80
        mBuffer( buffer ),
44 81
        mBufferLen( bufferLen ),
......
71 108

  
72 109
    ~PGranular(){}
73 110

  
74
    /* sets multiplier of duration of grains in seconds */
111
    /** Sets multiplier of duration of grains in seconds */
75 112
    void setGrainsDurationCoeff( double coeff )
76 113
    {
77 114
        mGrainsDurationCoeff = coeff;
78 115

  
79
        mGrainsDuration = std::lround( mTriggerRate * coeff ); // FIXME check if right rounding 
116
        mGrainsDuration = std::lround( mTriggerRate * coeff ); 
80 117

  
81 118
        if ( mGrainsDuration < kMinGrainsDuration )
82 119
            mGrainsDuration = kMinGrainsDuration;
83 120
    }
84 121

  
85
    /* sets rate of grains. e.g rate = 2 means one octave higer */
122
    /** Sets rate of grains. e.g rate = 2 means one octave higer */
86 123
    void setGrainsRate( double rate )
87 124
    {
88 125
        mGrainsRate = rate;
89 126
    }
90 127

  
91
    // sets trigger rate in samples 
128
    /** sets the selection start in samples */
92 129
    void setSelectionStart( size_t start )
93 130
    {
94 131
        mGrainsStart = start;
95 132
    }
96 133

  
134
    /** Sets the selection size ( and therefore the trigger rate) in samples */
97 135
    void setSelectionSize( size_t size )
98 136
    {
99 137

  
......
107 145

  
108 146
    }
109 147

  
148
    /** Sets the attenuation of the grains with respect to the level of the recorded sample
149
     *  attenuation is in amp value and defaule value is 0.25118864315096 (-12dB) */
110 150
    void setAttenuation( T attenuation )
111 151
    {
112 152
        mAttenuation = attenuation;
113 153
    }
114 154

  
155
    /** Starts the synthesis engine */
115 156
    void noteOn( double rate )
116 157
    {
117 158
        if ( mEnvASR.getState() == EnvASR<T>::State::eIdle ){
......
125 166
        }
126 167
    }
127 168

  
169
    /** Stops the synthesis engine */
128 170
    void noteOff()
129 171
    {
130 172
        if ( mEnvASR.getState() != EnvASR<T>::State::eIdle ){
......
132 174
        }
133 175
    }
134 176

  
177
    /** Whether the synthesis engine is active or not. After noteOff is called the synth stays active until the envelope decays to 0 */
135 178
    bool isIdle()
136 179
    {
137 180
        return mEnvASR.getState() == EnvASR<T>::State::eIdle;
138 181
    }
139 182

  
183
    /**
184
     * Runs the granular engine and stores the output in \a audioOut
185
     * 
186
     * \param pointer to an array of T. This will be filled with the output of PGranular. It needs to be at least \a numSamples lond
187
     * \param tempBuffer a temporary buffer used to store the envelope value. It needs to be at leas \a numSamples long
188
     * \param numSamples number of samples to be processed 
189
     */ 
140 190
    void process( T* audioOut, T* tempBuffer, size_t numSamples )
141 191
    {
142 192
        
......
144 194
        size_t envSamples = 0;
145 195
        bool becameIdle = false;
146 196

  
147
        // do the envelope first and store it in the tempBuffer 
197
        // process the envelope first and store it in the tempBuffer 
148 198
        for ( size_t i = 0; i < numSamples; i++ ){
149 199
            tempBuffer[i] = mEnvASR.tick();
150 200
            envSamples++;
......
156 206
            }
157 207
        }
158 208

  
209
        // does the actual grains processing 
159 210
        processGrains( audioOut, tempBuffer, envSamples );
160 211

  
212
        // becomes idle if the envelope goes to idle state 
161 213
        if ( becameIdle ){
162 214
            mTriggerCallback( 'e', mID );
163 215
            reset();
......
174 226
            synthesizeGrain( mGrains[grainIdx], audioOut, envelopeValues, numSamples );
175 227

  
176 228
            if ( !mGrains[grainIdx].alive ){
177
                // this grain is dead so copyu the last of the active grains here 
229
                // this grain is dead so copy the last of the active grains here 
178 230
                // so as to keep all active grains at the beginning of the array 
179 231
                // don't increment grainIdx so the last active grain is processed next cycle
180 232
                // if this grain is the last active grain then mNumAliveGrains is decremented 
......
243 295
        }
244 296
    }
245 297

  
298
    // synthesize a single grain 
246 299
    // audioOut = pointer to audio block to fill 
247 300
    // numSamples = numpber of samples to process for this block
248 301
    void synthesizeGrain( PGrain &grain, T* audioOut, T* envelopeValues, size_t numSamples )
CollidoscopeApp/include/PGranularNode.h
30 30
    explicit PGranularNode( ci::audio::Buffer *grainBuffer, CursorTriggerMsgRingBuffer &triggerRingBuffer );
31 31
    ~PGranularNode();
32 32

  
33
    // set selection size in samples 
33
    /** Set selection size in samples */
34 34
    void setSelectionSize( size_t size )
35 35
    {
36 36
        mSelectionSize.set( size );
37 37
    }
38 38

  
39
    /** Set selection start in samples */
39 40
    void setSelectionStart( size_t start )
40 41
    {
41 42
        mSelectionStart.set( start );
......
46 47
        mGrainDurationCoeff.set( coeff );
47 48
    }
48 49

  
49
    // used for trigger callback in PGRanular 
50
    /* PGranularNode passes itself as trigger callback in PGranular */
50 51
    void operator()( char msgType, int ID );
51 52

  
52 53
    ci::audio::dsp::RingBufferT<NoteMsg>& getNoteRingBuffer() { return mNoteMsgRingBufferPack.getBuffer(); }
......
59 60

  
60 61
private:
61 62

  
63
    // Wraps a std::atomic but get() returns a boost::optional that is set to a real value only when the atomic has changed. 
64
    //  It is used to avoid calling PGranulat setter methods with *  the same value at each audio callback.
62 65
    template< typename T>
63 66
    class LazyAtomic
64 67
    {
......
90 93
        T mPreviousVal;
91 94
    };
92 95

  
96
    // creates or re-start a PGranular and sets the pitch according to the MIDI note passed as argument
93 97
    void handleNoteMsg( const NoteMsg &msg );
94 98

  
95
    // pointer to PGranular object 
99
    // pointers to PGranular objects 
96 100
    std::unique_ptr < collidoscope::PGranular<float, RandomGenerator, PGranularNode > > mPGranularLoop;
97 101
    std::array<std::unique_ptr < collidoscope::PGranular<float, RandomGenerator, PGranularNode > >, kMaxVoices> mPGranularNotes;
102
    // maps midi notes to pgranulars. When a noteOff is received maks sure the right PGranular is turned off
98 103
    std::array<int, kMaxVoices> mMidiNotes;
99 104

  
100 105
    // pointer to the random generator struct passed over to PGranular 
101 106
    std::unique_ptr< RandomGenerator > mRandomOffset;
102 107
    
103
    /* buffer containing the recorder audio, to pass to PGranular in initialize() */
108
    // buffer containing the recorder audio, to pass to PGranular in initialize()
104 109
    ci::audio::Buffer *mGrainBuffer;
105 110

  
106 111
    ci::audio::BufferRef mTempBuffer;
CollidoscopeApp/include/ParticleController.h
3 3
#include "cinder/gl/gl.h"
4 4
#include <vector>
5 5

  
6

  
6
/**
7
 * The ParticleController creates/updates/draws and destroys particles
8
 */ 
7 9
class ParticleController {
8 10

  
9 11
    struct Particle {
......
23 25
	std::vector<Particle> mParticles;
24 26
    std::vector< ci::vec2 > mParticlePositions;
25 27

  
28
    // current number of active particles
26 29
    size_t mNumParticles;
27 30

  
28 31
    ci::gl::VboRef			mParticleVbo;
29 32
    ci::gl::BatchRef		mParticleBatch;
30 33

  
31 34
 public:
35
    /**
36
     * Every time addParticles is run, up to kMaxParticleAdd are added at once
37
     */ 
32 38
    static const int kMaxParticleAdd = 22;
33 39

  
34 40
    ParticleController();
41

  
42
    /**
43
     * Adds \a amount particles and places them in \a initialLocation. 
44
     * \cloudSize determines how far the particles can go
45
     */ 
35 46
	void addParticles(int amount, const ci::vec2 &initialLocation, const float cloudSize);
36 47
	
48
    /**
49
     * Updates position and age of the particles
50
     */ 
37 51
    void updateParticles();
38 52

  
53
    /**
54
     * Draws all the particles
55
     */ 
39 56
    inline void draw()
40 57
    {
41 58
        mParticleBatch->draw();
CollidoscopeApp/include/RingBufferPack.h
3 3
#include "cinder/audio/dsp/RingBuffer.h"
4 4

  
5 5

  
6
/* Packs together a RingBuffer and the erlated array used to exchange data (read/write) with the ring buffer 
7
*/
6
/** Packs together a cinder::audio::dsp::RingBuffer and the related array used passed as argument to exchange data (read/write) with the ring buffer  */
8 7
template <typename T>
9 8
class RingBufferPack {
10 9

  
......
40 39
    T* mArray;
41 40

  
42 41

  
43
};
42
};
CollidoscopeApp/include/Wave.h
30 30
using ci::Color;
31 31
using ci::ColorA;
32 32

  
33
/**
34
 * A Cursor is the white thingy that loops through the selection when Collidoscope is played.
35
 */ 
33 36
struct Cursor {
34 37
    static const int kNoPosition = -100;
35 38
    int pos;
36 39
    double lastUpdate;
37 40
};
38 41

  
39

  
42
/**
43
 * Collidoscope's graphical wave 
44
 *
45
 */ 
40 46
class Wave
41 47
{
42 48
	friend class ParticleController;
43 49

  
44 50
public:
45 51

  
52
    /**
53
     * The selection of the wave that is controlled by the big horizontal knob
54
     *
55
     */ 
46 56
	class Selection {
47 57
		
48 58
	public:
49 59

  
50 60
        Selection( Wave * w, Color color );
51 61
        
62
        /** Sets the start of selection. start is the index of the first chunk of the selection  */
52 63
        void setStart( size_t start );
53 64

  
65
        /** Sets the size of selection. size is the number of chunks the selection is made of */
54 66
		void setSize( size_t size );
55 67
		
68
        /** Particle spread is used to calculate the size of the cloud of particles */
56 69
        void inline setParticleSpread( float spread ){
57 70
            mParticleSpread = spread;
58 71
		}
......
70 83

  
71 84
		float inline  getParticleSpread() const { return mParticleSpread; }
72 85

  
86
        /** When selection is null no selection is showed on the wave */
73 87
		inline void setToNull(){
74 88
            mParticleSpread = 1.0f;
75 89
			mNull = true;
......
107 121

  
108 122
	
109 123

  
110
	/* there is one cursor for each Synth being played */
124
	/* Maps id of the synth to cursor. There is one cursor for each Synth being played */
111 125
	std::map < SynthID, Cursor > mCursors;
126
    /** Holds the positions of the cursor, namely on which chunk the cursor is currently */
112 127
	std::vector<int> mCursorsPos;
113 128

  
114 129
public:
115 130
	
116
    // note used to identify the loop for cursor position 
131
    // value used to identify the loop for cursor position 
117 132
    static const int kLoopNote = -1;
118 133
	static const cinder::Color CURSOR_CLR;
119 134
	/* must be in sync with supercollider durationFactor ControlSpec max */
......
122 137
	static const int PARTICLESIZE_COEFF = 40;
123 138
#endif
124 139

  
140
    /** Resetting a wave makes it shrink until it disappears. Each time a new sample is recorder the wave is reset
141
     *  \param onlyChunks if false the selection is also set to null, if true only the chunks are reset
142
     */
125 143
	void reset(bool onlyChunks);
126 144

  
145
    /** sets top and bottom values for the chunk. 
146
     * \a bottom and \a top are in audio coordinates [-1.0, 1.0]
147
     */
127 148
	void setChunk(size_t index, float bottom, float top);
128 149

  
129 150
	const Chunk & getChunk(size_t index);
130 151

  
152
    /** places the cursor on the wave. Every cursor is associated to a synth voice of the audio engine. 
153
     *  The synth id identifies uniquely the cursor in the internal map of the wave.
154
     *  If the cursor doesn't exist it is created */
131 155
    inline void setCursorPos( SynthID id, int pos, const DrawInfo& di ){
132 156

  
133 157
	    Cursor & cursor = mCursors[id];
......
135 159
	    cursor.lastUpdate = ci::app::getElapsedSeconds();
136 160

  
137 161
#ifdef USE_PARTICLES
138
	    /* if the duration is greater than 1.0 carry on the cursor as a particle
139
	    the smaller the selection the more particles
140
	    the bigger the duration the more particles */
162
	    // The idea is that, if the duration is greater than 1.0, the cursor continues in form of particles
163
	    // The smaller the selection the more particles; the bigger the duration the more particles 
141 164
	    if (mSelection.getParticleSpread() > 1.0f){
142 165
		    /* amountCoeff ranges from 1/8 to 1 */
143 166
            const float amountCoeff = (mSelection.getParticleSpread() / MAX_DURATION);
......
167 190

  
168 191
    void removeCursor( SynthID id ) { mCursors.erase( id ); }
169 192

  
170
    // parameter ranges from 0 to 1 
193
    /** Sets the transparency of this wave. \a alpha ranges from 0 to 1 */
171 194
	inline void setselectionAlpha(float alpha){ mFilterCoeff = alpha;}
172 195

  
173 196
    void draw( const DrawInfo& di );
......
180 203

  
181 204
    Wave( size_t numChunks, Color selectionColor );
182 205

  
183
    // no copies 
206
    /** no copies */
184 207
    Wave( const Wave &copy ) = delete;
185 208
    Wave & operator=(const Wave &copy) = delete;
186 209

  
......
197 220

  
198 221
    float mFilterCoeff;
199 222

  
223
    // cinder gl batch for batch drawing 
200 224
    ci::gl::BatchRef mChunkBatch;
201 225

  
202 226
};
CollidoscopeApp/src/PGranularNode.cpp
59 59
void PGranularNode::process (ci::audio::Buffer *buffer )
60 60
{
61 61
    // only update PGranular if the atomic value has changed from the previous time
62

  
63 62
    const boost::optional<size_t> selectionSize = mSelectionSize.get();
64 63
    if ( selectionSize ){
65 64
        mPGranularLoop->setSelectionSize( *selectionSize );
......
112 111
    }
113 112
}
114 113

  
114
// Called back when new grnular is triggered of turned off. Sends notification message to graphic thread.
115 115
void PGranularNode::operator()( char msgType, int ID ) {
116 116

  
117 117
    switch ( msgType ){
CollidoscopeApp/src/Wave.cpp
96 96

  
97 97
	
98 98
	const float wavePixelLen =  ( mNumChunks * ( 2 + Chunk::kWidth ) );
99
	/* scale the x-axis for the wave to fit the window */
99
	/* scale the x-axis for the wave to fit the window precisely */
100 100
	gl::scale( ((float)di.getWindowWidth() ) / wavePixelLen , 1.0f);
101 101
	/* draw the chunks */
102 102
	if (mSelection.isNull()){

Also available in: Unified diff