SamplePlayer.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     
00008     This program is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.  See the file
00012     COPYING included with this distribution for more information.
00013 */
00014 
00015 /*
00016     Based on trivial_sampler from the DSSI distribution
00017     (by Chris Cannam, public domain).
00018 */
00019 
00020 #include "SamplePlayer.h"
00021 
00022 #include <dssi.h>
00023 #include <cmath>
00024 
00025 #include <QMutexLocker>
00026 #include <QDir>
00027 #include <QFileInfo>
00028 
00029 #include <sndfile.h>
00030 #include <samplerate.h>
00031 #include <iostream>
00032 
00033 const char *const
00034 SamplePlayer::portNames[PortCount] =
00035 {
00036     "Output",
00037     "Tuned (on/off)",
00038     "Base Pitch (MIDI)",
00039     "Tuning of A (Hz)",
00040     "Sustain (on/off)",
00041     "Release time (s)"
00042 };
00043 
00044 const LADSPA_PortDescriptor 
00045 SamplePlayer::ports[PortCount] =
00046 {
00047     LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
00048     LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
00049     LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
00050     LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
00051     LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL
00052 };
00053 
00054 const LADSPA_PortRangeHint 
00055 SamplePlayer::hints[PortCount] =
00056 {
00057     { 0, 0, 0 },
00058     { LADSPA_HINT_DEFAULT_MAXIMUM | LADSPA_HINT_INTEGER |
00059       LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
00060     { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER |
00061       LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 120 },
00062     { LADSPA_HINT_DEFAULT_440 | LADSPA_HINT_LOGARITHMIC |
00063       LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 400, 499 },
00064     { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_INTEGER |
00065       LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 1 },
00066     { LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_LOGARITHMIC |
00067       LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0.001, 2.0 }
00068 };
00069 
00070 const LADSPA_Properties
00071 SamplePlayer::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
00072 
00073 const LADSPA_Descriptor 
00074 SamplePlayer::ladspaDescriptor =
00075 {
00076     0, // "Unique" ID
00077     "sample_player", // Label
00078     properties,
00079     "Library Sample Player", // Name
00080     "Chris Cannam", // Maker
00081     "GPL", // Copyright
00082     PortCount,
00083     ports,
00084     portNames,
00085     hints,
00086     0, // Implementation data
00087     instantiate,
00088     connectPort,
00089     activate,
00090     run,
00091     0, // Run adding
00092     0, // Set run adding gain
00093     deactivate,
00094     cleanup
00095 };
00096 
00097 const DSSI_Descriptor 
00098 SamplePlayer::dssiDescriptor =
00099 {
00100     2, // DSSI API version
00101     &ladspaDescriptor,
00102     configure,
00103     getProgram,
00104     selectProgram,
00105     getMidiController,
00106     runSynth,
00107     0, // Run synth adding
00108     0, // Run multiple synths
00109     0, // Run multiple synths adding
00110     receiveHostDescriptor
00111 };
00112 
00113 const DSSI_Host_Descriptor *
00114 SamplePlayer::hostDescriptor = 0;
00115 
00116 
00117 const DSSI_Descriptor *
00118 SamplePlayer::getDescriptor(unsigned long index)
00119 {
00120     if (index == 0) return &dssiDescriptor;
00121     return 0;
00122 }
00123 
00124 SamplePlayer::SamplePlayer(int sampleRate) :
00125     m_output(0),
00126     m_retune(0),
00127     m_basePitch(0),
00128     m_concertA(0),
00129     m_sustain(0),
00130     m_release(0),
00131     m_sampleData(0),
00132     m_sampleCount(0),
00133     m_sampleRate(sampleRate),
00134     m_sampleNo(0),
00135     m_sampleDir("samples"),
00136     m_sampleSearchComplete(false),
00137     m_pendingProgramChange(-1)
00138 {
00139 }
00140 
00141 SamplePlayer::~SamplePlayer()
00142 {
00143     if (m_sampleData) free(m_sampleData);
00144 }
00145     
00146 LADSPA_Handle
00147 SamplePlayer::instantiate(const LADSPA_Descriptor *, unsigned long rate)
00148 {
00149     if (!hostDescriptor || !hostDescriptor->request_non_rt_thread) {
00150         std::cerr << "SamplePlayer::instantiate: Host does not provide request_non_rt_thread, not instantiating" << std::endl;
00151         return 0;
00152     }
00153 
00154     SamplePlayer *player = new SamplePlayer(rate);
00155 
00156     if (hostDescriptor->request_non_rt_thread(player, workThreadCallback)) {
00157         std::cerr << "SamplePlayer::instantiate: Host rejected request_non_rt_thread call, not instantiating" << std::endl;
00158         delete player;
00159         return 0;
00160     }
00161 
00162     return player;
00163 }
00164 
00165 void
00166 SamplePlayer::connectPort(LADSPA_Handle handle,
00167                           unsigned long port, LADSPA_Data *location)
00168 {
00169     SamplePlayer *player = (SamplePlayer *)handle;
00170 
00171     float **ports[PortCount] = {
00172         &player->m_output,
00173         &player->m_retune,
00174         &player->m_basePitch,
00175         &player->m_concertA,
00176         &player->m_sustain,
00177         &player->m_release
00178     };
00179 
00180     *ports[port] = (float *)location;
00181 }
00182 
00183 void
00184 SamplePlayer::activate(LADSPA_Handle handle)
00185 {
00186     SamplePlayer *player = (SamplePlayer *)handle;
00187     QMutexLocker locker(&player->m_mutex);
00188 
00189     player->m_sampleNo = 0;
00190 
00191     for (size_t i = 0; i < Polyphony; ++i) {
00192         player->m_ons[i] = -1;
00193         player->m_offs[i] = -1;
00194         player->m_velocities[i] = 0;
00195     }
00196 }
00197 
00198 void
00199 SamplePlayer::run(LADSPA_Handle handle, unsigned long samples)
00200 {
00201     runSynth(handle, samples, 0, 0);
00202 }
00203 
00204 void
00205 SamplePlayer::deactivate(LADSPA_Handle handle)
00206 {
00207     activate(handle); // both functions just reset the plugin
00208 }
00209 
00210 void
00211 SamplePlayer::cleanup(LADSPA_Handle handle)
00212 {
00213     delete (SamplePlayer *)handle;
00214 }
00215 
00216 char *
00217 SamplePlayer::configure(LADSPA_Handle handle, const char *key, const char *value)
00218 {
00219     if (key && !strcmp(key, "sampledir")) {
00220 
00221         SamplePlayer *player = (SamplePlayer *)handle;
00222 
00223         QMutexLocker locker(&player->m_mutex);
00224 
00225         if (QFileInfo(value).exists() &&
00226             QFileInfo(value).isDir()) {
00227 
00228             player->m_sampleDir = value;
00229 
00230             if (player->m_sampleSearchComplete) {
00231                 player->m_sampleSearchComplete = false;
00232                 player->searchSamples();
00233             }
00234 
00235             return 0;
00236 
00237         } else {
00238             char *buffer = (char *)malloc(strlen(value) + 80);
00239             sprintf(buffer, "Sample directory \"%s\" does not exist, leaving unchanged", value);
00240             return buffer;
00241         }
00242     }
00243 
00244     return strdup("Unknown configure key");
00245 }
00246 
00247 const DSSI_Program_Descriptor *
00248 SamplePlayer::getProgram(LADSPA_Handle handle, unsigned long program)
00249 {
00250     SamplePlayer *player = (SamplePlayer *)handle;
00251 
00252     if (!player->m_sampleSearchComplete) {
00253         QMutexLocker locker(&player->m_mutex);
00254         if (!player->m_sampleSearchComplete) {
00255             player->searchSamples();
00256         }
00257     }
00258     if (program >= player->m_samples.size()) return 0;
00259 
00260     static DSSI_Program_Descriptor descriptor;
00261     static char name[60];
00262 
00263     strncpy(name, player->m_samples[program].first.toLocal8Bit().data(), 60);
00264     name[59] = '\0';
00265 
00266     descriptor.Bank = 0;
00267     descriptor.Program = program;
00268     descriptor.Name = name;
00269 
00270     return &descriptor;
00271 }
00272 
00273 void
00274 SamplePlayer::selectProgram(LADSPA_Handle handle,
00275                             unsigned long,
00276                             unsigned long program)
00277 {
00278     SamplePlayer *player = (SamplePlayer *)handle;
00279     player->m_pendingProgramChange = program;
00280 }
00281 
00282 int
00283 SamplePlayer::getMidiController(LADSPA_Handle, unsigned long port)
00284 {
00285     int controllers[PortCount] = {
00286         DSSI_NONE,
00287         DSSI_CC(12),
00288         DSSI_CC(13),
00289         DSSI_CC(64),
00290         DSSI_CC(72)
00291     };
00292 
00293     return controllers[port];
00294 }
00295 
00296 void
00297 SamplePlayer::runSynth(LADSPA_Handle handle, unsigned long samples,
00298                        snd_seq_event_t *events, unsigned long eventCount)
00299 {
00300     SamplePlayer *player = (SamplePlayer *)handle;
00301 
00302     player->runImpl(samples, events, eventCount);
00303 }
00304 
00305 void
00306 SamplePlayer::receiveHostDescriptor(const DSSI_Host_Descriptor *descriptor)
00307 {
00308     hostDescriptor = descriptor;
00309 }
00310 
00311 void
00312 SamplePlayer::workThreadCallback(LADSPA_Handle handle)
00313 {
00314     SamplePlayer *player = (SamplePlayer *)handle;
00315 
00316     if (player->m_pendingProgramChange >= 0) {
00317 
00318 //      std::cerr << "SamplePlayer::workThreadCallback: pending program change " << player->m_pendingProgramChange << std::endl;
00319 
00320         player->m_mutex.lock();
00321 
00322         int program = player->m_pendingProgramChange;
00323         player->m_pendingProgramChange = -1;
00324 
00325         if (!player->m_sampleSearchComplete) {
00326             player->searchSamples();
00327         }
00328         
00329         if (program < int(player->m_samples.size())) {
00330             QString path = player->m_samples[program].second;
00331             QString programName = player->m_samples[program].first;
00332             if (programName != player->m_program) {
00333                 player->m_program = programName;
00334                 player->m_mutex.unlock();
00335                 player->loadSampleData(path);
00336             } else {
00337                 player->m_mutex.unlock();
00338             }
00339         }
00340     }
00341 
00342     if (!player->m_sampleSearchComplete) {
00343 
00344         QMutexLocker locker(&player->m_mutex);
00345 
00346         if (!player->m_sampleSearchComplete) {
00347             player->searchSamples();
00348         }
00349     }
00350 }
00351 
00352 void
00353 SamplePlayer::searchSamples()
00354 {
00355     if (m_sampleSearchComplete) return;
00356 
00357     m_samples.clear();
00358 
00359     std::cerr << "SamplePlayer::searchSamples: Directory is \""
00360               << m_sampleDir.toLocal8Bit().data() << "\"" << std::endl;
00361 
00362     QDir dir(m_sampleDir, "*.wav");
00363     
00364     for (unsigned int i = 0; i < dir.count(); ++i) {
00365         QFileInfo file(dir.filePath(dir[i]));
00366         if (file.isReadable()) {
00367             m_samples.push_back(std::pair<QString, QString>
00368                                 (file.baseName(), file.filePath()));
00369 //            std::cerr << "Found: " << dir[i].toLocal8Bit().data() << std::endl;
00370         }
00371     }
00372     
00373     m_sampleSearchComplete = true;
00374 }
00375 
00376 void
00377 SamplePlayer::loadSampleData(QString path)
00378 {
00379     SF_INFO info;
00380     SNDFILE *file;
00381     size_t samples = 0;
00382     float *tmpFrames, *tmpSamples, *tmpResamples, *tmpOld;
00383     size_t i;
00384 
00385     info.format = 0;
00386     file = sf_open(path.toLocal8Bit().data(), SFM_READ, &info);
00387     if (!file) {
00388         std::cerr << "SamplePlayer::loadSampleData: Failed to open file "
00389                   << path.toLocal8Bit().data() << ": "
00390                   << sf_strerror(file) << std::endl;
00391         return;
00392     }
00393     
00394     samples = info.frames;
00395     tmpFrames = (float *)malloc(info.frames * info.channels * sizeof(float));
00396     if (!tmpFrames) return;
00397 
00398     sf_readf_float(file, tmpFrames, info.frames);
00399     sf_close(file);
00400 
00401     tmpResamples = 0;
00402 
00403     if (info.samplerate != m_sampleRate) {
00404         
00405         double ratio = (double)m_sampleRate / (double)info.samplerate;
00406         size_t target = (size_t)(info.frames * ratio);
00407         SRC_DATA data;
00408 
00409         tmpResamples = (float *)malloc(target * info.channels * sizeof(float));
00410         if (!tmpResamples) {
00411             free(tmpFrames);
00412             return;
00413         }
00414 
00415         memset(tmpResamples, 0, target * info.channels * sizeof(float));
00416 
00417         data.data_in = tmpFrames;
00418         data.data_out = tmpResamples;
00419         data.input_frames = info.frames;
00420         data.output_frames = target;
00421         data.src_ratio = ratio;
00422 
00423         if (!src_simple(&data, SRC_SINC_BEST_QUALITY, info.channels)) {
00424             free(tmpFrames);
00425             tmpFrames = tmpResamples;
00426             samples = target;
00427         } else {
00428             free(tmpResamples);
00429         }
00430     }
00431 
00432     /* add an extra sample for linear interpolation */
00433     tmpSamples = (float *)malloc((samples + 1) * sizeof(float));
00434     if (!tmpSamples) {
00435         free(tmpFrames);
00436         return;
00437     }
00438 
00439     for (i = 0; i < samples; ++i) {
00440         int j;
00441         tmpSamples[i] = 0.0f;
00442         for (j = 0; j < info.channels; ++j) {
00443             tmpSamples[i] += tmpFrames[i * info.channels + j];
00444         }
00445     }
00446 
00447     free(tmpFrames);
00448 
00449     /* add an extra sample for linear interpolation */
00450     tmpSamples[samples] = 0.0f;
00451     
00452     QMutexLocker locker(&m_mutex);
00453 
00454     tmpOld = m_sampleData;
00455     m_sampleData = tmpSamples;
00456     m_sampleCount = samples;
00457 
00458     for (i = 0; i < Polyphony; ++i) {
00459         m_ons[i] = -1;
00460         m_offs[i] = -1;
00461         m_velocities[i] = 0;
00462     }
00463 
00464     if (tmpOld) free(tmpOld);
00465 
00466     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);
00467 }
00468 
00469 void
00470 SamplePlayer::runImpl(unsigned long sampleCount,
00471                       snd_seq_event_t *events,
00472                       unsigned long eventCount)
00473 {
00474     unsigned long pos;
00475     unsigned long count;
00476     unsigned long event_pos;
00477     int i;
00478 
00479     memset(m_output, 0, sampleCount * sizeof(float));
00480 
00481     if (!m_mutex.tryLock()) return;
00482 
00483     if (!m_sampleData || !m_sampleCount) {
00484         m_sampleNo += sampleCount;
00485         m_mutex.unlock();
00486         return;
00487     }
00488 
00489     for (pos = 0, event_pos = 0; pos < sampleCount; ) {
00490 
00491         while (event_pos < eventCount
00492                && pos >= events[event_pos].time.tick) {
00493 
00494             if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
00495                 snd_seq_ev_note_t n = events[event_pos].data.note;
00496                 if (n.velocity > 0) {
00497                     m_ons[n.note] =
00498                         m_sampleNo + events[event_pos].time.tick;
00499                     m_offs[n.note] = -1;
00500                     m_velocities[n.note] = n.velocity;
00501                 } else {
00502                     if (!m_sustain || (*m_sustain < 0.001)) {
00503                         m_offs[n.note] = 
00504                             m_sampleNo + events[event_pos].time.tick;
00505                     }
00506                 }
00507             } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF &&
00508                        (!m_sustain || (*m_sustain < 0.001))) {
00509                 snd_seq_ev_note_t n = events[event_pos].data.note;
00510                 m_offs[n.note] = 
00511                     m_sampleNo + events[event_pos].time.tick;
00512             }
00513 
00514             ++event_pos;
00515         }
00516 
00517         count = sampleCount - pos;
00518         if (event_pos < eventCount &&
00519             events[event_pos].time.tick < sampleCount) {
00520             count = events[event_pos].time.tick - pos;
00521         }
00522 
00523         for (i = 0; i < Polyphony; ++i) {
00524             if (m_ons[i] >= 0) {
00525                 addSample(i, pos, count);
00526             }
00527         }
00528 
00529         pos += count;
00530     }
00531 
00532     m_sampleNo += sampleCount;
00533     m_mutex.unlock();
00534 }
00535 
00536 void
00537 SamplePlayer::addSample(int n, unsigned long pos, unsigned long count)
00538 {
00539     float ratio = 1.f;
00540     float gain = 1.f;
00541     unsigned long i, s;
00542 
00543     if (m_retune && *m_retune) {
00544         if (m_concertA) {
00545             ratio *= *m_concertA / 440.f;
00546         }
00547         if (m_basePitch && n != *m_basePitch) {
00548             ratio *= powf(1.059463094f, n - *m_basePitch);
00549         }
00550     }
00551 
00552     if (long(pos + m_sampleNo) < m_ons[n]) return;
00553 
00554     gain = (float)m_velocities[n] / 127.0f;
00555 
00556     for (i = 0, s = pos + m_sampleNo - m_ons[n];
00557          i < count;
00558          ++i, ++s) {
00559 
00560         float         lgain = gain;
00561         float         rs = s * ratio;
00562         unsigned long rsi = lrintf(floor(rs));
00563 
00564         if (rsi >= m_sampleCount) {
00565             m_ons[n] = -1;
00566             break;
00567         }
00568 
00569         if (m_offs[n] >= 0 &&
00570             long(pos + i + m_sampleNo) > m_offs[n]) {
00571 
00572             unsigned long dist =
00573                 pos + i + m_sampleNo - m_offs[n];
00574 
00575             unsigned long releaseFrames = 200;
00576             if (m_release) {
00577                 releaseFrames = long(*m_release * m_sampleRate + 0.0001);
00578             }
00579 
00580             if (dist > releaseFrames) {
00581                 m_ons[n] = -1;
00582                 break;
00583             } else {
00584                 lgain = lgain * (float)(releaseFrames - dist) /
00585                     (float)releaseFrames;
00586             }
00587         }
00588         
00589         float sample = m_sampleData[rsi] +
00590             ((m_sampleData[rsi + 1] -
00591               m_sampleData[rsi]) *
00592              (rs - (float)rsi));
00593 
00594         m_output[pos + i] += lgain * sample;
00595     }
00596 }

Generated on Wed Feb 20 15:45:28 2008 for SonicVisualiser by  doxygen 1.5.1