comparison audioio/ClipMixer.cpp @ 450:d9d132c0e240 alignment_view

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