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@0: A node in the Cinder audio graph that holds a PGranular 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@0: // set selection size in samples f@0: void setSelectionSize( size_t size ) f@0: { f@0: mSelectionSize.set( size ); f@0: } f@0: 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@0: // used for 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@0: void initialize() override; f@0: f@0: void process( ci::audio::Buffer *buffer ) override; f@0: f@0: private: f@0: 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@0: void handleNoteMsg( const NoteMsg &msg ); f@0: f@0: // pointer to PGranular object f@0: std::unique_ptr < collidoscope::PGranular > mPGranularLoop; f@0: std::array >, kMaxVoices> mPGranularNotes; 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@0: /* buffer containing the recorder 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: