f@5
|
1 /*
|
f@5
|
2
|
f@5
|
3 Copyright (C) 2016 Queen Mary University of London
|
f@5
|
4 Author: Fiore Martin
|
f@5
|
5
|
f@5
|
6 This file is part of Collidoscope.
|
f@5
|
7
|
f@5
|
8 Collidoscope is free software: you can redistribute it and/or modify
|
f@5
|
9 it under the terms of the GNU General Public License as published by
|
f@5
|
10 the Free Software Foundation, either version 3 of the License, or
|
f@5
|
11 (at your option) any later version.
|
f@5
|
12
|
f@5
|
13 This program is distributed in the hope that it will be useful,
|
f@5
|
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@5
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@5
|
16 GNU General Public License for more details.
|
f@5
|
17
|
f@5
|
18 You should have received a copy of the GNU General Public License
|
f@5
|
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@5
|
20 */
|
f@5
|
21
|
f@0
|
22 #pragma once
|
f@0
|
23
|
f@0
|
24 #include "cinder/Cinder.h"
|
f@0
|
25 #include "cinder/audio/Node.h"
|
f@0
|
26 #include "cinder/audio/dsp/RingBuffer.h"
|
f@0
|
27 #include "boost/optional.hpp"
|
f@0
|
28 #include "Messages.h"
|
f@0
|
29 #include "RingBufferPack.h"
|
f@0
|
30
|
f@0
|
31 #include <memory>
|
f@0
|
32
|
f@0
|
33 #include "PGranular.h"
|
f@0
|
34 #include "EnvASR.h"
|
f@0
|
35
|
f@0
|
36 typedef std::shared_ptr<class PGranularNode> PGranularNodeRef;
|
f@0
|
37 typedef ci::audio::dsp::RingBufferT<CursorTriggerMsg> CursorTriggerMsgRingBuffer;
|
f@0
|
38
|
f@0
|
39
|
f@0
|
40 struct RandomGenerator;
|
f@0
|
41
|
f@0
|
42 /*
|
f@16
|
43 A node in the Cinder audio graph that holds PGranulars for loop and keyboard playing
|
f@0
|
44 */
|
f@0
|
45 class PGranularNode : public ci::audio::Node
|
f@0
|
46 {
|
f@0
|
47 public:
|
f@0
|
48 static const size_t kMaxVoices = 6;
|
f@0
|
49 static const int kNoMidiNote = -50;
|
f@0
|
50
|
f@0
|
51 explicit PGranularNode( ci::audio::Buffer *grainBuffer, CursorTriggerMsgRingBuffer &triggerRingBuffer );
|
f@0
|
52 ~PGranularNode();
|
f@0
|
53
|
f@3
|
54 /** Set selection size in samples */
|
f@0
|
55 void setSelectionSize( size_t size )
|
f@0
|
56 {
|
f@0
|
57 mSelectionSize.set( size );
|
f@0
|
58 }
|
f@0
|
59
|
f@3
|
60 /** Set selection start in samples */
|
f@0
|
61 void setSelectionStart( size_t start )
|
f@0
|
62 {
|
f@0
|
63 mSelectionStart.set( start );
|
f@0
|
64 }
|
f@0
|
65
|
f@0
|
66 void setGrainsDurationCoeff( double coeff )
|
f@0
|
67 {
|
f@0
|
68 mGrainDurationCoeff.set( coeff );
|
f@0
|
69 }
|
f@0
|
70
|
f@3
|
71 /* PGranularNode passes itself as trigger callback in PGranular */
|
f@0
|
72 void operator()( char msgType, int ID );
|
f@0
|
73
|
f@0
|
74 ci::audio::dsp::RingBufferT<NoteMsg>& getNoteRingBuffer() { return mNoteMsgRingBufferPack.getBuffer(); }
|
f@0
|
75
|
f@0
|
76 protected:
|
f@0
|
77
|
f@5
|
78 void initialize() override;
|
f@0
|
79
|
f@5
|
80 void process( ci::audio::Buffer *buffer ) override;
|
f@0
|
81
|
f@0
|
82 private:
|
f@0
|
83
|
f@3
|
84 // 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
|
85 // It is used to avoid calling PGranular setter methods with the same value at each audio callback.
|
f@0
|
86 template< typename T>
|
f@0
|
87 class LazyAtomic
|
f@0
|
88 {
|
f@0
|
89 public:
|
f@0
|
90 LazyAtomic( T val ) :
|
f@0
|
91 mAtomic( val ),
|
f@0
|
92 mPreviousVal( val )
|
f@0
|
93 {}
|
f@0
|
94
|
f@0
|
95 void set( T val )
|
f@0
|
96 {
|
f@0
|
97 mAtomic = val;
|
f@0
|
98 }
|
f@0
|
99
|
f@0
|
100 boost::optional<T> get()
|
f@0
|
101 {
|
f@0
|
102 const T val = mAtomic;
|
f@0
|
103 if ( val != mPreviousVal ){
|
f@0
|
104 mPreviousVal = val;
|
f@0
|
105 return val;
|
f@0
|
106 }
|
f@0
|
107 else{
|
f@0
|
108 return boost::none;
|
f@0
|
109 }
|
f@0
|
110 }
|
f@0
|
111
|
f@0
|
112 private:
|
f@0
|
113 std::atomic<T> mAtomic;
|
f@0
|
114 T mPreviousVal;
|
f@0
|
115 };
|
f@0
|
116
|
f@3
|
117 // creates or re-start a PGranular and sets the pitch according to the MIDI note passed as argument
|
f@0
|
118 void handleNoteMsg( const NoteMsg &msg );
|
f@0
|
119
|
f@3
|
120 // pointers to PGranular objects
|
f@0
|
121 std::unique_ptr < collidoscope::PGranular<float, RandomGenerator, PGranularNode > > mPGranularLoop;
|
f@0
|
122 std::array<std::unique_ptr < collidoscope::PGranular<float, RandomGenerator, PGranularNode > >, kMaxVoices> mPGranularNotes;
|
f@16
|
123 // maps midi notes to pgranulars. When a noteOff is received makes sure the right PGranular is turned off
|
f@0
|
124 std::array<int, kMaxVoices> mMidiNotes;
|
f@0
|
125
|
f@0
|
126 // pointer to the random generator struct passed over to PGranular
|
f@0
|
127 std::unique_ptr< RandomGenerator > mRandomOffset;
|
f@0
|
128
|
f@16
|
129 // buffer containing the recorded audio, to pass to PGranular in initialize()
|
f@0
|
130 ci::audio::Buffer *mGrainBuffer;
|
f@0
|
131
|
f@0
|
132 ci::audio::BufferRef mTempBuffer;
|
f@0
|
133
|
f@0
|
134 CursorTriggerMsgRingBuffer &mTriggerRingBuffer;
|
f@0
|
135 RingBufferPack<NoteMsg> mNoteMsgRingBufferPack;
|
f@0
|
136
|
f@0
|
137 LazyAtomic<size_t> mSelectionSize;
|
f@0
|
138
|
f@0
|
139 LazyAtomic<size_t> mSelectionStart;
|
f@0
|
140
|
f@0
|
141 LazyAtomic<double> mGrainDurationCoeff;
|
f@0
|
142
|
f@0
|
143
|
f@0
|
144 };
|
f@0
|
145
|