To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / CollidoscopeApp / src / AudioEngine.cpp @ 0:02467299402e

History | View | Annotate | Download (6.26 KB)

1 0:02467299402e f
#include "AudioEngine.h"
2
#include "cinder/app/App.h"
3
//FIXME remove App.h include
4
#include "Log.h"
5
6
using namespace ci::audio;
7
8
double chromaticRatios[] = {
9
    1,
10
    1.0594630943591,
11
    1.1224620483089,
12
    1.1892071150019,
13
    1.2599210498937,
14
    1.3348398541685,
15
    1.4142135623711,
16
    1.4983070768743,
17
    1.5874010519653,
18
    1.6817928305039,
19
    1.7817974362766,
20
    1.8877486253586
21
};
22
23
inline double calculateMidiNoteRatio( int midiNote )
24
{
25
    int distanceFromCenter = midiNote - 60; // 60 is the central midi note
26
27
    if ( distanceFromCenter < 0 ){
28
        int diffAmount = -distanceFromCenter;
29
        int octaves = diffAmount / 12;
30
        int intervals = diffAmount % 12;
31
32
        return std::pow( 0.5, octaves ) / chromaticRatios[intervals];
33
    }
34
    else{
35
        int octaves = distanceFromCenter / 12;
36
        int intervals = distanceFromCenter % 12;
37
38
        return std::pow( 2, octaves ) * chromaticRatios[intervals];
39
    }
40
}
41
42
43
AudioEngine::AudioEngine()
44
{}
45
46
AudioEngine::~AudioEngine()
47
{}
48
49
void AudioEngine::setup(const Config& config)
50
{
51
52
    for ( int i = 0; i < NUM_WAVES; i++ ){
53
        mCursorTriggerRingBufferPacks[i].reset( new RingBufferPack<CursorTriggerMsg>( 512 ) ); // FIXME
54
    }
55
56
    /* audio context */
57
    auto ctx = Context::master();
58
59
    /* audio inpu device */
60
    auto inputDeviceNode = ctx->createInputDeviceNode( Device::getDefaultInput() );
61
62
63
    /* route the audio input, which is two channels, to one wave graph for each channel */
64
    for ( int chan = 0; chan < NUM_WAVES; chan++ ){
65
66
        /* one channel router */
67
        mInputRouterNodes[chan] = ctx->makeNode( new ChannelRouterNode( Node::Format().channels( 1 ) ) );
68
69
        /* buffer recorders */
70
        mBufferRecorderNodes[chan] = ctx->makeNode( new BufferToWaveRecorderNode( config.getNumChunks(), config.getWaveLen() ) );
71
        /* this prevents the node from recording before record is pressed */
72
        mBufferRecorderNodes[chan]->setAutoEnabled( false );
73
74
        // route the input part of the audio graph. Two channels input goes into
75
        // one channel route and to one channel buffer recorder
76
        inputDeviceNode >> mInputRouterNodes[chan]->route( chan, 0, 1 ) >> mBufferRecorderNodes[chan];
77
78
79
        // create PGranular loops passing the buffer of the RecorderNode as argument to the contructor
80
        // use -1 as ID
81
        mPGranularNodes[chan] = ctx->makeNode( new PGranularNode( mBufferRecorderNodes[chan]->getRecorderBuffer(), mCursorTriggerRingBufferPacks[chan]->getBuffer() ) );
82
83
        // create filter nodes
84
        mLowPassFilterNodes[chan] = ctx->makeNode( new FilterLowPassNode( MonitorNode::Format().channels( 1 ) ) );
85
        mLowPassFilterNodes[chan]->setCutoffFreq( config.getMaxFilterCutoffFreq() );
86
        mLowPassFilterNodes[chan]->setQ( 0.707f );
87
        // create monitor nodes for oscilloscopes
88
        mOutputMonitorNodes[chan] = ctx->makeNode( new MonitorNode( MonitorNode::Format().channels( 1 ) ) );
89
90
        // all output goes to the filter
91
        mPGranularNodes[chan] >> mLowPassFilterNodes[chan];
92
93
        mOutputRouterNodes[chan] = ctx->makeNode( new ChannelRouterNode( Node::Format().channels( 2 ) ) );
94
95
        // filter goes to output
96
        mLowPassFilterNodes[chan] >> mOutputRouterNodes[chan]->route( 0, chan, 1 ) >> ctx->getOutput();
97
98
        // what goes to output goes to scope
99
        mLowPassFilterNodes[chan] >> mOutputMonitorNodes[chan];
100
101
    }
102
103
    ctx->getOutput()->enableClipDetection( false );
104
    /* enable the whole audio graph */
105
    inputDeviceNode->enable();
106
    ctx->enable();
107
}
108
109
size_t AudioEngine::getSampleRate()
110
{
111
    return Context::master()->getSampleRate();
112
}
113
114
void AudioEngine::loopOn( size_t waveIdx )
115
{
116
    NoteMsg msg = makeNoteMsg( Command::LOOP_ON, 1, 1.0 );
117
    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
118
}
119
120
void AudioEngine::loopOff( size_t waveIdx )
121
{
122
    NoteMsg msg = makeNoteMsg( Command::LOOP_OFF, 0, 0.0 );
123
    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
124
}
125
126
void AudioEngine::record( size_t waveIdx )
127
{
128
    mBufferRecorderNodes[waveIdx]->start();
129
}
130
131
void AudioEngine::noteOn( size_t waveIdx, int midiNote )
132
{
133
134
    double midiAsRate = calculateMidiNoteRatio(midiNote);
135
    NoteMsg msg = makeNoteMsg( Command::NOTE_ON, midiNote, midiAsRate );
136
137
    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
138
}
139
140
void AudioEngine::noteOff( size_t waveIdx, int midiNote )
141
{
142
    NoteMsg msg = makeNoteMsg( Command::NOTE_OFF, midiNote, 0.0 );
143
    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
144
}
145
146
147
148
void AudioEngine::setSelectionSize( size_t waveIdx, size_t size )
149
{
150
    mPGranularNodes[waveIdx]->setSelectionSize( size );
151
}
152
153
void AudioEngine::setSelectionStart( size_t waveIdx, size_t start )
154
{
155
    mPGranularNodes[waveIdx]->setSelectionStart( start );
156
}
157
158
void AudioEngine::setGrainDurationCoeff( size_t waveIdx, double coeff )
159
{
160
    mPGranularNodes[waveIdx]->setGrainsDurationCoeff( coeff );
161
}
162
163
void AudioEngine::setFilterCutoff( size_t waveIdx, double cutoff )
164
{
165
    mLowPassFilterNodes[waveIdx]->setCutoffFreq( cutoff );
166
}
167
168
// ------------------------------------------------------
169
// ----- methods for communication with main thread -----
170
// ------------------------------------------------------
171
172
size_t AudioEngine::getRecordWaveAvailable( size_t waveIdx )
173
{
174
    return mBufferRecorderNodes[waveIdx]->getRingBuffer().getAvailableRead();
175
}
176
177
bool AudioEngine::readRecordWave( size_t waveIdx, RecordWaveMsg* buffer, size_t count )
178
{
179
    return mBufferRecorderNodes[waveIdx]->getRingBuffer().read( buffer, count );
180
}
181
182
void AudioEngine::checkCursorTriggers( size_t waveIdx, std::vector<CursorTriggerMsg>& cursorTriggers )
183
{
184
    ci::audio::dsp::RingBufferT<CursorTriggerMsg> &ringBuffer = mCursorTriggerRingBufferPacks[waveIdx]->getBuffer();
185
    CursorTriggerMsg* ringBufferReadArray = mCursorTriggerRingBufferPacks[waveIdx]->getExchangeArray();
186
187
    size_t availableRead = ringBuffer.getAvailableRead();
188
    bool successfulRead = ringBuffer.read( ringBufferReadArray, availableRead );
189
190
    if ( successfulRead ){
191
        for ( size_t i = 0; i < availableRead; i++ ){
192
            cursorTriggers.push_back( ringBufferReadArray[i] );
193
        }
194
    }
195
}
196
197
const ci::audio::Buffer& AudioEngine::getAudioOutputBuffer( size_t waveIdx ) const
198
{
199
    return mOutputMonitorNodes[waveIdx]->getBuffer();
200
}