annotate plugin/plugins/SamplePlayer.cpp @ 282:d9319859a4cf tip

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