Mercurial > hg > svapp
comparison audioio/ClipMixer.cpp @ 310:8c59cc68eabd tonioni
Initial implementation of clip note mix
author | Chris Cannam |
---|---|
date | Tue, 07 Jan 2014 17:11:14 +0000 |
parents | 289d65722123 |
children | 86fb9160d122 |
comparison
equal
deleted
inserted
replaced
309:71050ffd0141 | 310:8c59cc68eabd |
---|---|
14 */ | 14 */ |
15 | 15 |
16 #include "ClipMixer.h" | 16 #include "ClipMixer.h" |
17 | 17 |
18 #include <sndfile.h> | 18 #include <sndfile.h> |
19 #include <cmath> | |
19 | 20 |
20 #include "base/Debug.h" | 21 #include "base/Debug.h" |
21 | 22 |
22 ClipMixer::ClipMixer(int channels, int sampleRate, int blockSize) : | 23 ClipMixer::ClipMixer(int channels, int sampleRate, int blockSize) : |
23 m_channels(channels), | 24 m_channels(channels), |
87 free(tmpFrames); | 88 free(tmpFrames); |
88 | 89 |
89 m_clipLength = info.frames; | 90 m_clipLength = info.frames; |
90 m_clipF0 = f0; | 91 m_clipF0 = f0; |
91 m_clipRate = info.samplerate; | 92 m_clipRate = info.samplerate; |
93 | |
94 return true; | |
92 } | 95 } |
93 | 96 |
94 void | 97 void |
95 ClipMixer::reset() | 98 ClipMixer::reset() |
96 { | 99 { |
97 //!!! | 100 m_playing.clear(); |
101 } | |
102 | |
103 float | |
104 ClipMixer::getResampleRatioFor(float frequency) | |
105 { | |
106 if (!m_clipData) return 1.0; | |
107 float pitchRatio = frequency / m_clipF0; | |
108 float resampleRatio = m_sampleRate / m_clipRate; | |
109 return pitchRatio * resampleRatio; | |
110 } | |
111 | |
112 int | |
113 ClipMixer::getResampledClipDuration(float frequency) | |
114 { | |
115 return int(ceil(m_clipLength * getResampleRatioFor(frequency))); | |
98 } | 116 } |
99 | 117 |
100 void | 118 void |
101 ClipMixer::mix(float **toBuffers, | 119 ClipMixer::mix(float **toBuffers, |
102 float gain, | 120 float gain, |
103 std::vector<NoteStart> newNotes, | 121 std::vector<NoteStart> newNotes, |
104 std::vector<NoteEnd> endingNotes) | 122 std::vector<NoteEnd> endingNotes) |
105 { | 123 { |
106 //!!! do this! | 124 foreach (NoteStart note, newNotes) { |
107 } | 125 m_playing.push_back(note); |
108 | 126 } |
127 | |
128 std::vector<NoteStart> remaining; | |
129 | |
130 float *levels = new float[m_channels]; | |
131 | |
132 foreach (NoteStart note, m_playing) { | |
133 | |
134 for (int c = 0; c < m_channels; ++c) { | |
135 levels[c] = gain; | |
136 } | |
137 if (note.pan != 0.0 && m_channels == 2) { | |
138 levels[0] *= 1.0 - note.pan; | |
139 levels[1] *= note.pan + 1.0; | |
140 } | |
141 | |
142 int start = note.frameOffset; | |
143 int durationHere = m_blockSize; | |
144 if (start > 0) durationHere = m_blockSize - start; | |
145 | |
146 bool ending = false; | |
147 | |
148 foreach (NoteEnd end, endingNotes) { | |
149 if (end.frequency == note.frequency && | |
150 end.frameOffset >= start && | |
151 end.frameOffset <= m_blockSize) { | |
152 ending = true; | |
153 durationHere = end.frameOffset; | |
154 if (start > 0) durationHere = end.frameOffset - start; | |
155 break; | |
156 } | |
157 } | |
158 | |
159 int clipDuration = getResampledClipDuration(note.frequency); | |
160 if (start + clipDuration > 0) { | |
161 if (start < 0 && start + clipDuration < durationHere) { | |
162 durationHere = clipDuration - start; | |
163 } | |
164 if (durationHere > 0) { | |
165 mixNote(toBuffers, | |
166 levels, | |
167 note.frequency, | |
168 start < 0 ? -start : 0, | |
169 start > 0 ? start : 0, | |
170 durationHere); | |
171 } | |
172 } | |
173 | |
174 if (!ending) { | |
175 NoteStart adjusted = note; | |
176 adjusted.frameOffset -= m_blockSize; | |
177 remaining.push_back(adjusted); | |
178 } | |
179 } | |
180 | |
181 m_playing = remaining; | |
182 } | |
183 | |
184 void | |
185 ClipMixer::mixNote(float **toBuffers, | |
186 float *levels, | |
187 float frequency, | |
188 int sourceOffset, | |
189 int targetOffset, | |
190 int sampleCount) | |
191 { | |
192 if (!m_clipData) return; | |
193 | |
194 float ratio = getResampleRatioFor(frequency); | |
195 | |
196 //!!! todo: release time | |
197 | |
198 for (int i = 0; i < sampleCount; ++i) { | |
199 | |
200 int s = sourceOffset + i; | |
201 | |
202 float os = s / ratio; | |
203 int osi = int(floor(os)); | |
204 | |
205 //!!! just linear interpolation for now (same as SV's sample | |
206 //!!! player). a small sinc kernel would be better and | |
207 //!!! probably "good enough" | |
208 float value = 0.f; | |
209 if (osi < m_clipLength) { | |
210 value += m_clipData[osi]; | |
211 } | |
212 if (osi + 1 < m_clipLength) { | |
213 value += (m_clipData[osi + 1] - m_clipData[osi]) * (os - osi); | |
214 } | |
215 | |
216 for (int c = 0; c < m_channels; ++c) { | |
217 toBuffers[c][targetOffset + i] = levels[c] * value; | |
218 } | |
219 } | |
220 } | |
221 | |
222 |