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

First import CollidoscopeApp for Raspberry Pi JackDevice Teensy code for Collidoscope
author Fiore Martin <f.martin@qmul.ac.uk>
date Thu, 30 Jun 2016 14:50:06 +0200
parents
children dd889fff8423
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CollidoscopeApp/src/AudioEngine.cpp	Thu Jun 30 14:50:06 2016 +0200
@@ -0,0 +1,201 @@
+#include "AudioEngine.h"
+#include "cinder/app/App.h"
+//FIXME remove App.h include 
+#include "Log.h"
+
+using namespace ci::audio;
+
+double chromaticRatios[] = { 
+    1, 
+    1.0594630943591, 
+    1.1224620483089, 
+    1.1892071150019, 
+    1.2599210498937, 
+    1.3348398541685, 
+    1.4142135623711, 
+    1.4983070768743, 
+    1.5874010519653, 
+    1.6817928305039, 
+    1.7817974362766, 
+    1.8877486253586 
+};
+
+inline double calculateMidiNoteRatio( int midiNote )
+{
+    int distanceFromCenter = midiNote - 60; // 60 is the central midi note 
+
+    if ( distanceFromCenter < 0 ){
+        int diffAmount = -distanceFromCenter;
+        int octaves = diffAmount / 12;
+        int intervals = diffAmount % 12;
+
+        return std::pow( 0.5, octaves ) / chromaticRatios[intervals];
+    }
+    else{
+        int octaves = distanceFromCenter / 12;
+        int intervals = distanceFromCenter % 12;
+
+        return std::pow( 2, octaves ) * chromaticRatios[intervals];
+    }
+}
+
+
+AudioEngine::AudioEngine() 
+{}
+
+AudioEngine::~AudioEngine()
+{}
+
+void AudioEngine::setup(const Config& config)
+{
+    
+    for ( int i = 0; i < NUM_WAVES; i++ ){
+        mCursorTriggerRingBufferPacks[i].reset( new RingBufferPack<CursorTriggerMsg>( 512 ) ); // FIXME 
+    }
+
+    /* audio context */
+    auto ctx = Context::master();
+
+    /* audio inpu device */
+    auto inputDeviceNode = ctx->createInputDeviceNode( Device::getDefaultInput() );
+ 
+
+    /* route the audio input, which is two channels, to one wave graph for each channel */
+    for ( int chan = 0; chan < NUM_WAVES; chan++ ){
+
+        /* one channel router */
+        mInputRouterNodes[chan] = ctx->makeNode( new ChannelRouterNode( Node::Format().channels( 1 ) ) );
+
+        /* buffer recorders */  
+        mBufferRecorderNodes[chan] = ctx->makeNode( new BufferToWaveRecorderNode( config.getNumChunks(), config.getWaveLen() ) );
+        /* this prevents the node from recording before record is pressed */
+        mBufferRecorderNodes[chan]->setAutoEnabled( false );
+
+        // route the input part of the audio graph. Two channels input goes into
+        // one channel route and to one channel buffer recorder 
+        inputDeviceNode >> mInputRouterNodes[chan]->route( chan, 0, 1 ) >> mBufferRecorderNodes[chan];
+
+
+        // create PGranular loops passing the buffer of the RecorderNode as argument to the contructor 
+        // use -1 as ID 
+        mPGranularNodes[chan] = ctx->makeNode( new PGranularNode( mBufferRecorderNodes[chan]->getRecorderBuffer(), mCursorTriggerRingBufferPacks[chan]->getBuffer() ) );
+
+        // create filter nodes 
+        mLowPassFilterNodes[chan] = ctx->makeNode( new FilterLowPassNode( MonitorNode::Format().channels( 1 ) ) );
+        mLowPassFilterNodes[chan]->setCutoffFreq( config.getMaxFilterCutoffFreq() );
+        mLowPassFilterNodes[chan]->setQ( 0.707f );
+        // create monitor nodes for oscilloscopes 
+        mOutputMonitorNodes[chan] = ctx->makeNode( new MonitorNode( MonitorNode::Format().channels( 1 ) ) );
+
+        // all output goes to the filter 
+        mPGranularNodes[chan] >> mLowPassFilterNodes[chan];
+        
+        mOutputRouterNodes[chan] = ctx->makeNode( new ChannelRouterNode( Node::Format().channels( 2 ) ) );
+
+        // filter goes to output 
+        mLowPassFilterNodes[chan] >> mOutputRouterNodes[chan]->route( 0, chan, 1 ) >> ctx->getOutput();
+        
+        // what goes to output goes to scope 
+        mLowPassFilterNodes[chan] >> mOutputMonitorNodes[chan];
+
+    }
+
+    ctx->getOutput()->enableClipDetection( false );
+    /* enable the whole audio graph */
+    inputDeviceNode->enable();
+    ctx->enable();
+}
+
+size_t AudioEngine::getSampleRate()
+{
+    return Context::master()->getSampleRate();
+}
+
+void AudioEngine::loopOn( size_t waveIdx )
+{
+    NoteMsg msg = makeNoteMsg( Command::LOOP_ON, 1, 1.0 );
+    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
+}
+
+void AudioEngine::loopOff( size_t waveIdx )
+{
+    NoteMsg msg = makeNoteMsg( Command::LOOP_OFF, 0, 0.0 );
+    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
+}
+
+void AudioEngine::record( size_t waveIdx )
+{
+    mBufferRecorderNodes[waveIdx]->start();
+}
+
+void AudioEngine::noteOn( size_t waveIdx, int midiNote )
+{
+    
+    double midiAsRate = calculateMidiNoteRatio(midiNote);
+    NoteMsg msg = makeNoteMsg( Command::NOTE_ON, midiNote, midiAsRate );
+
+    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
+}
+
+void AudioEngine::noteOff( size_t waveIdx, int midiNote )
+{
+    NoteMsg msg = makeNoteMsg( Command::NOTE_OFF, midiNote, 0.0 );
+    mPGranularNodes[waveIdx]->getNoteRingBuffer().write( &msg, 1 );
+}
+
+
+
+void AudioEngine::setSelectionSize( size_t waveIdx, size_t size )
+{
+    mPGranularNodes[waveIdx]->setSelectionSize( size );
+}
+
+void AudioEngine::setSelectionStart( size_t waveIdx, size_t start )
+{
+    mPGranularNodes[waveIdx]->setSelectionStart( start );
+}
+
+void AudioEngine::setGrainDurationCoeff( size_t waveIdx, double coeff )
+{
+    mPGranularNodes[waveIdx]->setGrainsDurationCoeff( coeff );
+}
+
+void AudioEngine::setFilterCutoff( size_t waveIdx, double cutoff )
+{
+    mLowPassFilterNodes[waveIdx]->setCutoffFreq( cutoff );
+}
+
+// ------------------------------------------------------
+// ----- methods for communication with main thread -----
+// ------------------------------------------------------
+
+size_t AudioEngine::getRecordWaveAvailable( size_t waveIdx )
+{
+    return mBufferRecorderNodes[waveIdx]->getRingBuffer().getAvailableRead();
+}
+
+bool AudioEngine::readRecordWave( size_t waveIdx, RecordWaveMsg* buffer, size_t count )
+{
+    return mBufferRecorderNodes[waveIdx]->getRingBuffer().read( buffer, count );
+}
+
+void AudioEngine::checkCursorTriggers( size_t waveIdx, std::vector<CursorTriggerMsg>& cursorTriggers )
+{
+    ci::audio::dsp::RingBufferT<CursorTriggerMsg> &ringBuffer = mCursorTriggerRingBufferPacks[waveIdx]->getBuffer();
+    CursorTriggerMsg* ringBufferReadArray = mCursorTriggerRingBufferPacks[waveIdx]->getExchangeArray();
+
+    size_t availableRead = ringBuffer.getAvailableRead();
+    bool successfulRead = ringBuffer.read( ringBufferReadArray, availableRead );
+
+    if ( successfulRead ){
+        for ( size_t i = 0; i < availableRead; i++ ){
+            cursorTriggers.push_back( ringBufferReadArray[i] );
+        }
+    }
+}
+
+const ci::audio::Buffer& AudioEngine::getAudioOutputBuffer( size_t waveIdx ) const
+{
+    return mOutputMonitorNodes[waveIdx]->getBuffer();
+}
+