comparison plugin/plugins/SamplePlayer.cpp @ 0:fc9323a41f5a

start base : Sonic Visualiser sv1-1.0rc1
author lbajardsilogic
date Fri, 11 May 2007 09:08:14 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:fc9323a41f5a
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version. See the file
12 COPYING included with this distribution for more information.
13 */
14
15 /*
16 Based on trivial_sampler from the DSSI distribution
17 (by Chris Cannam, public domain).
18 */
19
20 #include "SamplePlayer.h"
21
22 #include <dssi.h>
23 #include <cmath>
24
25 #include <QMutexLocker>
26 #include <QDir>
27 #include <QFileInfo>
28
29 #include <sndfile.h>
30 #include <samplerate.h>
31 #include <iostream>
32
33 #include "system/System.h"
34
35 const char *const
36 SamplePlayer::portNames[PortCount] =
37 {
38 "Output",
39 "Tuned (on/off)",
40 "Base Pitch (MIDI)",
41 "Tuning of A (Hz)",
42 "Sustain (on/off)",
43 "Release time (s)"
44 };
45
46 const LADSPA_PortDescriptor
47 SamplePlayer::ports[PortCount] =
48 {
49 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
50 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
51 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
52 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
53 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL
54 };
55
56 const LADSPA_PortRangeHint
57 SamplePlayer::hints[PortCount] =
58 {
59 { 0, 0, 0 },
60 { LADSPA_HINT_DEFAULT_MAXIMUM | LADSPA_HINT_INTEGER |
61 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
62 { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER |
63 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 120 },
64 { LADSPA_HINT_DEFAULT_440 | LADSPA_HINT_LOGARITHMIC |
65 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 400, 499 },
66 { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_INTEGER |
67 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
68 { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_LOGARITHMIC |
69 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0.001, 2.0 }
70 };
71
72 const LADSPA_Properties
73 SamplePlayer::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
74
75 const LADSPA_Descriptor
76 SamplePlayer::ladspaDescriptor =
77 {
78 0, // "Unique" ID
79 "sample_player", // Label
80 properties,
81 "Library Sample Player", // Name
82 "Chris Cannam", // Maker
83 "GPL", // Copyright
84 PortCount,
85 ports,
86 portNames,
87 hints,
88 0, // Implementation data
89 instantiate,
90 connectPort,
91 activate,
92 run,
93 0, // Run adding
94 0, // Set run adding gain
95 deactivate,
96 cleanup
97 };
98
99 const DSSI_Descriptor
100 SamplePlayer::dssiDescriptor =
101 {
102 2, // DSSI API version
103 &ladspaDescriptor,
104 configure,
105 getProgram,
106 selectProgram,
107 getMidiController,
108 runSynth,
109 0, // Run synth adding
110 0, // Run multiple synths
111 0, // Run multiple synths adding
112 receiveHostDescriptor
113 };
114
115 const DSSI_Host_Descriptor *
116 SamplePlayer::hostDescriptor = 0;
117
118
119 const DSSI_Descriptor *
120 SamplePlayer::getDescriptor(unsigned long index)
121 {
122 if (index == 0) return &dssiDescriptor;
123 return 0;
124 }
125
126 SamplePlayer::SamplePlayer(int sampleRate) :
127 m_output(0),
128 m_retune(0),
129 m_basePitch(0),
130 m_concertA(0),
131 m_sustain(0),
132 m_release(0),
133 m_sampleData(0),
134 m_sampleCount(0),
135 m_sampleRate(sampleRate),
136 m_sampleNo(0),
137 m_sampleDir("samples"),
138 m_sampleSearchComplete(false),
139 m_pendingProgramChange(-1)
140 {
141 }
142
143 SamplePlayer::~SamplePlayer()
144 {
145 if (m_sampleData) free(m_sampleData);
146 }
147
148 LADSPA_Handle
149 SamplePlayer::instantiate(const LADSPA_Descriptor *, unsigned long rate)
150 {
151 if (!hostDescriptor || !hostDescriptor->request_non_rt_thread) {
152 std::cerr << "SamplePlayer::instantiate: Host does not provide request_non_rt_thread, not instantiating" << std::endl;
153 return 0;
154 }
155
156 SamplePlayer *player = new SamplePlayer(rate);
157
158 if (hostDescriptor->request_non_rt_thread(player, workThreadCallback)) {
159 std::cerr << "SamplePlayer::instantiate: Host rejected request_non_rt_thread call, not instantiating" << std::endl;
160 delete player;
161 return 0;
162 }
163
164 return player;
165 }
166
167 void
168 SamplePlayer::connectPort(LADSPA_Handle handle,
169 unsigned long port, LADSPA_Data *location)
170 {
171 SamplePlayer *player = (SamplePlayer *)handle;
172
173 float **ports[PortCount] = {
174 &player->m_output,
175 &player->m_retune,
176 &player->m_basePitch,
177 &player->m_concertA,
178 &player->m_sustain,
179 &player->m_release
180 };
181
182 *ports[port] = (float *)location;
183 }
184
185 void
186 SamplePlayer::activate(LADSPA_Handle handle)
187 {
188 SamplePlayer *player = (SamplePlayer *)handle;
189 QMutexLocker locker(&player->m_mutex);
190
191 player->m_sampleNo = 0;
192
193 for (size_t i = 0; i < Polyphony; ++i) {
194 player->m_ons[i] = -1;
195 player->m_offs[i] = -1;
196 player->m_velocities[i] = 0;
197 }
198 }
199
200 void
201 SamplePlayer::run(LADSPA_Handle handle, unsigned long samples)
202 {
203 runSynth(handle, samples, 0, 0);
204 }
205
206 void
207 SamplePlayer::deactivate(LADSPA_Handle handle)
208 {
209 activate(handle); // both functions just reset the plugin
210 }
211
212 void
213 SamplePlayer::cleanup(LADSPA_Handle handle)
214 {
215 delete (SamplePlayer *)handle;
216 }
217
218 char *
219 SamplePlayer::configure(LADSPA_Handle handle, const char *key, const char *value)
220 {
221 if (key && !strcmp(key, "sampledir")) {
222
223 SamplePlayer *player = (SamplePlayer *)handle;
224
225 QMutexLocker locker(&player->m_mutex);
226
227 if (QFileInfo(value).exists() &&
228 QFileInfo(value).isDir()) {
229
230 player->m_sampleDir = value;
231
232 if (player->m_sampleSearchComplete) {
233 player->m_sampleSearchComplete = false;
234 player->searchSamples();
235 }
236
237 return 0;
238
239 } else {
240 char *buffer = (char *)malloc(strlen(value) + 80);
241 sprintf(buffer, "Sample directory \"%s\" does not exist, leaving unchanged", value);
242 return buffer;
243 }
244 }
245
246 return strdup("Unknown configure key");
247 }
248
249 const DSSI_Program_Descriptor *
250 SamplePlayer::getProgram(LADSPA_Handle handle, unsigned long program)
251 {
252 SamplePlayer *player = (SamplePlayer *)handle;
253
254 if (!player->m_sampleSearchComplete) {
255 QMutexLocker locker(&player->m_mutex);
256 if (!player->m_sampleSearchComplete) {
257 player->searchSamples();
258 }
259 }
260 if (program >= player->m_samples.size()) return 0;
261
262 static DSSI_Program_Descriptor descriptor;
263 static char name[60];
264
265 strncpy(name, player->m_samples[program].first.toLocal8Bit().data(), 60);
266 name[59] = '\0';
267
268 descriptor.Bank = 0;
269 descriptor.Program = program;
270 descriptor.Name = name;
271
272 return &descriptor;
273 }
274
275 void
276 SamplePlayer::selectProgram(LADSPA_Handle handle,
277 unsigned long,
278 unsigned long program)
279 {
280 SamplePlayer *player = (SamplePlayer *)handle;
281 player->m_pendingProgramChange = program;
282 }
283
284 int
285 SamplePlayer::getMidiController(LADSPA_Handle, unsigned long port)
286 {
287 int controllers[PortCount] = {
288 DSSI_NONE,
289 DSSI_CC(12),
290 DSSI_CC(13),
291 DSSI_CC(64),
292 DSSI_CC(72)
293 };
294
295 return controllers[port];
296 }
297
298 void
299 SamplePlayer::runSynth(LADSPA_Handle handle, unsigned long samples,
300 snd_seq_event_t *events, unsigned long eventCount)
301 {
302 SamplePlayer *player = (SamplePlayer *)handle;
303
304 player->runImpl(samples, events, eventCount);
305 }
306
307 void
308 SamplePlayer::receiveHostDescriptor(const DSSI_Host_Descriptor *descriptor)
309 {
310 hostDescriptor = descriptor;
311 }
312
313 void
314 SamplePlayer::workThreadCallback(LADSPA_Handle handle)
315 {
316 SamplePlayer *player = (SamplePlayer *)handle;
317
318 if (player->m_pendingProgramChange >= 0) {
319
320 // std::cerr << "SamplePlayer::workThreadCallback: pending program change " << player->m_pendingProgramChange << std::endl;
321
322 player->m_mutex.lock();
323
324 int program = player->m_pendingProgramChange;
325 player->m_pendingProgramChange = -1;
326
327 if (!player->m_sampleSearchComplete) {
328 player->searchSamples();
329 }
330
331 if (program < int(player->m_samples.size())) {
332 QString path = player->m_samples[program].second;
333 QString programName = player->m_samples[program].first;
334 if (programName != player->m_program) {
335 player->m_program = programName;
336 player->m_mutex.unlock();
337 player->loadSampleData(path);
338 } else {
339 player->m_mutex.unlock();
340 }
341 }
342 }
343
344 if (!player->m_sampleSearchComplete) {
345
346 QMutexLocker locker(&player->m_mutex);
347
348 if (!player->m_sampleSearchComplete) {
349 player->searchSamples();
350 }
351 }
352 }
353
354 void
355 SamplePlayer::searchSamples()
356 {
357 if (m_sampleSearchComplete) return;
358
359 m_samples.clear();
360
361 std::cerr << "SamplePlayer::searchSamples: Directory is \""
362 << m_sampleDir.toLocal8Bit().data() << "\"" << std::endl;
363
364 QDir dir(m_sampleDir, "*.wav");
365
366 for (unsigned int i = 0; i < dir.count(); ++i) {
367 QFileInfo file(dir.filePath(dir[i]));
368 if (file.isReadable()) {
369 m_samples.push_back(std::pair<QString, QString>
370 (file.baseName(), file.filePath()));
371 // std::cerr << "Found: " << dir[i].toLocal8Bit().data() << std::endl;
372 }
373 }
374
375 m_sampleSearchComplete = true;
376 }
377
378 void
379 SamplePlayer::loadSampleData(QString path)
380 {
381 SF_INFO info;
382 SNDFILE *file;
383 size_t samples = 0;
384 float *tmpFrames, *tmpSamples, *tmpResamples, *tmpOld;
385 size_t i;
386
387 info.format = 0;
388 file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info);
389 if (!file) {
390 std::cerr << "SamplePlayer::loadSampleData: Failed to open file "
391 << path.toLocal8Bit().data() << ": "
392 << sf_strerror(file) << std::endl;
393 return;
394 }
395
396 samples = info.frames;
397 tmpFrames = (float *)malloc(info.frames * info.channels * sizeof(float));
398 if (!tmpFrames) return;
399
400 sf_readf_float(file, tmpFrames, info.frames);
401 sf_close(file);
402
403 tmpResamples = 0;
404
405 if (info.samplerate != m_sampleRate) {
406
407 double ratio = (double)m_sampleRate / (double)info.samplerate;
408 size_t target = (size_t)(info.frames * ratio);
409 SRC_DATA data;
410
411 tmpResamples = (float *)malloc(target * info.channels * sizeof(float));
412 if (!tmpResamples) {
413 free(tmpFrames);
414 return;
415 }
416
417 memset(tmpResamples, 0, target * info.channels * sizeof(float));
418
419 data.data_in = tmpFrames;
420 data.data_out = tmpResamples;
421 data.input_frames = info.frames;
422 data.output_frames = target;
423 data.src_ratio = ratio;
424
425 if (!src_simple(&data, SRC_SINC_BEST_QUALITY, info.channels)) {
426 free(tmpFrames);
427 tmpFrames = tmpResamples;
428 samples = target;
429 } else {
430 free(tmpResamples);
431 }
432 }
433
434 /* add an extra sample for linear interpolation */
435 tmpSamples = (float *)malloc((samples + 1) * sizeof(float));
436 if (!tmpSamples) {
437 free(tmpFrames);
438 return;
439 }
440
441 for (i = 0; i < samples; ++i) {
442 int j;
443 tmpSamples[i] = 0.0f;
444 for (j = 0; j < info.channels; ++j) {
445 tmpSamples[i] += tmpFrames[i * info.channels + j];
446 }
447 }
448
449 free(tmpFrames);
450
451 /* add an extra sample for linear interpolation */
452 tmpSamples[samples] = 0.0f;
453
454 QMutexLocker locker(&m_mutex);
455
456 tmpOld = m_sampleData;
457 m_sampleData = tmpSamples;
458 m_sampleCount = samples;
459
460 for (i = 0; i < Polyphony; ++i) {
461 m_ons[i] = -1;
462 m_offs[i] = -1;
463 m_velocities[i] = 0;
464 }
465
466 if (tmpOld) free(tmpOld);
467
468 printf("%s: loaded %s (%ld samples from original %ld channels resampled from %ld frames at %ld Hz)\n", "sampler", path.toLocal8Bit().data(), (long)samples, (long)info.channels, (long)info.frames, (long)info.samplerate);
469 }
470
471 void
472 SamplePlayer::runImpl(unsigned long sampleCount,
473 snd_seq_event_t *events,
474 unsigned long eventCount)
475 {
476 unsigned long pos;
477 unsigned long count;
478 unsigned long event_pos;
479 int i;
480
481 memset(m_output, 0, sampleCount * sizeof(float));
482
483 if (!m_mutex.tryLock()) return;
484
485 if (!m_sampleData || !m_sampleCount) {
486 m_sampleNo += sampleCount;
487 m_mutex.unlock();
488 return;
489 }
490
491 for (pos = 0, event_pos = 0; pos < sampleCount; ) {
492
493 while (event_pos < eventCount
494 && pos >= events[event_pos].time.tick) {
495
496 if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
497 snd_seq_ev_note_t n = events[event_pos].data.note;
498 if (n.velocity > 0) {
499 m_ons[n.note] =
500 m_sampleNo + events[event_pos].time.tick;
501 m_offs[n.note] = -1;
502 m_velocities[n.note] = n.velocity;
503 } else {
504 if (!m_sustain || (*m_sustain < 0.001)) {
505 m_offs[n.note] =
506 m_sampleNo + events[event_pos].time.tick;
507 }
508 }
509 } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF &&
510 (!m_sustain || (*m_sustain < 0.001))) {
511 snd_seq_ev_note_t n = events[event_pos].data.note;
512 m_offs[n.note] =
513 m_sampleNo + events[event_pos].time.tick;
514 }
515
516 ++event_pos;
517 }
518
519 count = sampleCount - pos;
520 if (event_pos < eventCount &&
521 events[event_pos].time.tick < sampleCount) {
522 count = events[event_pos].time.tick - pos;
523 }
524
525 for (i = 0; i < Polyphony; ++i) {
526 if (m_ons[i] >= 0) {
527 addSample(i, pos, count);
528 }
529 }
530
531 pos += count;
532 }
533
534 m_sampleNo += sampleCount;
535 m_mutex.unlock();
536 }
537
538 void
539 SamplePlayer::addSample(int n, unsigned long pos, unsigned long count)
540 {
541 float ratio = 1.f;
542 float gain = 1.f;
543 unsigned long i, s;
544
545 if (m_retune && *m_retune) {
546 if (m_concertA) {
547 ratio *= *m_concertA / 440.f;
548 }
549 if (m_basePitch && n != *m_basePitch) {
550 ratio *= powf(1.059463094f, n - *m_basePitch);
551 }
552 }
553
554 if (long(pos + m_sampleNo) < m_ons[n]) return;
555
556 gain = (float)m_velocities[n] / 127.0f;
557
558 for (i = 0, s = pos + m_sampleNo - m_ons[n];
559 i < count;
560 ++i, ++s) {
561
562 float lgain = gain;
563 float rs = s * ratio;
564 unsigned long rsi = lrintf(floor(rs));
565
566 if (rsi >= m_sampleCount) {
567 m_ons[n] = -1;
568 break;
569 }
570
571 if (m_offs[n] >= 0 &&
572 long(pos + i + m_sampleNo) > m_offs[n]) {
573
574 unsigned long dist =
575 pos + i + m_sampleNo - m_offs[n];
576
577 unsigned long releaseFrames = 200;
578 if (m_release) {
579 releaseFrames = long(*m_release * m_sampleRate + 0.0001);
580 }
581
582 if (dist > releaseFrames) {
583 m_ons[n] = -1;
584 break;
585 } else {
586 lgain = lgain * (float)(releaseFrames - dist) /
587 (float)releaseFrames;
588 }
589 }
590
591 float sample = m_sampleData[rsi] +
592 ((m_sampleData[rsi + 1] -
593 m_sampleData[rsi]) *
594 (rs - (float)rsi));
595
596 m_output[pos + i] += lgain * sample;
597 }
598 }