f@5: /*
f@5:
f@5: Copyright (C) 2016 Queen Mary University of London
f@5: Author: Fiore Martin
f@5:
f@5: This file is part of Collidoscope.
f@5:
f@5: Collidoscope is free software: you can redistribute it and/or modify
f@5: it under the terms of the GNU General Public License as published by
f@5: the Free Software Foundation, either version 3 of the License, or
f@5: (at your option) any later version.
f@5:
f@5: This program is distributed in the hope that it will be useful,
f@5: but WITHOUT ANY WARRANTY; without even the implied warranty of
f@5: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f@5: GNU General Public License for more details.
f@5:
f@5: You should have received a copy of the GNU General Public License
f@5: along with this program. If not, see .
f@5: */
f@5:
f@0: #pragma once
f@0:
f@0: #include "cinder/Cinder.h"
f@0: #include "cinder/audio/Node.h"
f@0: #include "cinder/audio/dsp/RingBuffer.h"
f@0: #include "boost/optional.hpp"
f@0: #include "Messages.h"
f@0: #include "RingBufferPack.h"
f@0:
f@0: #include
f@0:
f@0: #include "PGranular.h"
f@0: #include "EnvASR.h"
f@0:
f@0: typedef std::shared_ptr PGranularNodeRef;
f@0: typedef ci::audio::dsp::RingBufferT CursorTriggerMsgRingBuffer;
f@0:
f@0:
f@0: struct RandomGenerator;
f@0:
f@0: /*
f@16: A node in the Cinder audio graph that holds PGranulars for loop and keyboard playing
f@0: */
f@0: class PGranularNode : public ci::audio::Node
f@0: {
f@0: public:
f@0: static const size_t kMaxVoices = 6;
f@0: static const int kNoMidiNote = -50;
f@0:
f@0: explicit PGranularNode( ci::audio::Buffer *grainBuffer, CursorTriggerMsgRingBuffer &triggerRingBuffer );
f@0: ~PGranularNode();
f@0:
f@3: /** Set selection size in samples */
f@0: void setSelectionSize( size_t size )
f@0: {
f@0: mSelectionSize.set( size );
f@0: }
f@0:
f@3: /** Set selection start in samples */
f@0: void setSelectionStart( size_t start )
f@0: {
f@0: mSelectionStart.set( start );
f@0: }
f@0:
f@0: void setGrainsDurationCoeff( double coeff )
f@0: {
f@0: mGrainDurationCoeff.set( coeff );
f@0: }
f@0:
f@3: /* PGranularNode passes itself as trigger callback in PGranular */
f@0: void operator()( char msgType, int ID );
f@0:
f@0: ci::audio::dsp::RingBufferT& getNoteRingBuffer() { return mNoteMsgRingBufferPack.getBuffer(); }
f@0:
f@0: protected:
f@0:
f@5: void initialize() override;
f@0:
f@5: void process( ci::audio::Buffer *buffer ) override;
f@0:
f@0: private:
f@0:
f@3: // Wraps a std::atomic but get() returns a boost::optional that is set to a real value only when the atomic has changed.
f@16: // It is used to avoid calling PGranular setter methods with the same value at each audio callback.
f@0: template< typename T>
f@0: class LazyAtomic
f@0: {
f@0: public:
f@0: LazyAtomic( T val ) :
f@0: mAtomic( val ),
f@0: mPreviousVal( val )
f@0: {}
f@0:
f@0: void set( T val )
f@0: {
f@0: mAtomic = val;
f@0: }
f@0:
f@0: boost::optional get()
f@0: {
f@0: const T val = mAtomic;
f@0: if ( val != mPreviousVal ){
f@0: mPreviousVal = val;
f@0: return val;
f@0: }
f@0: else{
f@0: return boost::none;
f@0: }
f@0: }
f@0:
f@0: private:
f@0: std::atomic mAtomic;
f@0: T mPreviousVal;
f@0: };
f@0:
f@3: // creates or re-start a PGranular and sets the pitch according to the MIDI note passed as argument
f@0: void handleNoteMsg( const NoteMsg &msg );
f@0:
f@3: // pointers to PGranular objects
f@0: std::unique_ptr < collidoscope::PGranular > mPGranularLoop;
f@0: std::array >, kMaxVoices> mPGranularNotes;
f@16: // maps midi notes to pgranulars. When a noteOff is received makes sure the right PGranular is turned off
f@0: std::array mMidiNotes;
f@0:
f@0: // pointer to the random generator struct passed over to PGranular
f@0: std::unique_ptr< RandomGenerator > mRandomOffset;
f@0:
f@16: // buffer containing the recorded audio, to pass to PGranular in initialize()
f@0: ci::audio::Buffer *mGrainBuffer;
f@0:
f@0: ci::audio::BufferRef mTempBuffer;
f@0:
f@0: CursorTriggerMsgRingBuffer &mTriggerRingBuffer;
f@0: RingBufferPack mNoteMsgRingBufferPack;
f@0:
f@0: LazyAtomic mSelectionSize;
f@0:
f@0: LazyAtomic mSelectionStart;
f@0:
f@0: LazyAtomic mGrainDurationCoeff;
f@0:
f@0:
f@0: };
f@0: