23 #include "../api/dssi.h" 28 #include <QMutexLocker> 33 #include <samplerate.h> 49 const LADSPA_PortDescriptor
52 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
53 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
54 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
55 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
56 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL
59 const LADSPA_PortRangeHint
63 { LADSPA_HINT_DEFAULT_MAXIMUM | LADSPA_HINT_INTEGER |
64 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
65 { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER |
66 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 120 },
67 { LADSPA_HINT_DEFAULT_440 | LADSPA_HINT_LOGARITHMIC |
68 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 400, 499 },
69 { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_INTEGER |
70 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
71 { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_LOGARITHMIC |
72 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0.001, 2.0 }
75 const LADSPA_Properties
78 const LADSPA_Descriptor
84 "Library Sample Player",
102 const DSSI_Descriptor
115 receiveHostDescriptor
118 const DSSI_Host_Descriptor *
122 const DSSI_Descriptor *
138 m_sampleRate(sampleRate),
140 m_sampleDir(
"samples"),
141 m_sampleSearchComplete(false),
142 m_pendingProgramChange(-1)
155 SVDEBUG <<
"SamplePlayer::instantiate: Host does not provide request_non_rt_thread, not instantiating" << endl;
163 SVDEBUG <<
"SamplePlayer::instantiate: Host rejected request_non_rt_thread call, not instantiating" << endl;
173 unsigned long port, LADSPA_Data *location)
186 *
ports[port] = (
float *)location;
193 QMutexLocker locker(&player->
m_mutex);
198 player->
m_ons[i] = -1;
225 if (key && !strcmp(key,
"sampledir")) {
229 QMutexLocker locker(&player->
m_mutex);
231 if (QFileInfo(value).exists() &&
232 QFileInfo(value).isDir()) {
244 char *buffer = (
char *)malloc(strlen(value) + 80);
245 sprintf(buffer,
"Sample directory \"%s\" does not exist, leaving unchanged", value);
250 return strdup(
"Unknown configure key");
253 const DSSI_Program_Descriptor *
259 QMutexLocker locker(&player->
m_mutex);
264 if (program >= player->
m_samples.size())
return 0;
266 static DSSI_Program_Descriptor descriptor;
267 static char name[60];
269 strncpy(name, player->
m_samples[program].first.toLocal8Bit().data(), 60);
273 descriptor.Program = program;
274 descriptor.Name = name;
282 unsigned long program)
299 return controllers[port];
304 snd_seq_event_t *events,
unsigned long eventCount)
308 player->
runImpl(samples, events, eventCount);
324 #ifdef DEBUG_SAMPLE_PLAYER 337 if (program <
int(player->
m_samples.size())) {
338 QString path = player->
m_samples[program].second;
339 QString programName = player->
m_samples[program].first;
352 QMutexLocker locker(&player->
m_mutex);
367 #ifdef DEBUG_SAMPLE_PLAYER 368 SVDEBUG <<
"SamplePlayer::searchSamples: Directory is \"" 374 for (
unsigned int i = 0; i < dir.count(); ++i) {
375 QFileInfo file(dir.filePath(dir[i]));
376 if (file.isReadable()) {
377 m_samples.push_back(std::pair<QString, QString>
378 (file.baseName(), file.filePath()));
379 #ifdef DEBUG_SAMPLE_PLAYER 380 cerr <<
"Found: " << dir[i] << endl;
394 float *tmpFrames, *tmpSamples, *tmpResamples, *tmpOld;
398 file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info);
400 cerr <<
"SamplePlayer::loadSampleData: Failed to open file " 402 << sf_strerror(file) << endl;
406 samples = info.frames;
407 tmpFrames = (
float *)malloc(info.frames * info.channels *
sizeof(
float));
408 if (!tmpFrames)
return;
410 sf_readf_float(file, tmpFrames, info.frames);
417 double ratio = (double)
m_sampleRate / (
double)info.samplerate;
418 size_t target = (size_t)(info.frames * ratio);
421 tmpResamples = (
float *)malloc(target * info.channels *
sizeof(
float));
427 memset(tmpResamples, 0, target * info.channels *
sizeof(
float));
429 data.data_in = tmpFrames;
430 data.data_out = tmpResamples;
431 data.input_frames = info.frames;
432 data.output_frames = target;
433 data.src_ratio = ratio;
435 if (!src_simple(&data, SRC_SINC_BEST_QUALITY, info.channels)) {
437 tmpFrames = tmpResamples;
445 tmpSamples = (
float *)malloc((samples + 1) *
sizeof(float));
451 for (i = 0; i < samples; ++i) {
453 tmpSamples[i] = 0.0f;
454 for (j = 0; j < info.channels; ++j) {
455 tmpSamples[i] += tmpFrames[i * info.channels + j];
462 tmpSamples[samples] = 0.0f;
476 if (tmpOld) free(tmpOld);
478 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);
483 snd_seq_event_t *events,
484 unsigned long eventCount)
488 unsigned long event_pos;
491 memset(
m_output, 0, sampleCount *
sizeof(
float));
493 if (!
m_mutex.tryLock())
return;
501 for (pos = 0, event_pos = 0; pos < sampleCount; ) {
503 while (event_pos < eventCount
504 && pos >= events[event_pos].time.tick) {
506 if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
507 #ifdef DEBUG_SAMPLE_PLAYER 508 cerr <<
"SamplePlayer: found NOTEON at time " 509 << events[event_pos].time.tick << endl;
511 snd_seq_ev_note_t n = events[event_pos].data.note;
512 if (n.velocity > 0) {
523 }
else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF &&
525 #ifdef DEBUG_SAMPLE_PLAYER 526 cerr <<
"SamplePlayer: found NOTEOFF at time " 527 << events[event_pos].time.tick << endl;
529 snd_seq_ev_note_t n = events[event_pos].data.note;
537 count = sampleCount - pos;
538 if (event_pos < eventCount &&
539 events[event_pos].time.tick < sampleCount) {
540 count = events[event_pos].time.tick - pos;
552 #ifdef DEBUG_SAMPLE_PLAYER 553 cerr <<
"SamplePlayer: have " << notecount <<
" note(s) sounding currently" << endl;
588 float rs = s * ratio;
589 unsigned long rsi = lrintf(floor(rs));
592 #ifdef DEBUG_SAMPLE_PLAYER 593 cerr <<
"Note " << n <<
" has run out of samples (were " <<
m_sampleCount <<
" available at ratio " << ratio <<
"), ending" << endl;
605 unsigned long releaseFrames = 200;
610 if (dist > releaseFrames) {
611 #ifdef DEBUG_SAMPLE_PLAYER 612 cerr <<
"Note " << n <<
" has expired its release time (" << releaseFrames <<
" frames), ending" << endl;
617 lgain = lgain * (float)(releaseFrames - dist) /
618 (float)releaseFrames;
627 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)