Mercurial > hg > svapp
comparison audioio/ClipMixer.cpp @ 441:aa6fb3516e28 tonioni
Merge from cxx11 branch
author | Chris Cannam |
---|---|
date | Mon, 23 Mar 2015 11:26:28 +0000 |
parents | 72c662fe7ea3 |
children | 88ae0e53a5da |
comparison
equal
deleted
inserted
replaced
440:2185d52b4758 | 441:aa6fb3516e28 |
---|---|
18 #include <sndfile.h> | 18 #include <sndfile.h> |
19 #include <cmath> | 19 #include <cmath> |
20 | 20 |
21 #include "base/Debug.h" | 21 #include "base/Debug.h" |
22 | 22 |
23 ClipMixer::ClipMixer(int channels, int sampleRate, int blockSize) : | 23 ClipMixer::ClipMixer(int channels, sv_samplerate_t sampleRate, sv_frame_t blockSize) : |
24 m_channels(channels), | 24 m_channels(channels), |
25 m_sampleRate(sampleRate), | 25 m_sampleRate(sampleRate), |
26 m_blockSize(blockSize), | 26 m_blockSize(blockSize), |
27 m_clipData(0), | 27 m_clipData(0), |
28 m_clipLength(0), | 28 m_clipLength(0), |
41 { | 41 { |
42 m_channels = channels; | 42 m_channels = channels; |
43 } | 43 } |
44 | 44 |
45 bool | 45 bool |
46 ClipMixer::loadClipData(QString path, float f0, float level) | 46 ClipMixer::loadClipData(QString path, double f0, double level) |
47 { | 47 { |
48 if (m_clipData) { | 48 if (m_clipData) { |
49 cerr << "ClipMixer::loadClipData: Already have clip loaded" << endl; | 49 cerr << "ClipMixer::loadClipData: Already have clip loaded" << endl; |
50 return false; | 50 return false; |
51 } | 51 } |
52 | 52 |
53 SF_INFO info; | 53 SF_INFO info; |
54 SNDFILE *file; | 54 SNDFILE *file; |
55 float *tmpFrames; | 55 float *tmpFrames; |
56 int i; | 56 sv_frame_t i; |
57 | 57 |
58 info.format = 0; | 58 info.format = 0; |
59 file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info); | 59 file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info); |
60 if (!file) { | 60 if (!file) { |
61 cerr << "ClipMixer::loadClipData: Failed to open file path \"" | 61 cerr << "ClipMixer::loadClipData: Failed to open file path \"" |
81 | 81 |
82 for (i = 0; i < info.frames; ++i) { | 82 for (i = 0; i < info.frames; ++i) { |
83 int j; | 83 int j; |
84 m_clipData[i] = 0.0f; | 84 m_clipData[i] = 0.0f; |
85 for (j = 0; j < info.channels; ++j) { | 85 for (j = 0; j < info.channels; ++j) { |
86 m_clipData[i] += tmpFrames[i * info.channels + j] * level; | 86 m_clipData[i] += tmpFrames[i * info.channels + j] * float(level); |
87 } | 87 } |
88 } | 88 } |
89 | 89 |
90 free(tmpFrames); | 90 free(tmpFrames); |
91 | 91 |
100 ClipMixer::reset() | 100 ClipMixer::reset() |
101 { | 101 { |
102 m_playing.clear(); | 102 m_playing.clear(); |
103 } | 103 } |
104 | 104 |
105 float | 105 double |
106 ClipMixer::getResampleRatioFor(float frequency) | 106 ClipMixer::getResampleRatioFor(double frequency) |
107 { | 107 { |
108 if (!m_clipData || !m_clipRate) return 1.0; | 108 if (!m_clipData || !m_clipRate) return 1.0; |
109 float pitchRatio = m_clipF0 / frequency; | 109 double pitchRatio = m_clipF0 / frequency; |
110 float resampleRatio = m_sampleRate / m_clipRate; | 110 double resampleRatio = m_sampleRate / m_clipRate; |
111 return pitchRatio * resampleRatio; | 111 return pitchRatio * resampleRatio; |
112 } | 112 } |
113 | 113 |
114 int | 114 sv_frame_t |
115 ClipMixer::getResampledClipDuration(float frequency) | 115 ClipMixer::getResampledClipDuration(double frequency) |
116 { | 116 { |
117 return int(ceil(m_clipLength * getResampleRatioFor(frequency))); | 117 return sv_frame_t(ceil(double(m_clipLength) * getResampleRatioFor(frequency))); |
118 } | 118 } |
119 | 119 |
120 void | 120 void |
121 ClipMixer::mix(float **toBuffers, | 121 ClipMixer::mix(float **toBuffers, |
122 float gain, | 122 float gain, |
144 | 144 |
145 for (int c = 0; c < m_channels; ++c) { | 145 for (int c = 0; c < m_channels; ++c) { |
146 levels[c] = note.level * gain; | 146 levels[c] = note.level * gain; |
147 } | 147 } |
148 if (note.pan != 0.0 && m_channels == 2) { | 148 if (note.pan != 0.0 && m_channels == 2) { |
149 levels[0] *= 1.0 - note.pan; | 149 levels[0] *= 1.0f - note.pan; |
150 levels[1] *= note.pan + 1.0; | 150 levels[1] *= note.pan + 1.0f; |
151 } | 151 } |
152 | 152 |
153 int start = note.frameOffset; | 153 sv_frame_t start = note.frameOffset; |
154 int durationHere = m_blockSize; | 154 sv_frame_t durationHere = m_blockSize; |
155 if (start > 0) durationHere = m_blockSize - start; | 155 if (start > 0) durationHere = m_blockSize - start; |
156 | 156 |
157 bool ending = false; | 157 bool ending = false; |
158 | 158 |
159 foreach (NoteEnd end, endingNotes) { | 159 foreach (NoteEnd end, endingNotes) { |
165 if (start > 0) durationHere = end.frameOffset - start; | 165 if (start > 0) durationHere = end.frameOffset - start; |
166 break; | 166 break; |
167 } | 167 } |
168 } | 168 } |
169 | 169 |
170 int clipDuration = getResampledClipDuration(note.frequency); | 170 sv_frame_t clipDuration = getResampledClipDuration(note.frequency); |
171 if (start + clipDuration > 0) { | 171 if (start + clipDuration > 0) { |
172 if (start < 0 && start + clipDuration < durationHere) { | 172 if (start < 0 && start + clipDuration < durationHere) { |
173 durationHere = start + clipDuration; | 173 durationHere = start + clipDuration; |
174 } | 174 } |
175 if (durationHere > 0) { | 175 if (durationHere > 0) { |
197 | 197 |
198 void | 198 void |
199 ClipMixer::mixNote(float **toBuffers, | 199 ClipMixer::mixNote(float **toBuffers, |
200 float *levels, | 200 float *levels, |
201 float frequency, | 201 float frequency, |
202 int sourceOffset, | 202 sv_frame_t sourceOffset, |
203 int targetOffset, | 203 sv_frame_t targetOffset, |
204 int sampleCount, | 204 sv_frame_t sampleCount, |
205 bool isEnd) | 205 bool isEnd) |
206 { | 206 { |
207 if (!m_clipData) return; | 207 if (!m_clipData) return; |
208 | 208 |
209 float ratio = getResampleRatioFor(frequency); | 209 double ratio = getResampleRatioFor(frequency); |
210 | 210 |
211 float releaseTime = 0.01; | 211 double releaseTime = 0.01; |
212 int releaseSampleCount = round(releaseTime * m_sampleRate); | 212 sv_frame_t releaseSampleCount = sv_frame_t(round(releaseTime * m_sampleRate)); |
213 if (releaseSampleCount > sampleCount) { | 213 if (releaseSampleCount > sampleCount) { |
214 releaseSampleCount = sampleCount; | 214 releaseSampleCount = sampleCount; |
215 } | 215 } |
216 float releaseFraction = 1.f/releaseSampleCount; | 216 double releaseFraction = 1.0/double(releaseSampleCount); |
217 | 217 |
218 for (int i = 0; i < sampleCount; ++i) { | 218 for (sv_frame_t i = 0; i < sampleCount; ++i) { |
219 | 219 |
220 int s = sourceOffset + i; | 220 sv_frame_t s = sourceOffset + i; |
221 | 221 |
222 float os = s / ratio; | 222 double os = double(s) / ratio; |
223 int osi = int(floor(os)); | 223 sv_frame_t osi = sv_frame_t(floor(os)); |
224 | 224 |
225 //!!! just linear interpolation for now (same as SV's sample | 225 //!!! just linear interpolation for now (same as SV's sample |
226 //!!! player). a small sinc kernel would be better and | 226 //!!! player). a small sinc kernel would be better and |
227 //!!! probably "good enough" | 227 //!!! probably "good enough" |
228 float value = 0.f; | 228 double value = 0.0; |
229 if (osi < m_clipLength) { | 229 if (osi < m_clipLength) { |
230 value += m_clipData[osi]; | 230 value += m_clipData[osi]; |
231 } | 231 } |
232 if (osi + 1 < m_clipLength) { | 232 if (osi + 1 < m_clipLength) { |
233 value += (m_clipData[osi + 1] - m_clipData[osi]) * (os - osi); | 233 value += (m_clipData[osi + 1] - m_clipData[osi]) * (os - double(osi)); |
234 } | 234 } |
235 | 235 |
236 if (isEnd && i + releaseSampleCount > sampleCount) { | 236 if (isEnd && i + releaseSampleCount > sampleCount) { |
237 value *= releaseFraction * (sampleCount - i); // linear ramp for release | 237 value *= releaseFraction * double(sampleCount - i); // linear ramp for release |
238 } | 238 } |
239 | 239 |
240 for (int c = 0; c < m_channels; ++c) { | 240 for (int c = 0; c < m_channels; ++c) { |
241 toBuffers[c][targetOffset + i] += levels[c] * value; | 241 toBuffers[c][targetOffset + i] += float(levels[c] * value); |
242 } | 242 } |
243 } | 243 } |
244 } | 244 } |
245 | 245 |
246 | 246 |