23 #include "../api/dssi.h" 28 #include <QMutexLocker> 34 #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 38 #include <samplerate.h> 54 const LADSPA_PortDescriptor
57 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
58 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
59 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
60 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
61 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL
64 const LADSPA_PortRangeHint
68 { LADSPA_HINT_DEFAULT_MAXIMUM | LADSPA_HINT_INTEGER |
69 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
70 { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER |
71 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 120 },
72 { LADSPA_HINT_DEFAULT_440 | LADSPA_HINT_LOGARITHMIC |
73 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 400, 499 },
74 { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_INTEGER |
75 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
76 { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_LOGARITHMIC |
77 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0.001f, 2.0f }
80 const LADSPA_Properties
83 const LADSPA_Descriptor
89 "Library Sample Player",
107 const DSSI_Descriptor
120 receiveHostDescriptor
123 const DSSI_Host_Descriptor *
127 const DSSI_Descriptor *
160 SVDEBUG <<
"SamplePlayer::instantiate: Host does not provide request_non_rt_thread, not instantiating" << endl;
168 SVDEBUG <<
"SamplePlayer::instantiate: Host rejected request_non_rt_thread call, not instantiating" << endl;
178 unsigned long port, LADSPA_Data *location)
191 *ports[port] = (
float *)location;
198 QMutexLocker locker(&player->
m_mutex);
203 player->
m_ons[i] = -1;
212 runSynth(handle, samples,
nullptr, 0);
230 if (key && !strcmp(key,
"sampledir")) {
234 QMutexLocker locker(&player->
m_mutex);
236 if (QFileInfo(value).exists() &&
237 QFileInfo(value).isDir()) {
249 char *buffer = (
char *)malloc(strlen(value) + 80);
250 sprintf(buffer,
"Sample directory \"%s\" does not exist, leaving unchanged", value);
255 return strdup(
"Unknown configure key");
258 const DSSI_Program_Descriptor *
264 QMutexLocker locker(&player->
m_mutex);
269 if (program >= player->
m_samples.size())
return nullptr;
271 static DSSI_Program_Descriptor descriptor;
272 static char name[60];
274 strncpy(name, player->
m_samples[program].first.toLocal8Bit().data(), 59);
278 descriptor.Program = program;
279 descriptor.Name = name;
287 unsigned long program)
304 return controllers[port];
309 snd_seq_event_t *events,
unsigned long eventCount)
313 player->
runImpl(samples, events, eventCount);
329 #ifdef DEBUG_SAMPLE_PLAYER 342 if (program <
int(player->
m_samples.size())) {
343 QString path = player->
m_samples[program].second;
344 QString programName = player->
m_samples[program].first;
357 QMutexLocker locker(&player->
m_mutex);
372 #ifdef DEBUG_SAMPLE_PLAYER 373 SVDEBUG <<
"SamplePlayer::searchSamples: Directory is \"" 379 for (
unsigned int i = 0; i < dir.count(); ++i) {
380 QFileInfo file(dir.filePath(dir[i]));
381 if (file.isReadable()) {
382 m_samples.push_back(std::pair<QString, QString>
383 (file.baseName(), file.filePath()));
384 #ifdef DEBUG_SAMPLE_PLAYER 385 cerr <<
"Found: " << dir[i] << endl;
399 float *tmpFrames, *tmpSamples, *tmpResamples, *tmpOld;
404 file = sf_wchar_open((LPCWSTR)path.utf16(), SFM_READ, &info);
406 file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info);
409 cerr <<
"SamplePlayer::loadSampleData: Failed to open file " 411 << sf_strerror(file) << endl;
415 samples = info.frames;
416 tmpFrames = (
float *)malloc(info.frames * info.channels *
sizeof(
float));
417 if (!tmpFrames)
return;
419 sf_readf_float(file, tmpFrames, info.frames);
422 tmpResamples =
nullptr;
426 double ratio = (double)
m_sampleRate / (
double)info.samplerate;
427 size_t target = (size_t)(
double(info.frames) * ratio);
430 tmpResamples = (
float *)malloc(target * info.channels *
sizeof(
float));
436 memset(tmpResamples, 0, target * info.channels *
sizeof(
float));
438 data.data_in = tmpFrames;
439 data.data_out = tmpResamples;
440 data.input_frames = info.frames;
441 data.output_frames = target;
442 data.src_ratio = ratio;
444 if (!src_simple(&data, SRC_SINC_BEST_QUALITY, info.channels)) {
446 tmpFrames = tmpResamples;
454 tmpSamples = (
float *)malloc((samples + 1) *
sizeof(float));
460 for (i = 0; i < samples; ++i) {
462 tmpSamples[i] = 0.0f;
463 for (j = 0; j < info.channels; ++j) {
464 tmpSamples[i] += tmpFrames[i * info.channels + j];
471 tmpSamples[samples] = 0.0f;
485 if (tmpOld) free(tmpOld);
487 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);
492 snd_seq_event_t *events,
493 unsigned long eventCount)
497 unsigned long event_pos;
500 memset(
m_output, 0, sampleCount *
sizeof(
float));
502 if (!
m_mutex.tryLock())
return;
510 for (pos = 0, event_pos = 0; pos < sampleCount; ) {
512 while (event_pos < eventCount
513 && pos >= events[event_pos].time.tick) {
515 if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
516 #ifdef DEBUG_SAMPLE_PLAYER 517 cerr <<
"SamplePlayer: found NOTEON at time " 518 << events[event_pos].time.tick << endl;
520 snd_seq_ev_note_t n = events[event_pos].data.note;
521 if (n.velocity > 0) {
532 }
else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF &&
534 #ifdef DEBUG_SAMPLE_PLAYER 535 cerr <<
"SamplePlayer: found NOTEOFF at time " 536 << events[event_pos].time.tick << endl;
538 snd_seq_ev_note_t n = events[event_pos].data.note;
546 count = sampleCount - pos;
547 if (event_pos < eventCount &&
548 events[event_pos].time.tick < sampleCount) {
549 count = events[event_pos].time.tick - pos;
561 #ifdef DEBUG_SAMPLE_PLAYER 562 cerr <<
"SamplePlayer: have " << notecount <<
" note(s) sounding currently" << endl;
584 ratio *= powf(1.059463094f,
float(n) - *
m_basePitch);
597 float rs = float(s) * ratio;
598 unsigned long rsi = lrintf(floorf(rs));
601 #ifdef DEBUG_SAMPLE_PLAYER 602 cerr <<
"Note " << n <<
" has run out of samples (were " <<
m_sampleCount <<
" available at ratio " << ratio <<
"), ending" << endl;
614 unsigned long releaseFrames = 200;
619 if (dist > releaseFrames) {
620 #ifdef DEBUG_SAMPLE_PLAYER 621 cerr <<
"Note " << n <<
" has expired its release time (" << releaseFrames <<
" frames), ending" << endl;
626 lgain = lgain * (float)(releaseFrames - dist) /
627 (float)releaseFrames;
636 m_output[pos + i] += lgain * sample;
static void run(LADSPA_Handle, unsigned long)
void loadSampleData(QString path)
void addSample(int, unsigned long, unsigned long)
void runImpl(unsigned long, snd_seq_event_t *, unsigned long)
std::vector< std::pair< QString, QString > > m_samples
static void deactivate(LADSPA_Handle)
static char * configure(LADSPA_Handle, const char *, const char *)
static void selectProgram(LADSPA_Handle, unsigned long, unsigned long)
static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long)
SamplePlayer(int sampleRate)
static const DSSI_Descriptor * getDescriptor(unsigned long index)
static const LADSPA_PortDescriptor ports[PortCount]
static const char *const portNames[PortCount]
int m_velocities[Polyphony]
static void runSynth(LADSPA_Handle, unsigned long, snd_seq_event_t *, unsigned long)
static void workThreadCallback(LADSPA_Handle)
static const DSSI_Host_Descriptor * hostDescriptor
static const LADSPA_PortRangeHint hints[PortCount]
static void activate(LADSPA_Handle)
static const LADSPA_Properties properties
static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *)
static const DSSI_Program_Descriptor * getProgram(LADSPA_Handle, unsigned long)
static void receiveHostDescriptor(const DSSI_Host_Descriptor *descriptor)
bool m_sampleSearchComplete
static const LADSPA_Descriptor ladspaDescriptor
int m_pendingProgramChange
static int getMidiController(LADSPA_Handle, unsigned long)
static const DSSI_Descriptor dssiDescriptor
static void cleanup(LADSPA_Handle)