@@ -73,7 +73,7 @@ void SamplerDevice::processMidiNoteOn(uint8_t note, uint8_t velocity)
7373{
7474 std::lock_guard<std::mutex> lock { m_mutex };
7575
76- if (note >= 128 || !m_samples.at (note)) {
76+ if (note >= maxSamples || !m_samples.at (note)) {
7777 return ;
7878 }
7979
@@ -91,7 +91,7 @@ void SamplerDevice::processMidiNoteOn(uint8_t note, uint8_t velocity)
9191 if (!voice.active ) {
9292 voice.note = note;
9393 voice.sample = m_samples.at (note).get ();
94- voice.position = 0.0 ;
94+ voice.position = voice. sample -> startOffset * voice. sample -> sampleRate ;
9595 voice.velocity = static_cast <float >(velocity) / 127 .0f ;
9696 voice.pan = m_globalPan;
9797 voice.volume = m_globalVolume;
@@ -157,7 +157,7 @@ void SamplerDevice::processMidiCc(uint8_t controller, uint8_t value, uint8_t cha
157157 if (m_channelMode) {
158158 // channel is 0-indexed (0-15)
159159 const size_t note = 36 + channel;
160- if (note < 128 && m_samples.at (note)) {
160+ if (note < maxSamples && m_samples.at (note)) {
161161 if (controller == 10 ) { // Panning
162162 m_samples.at (note)->pan = static_cast <float >(value) / 127 .0f ;
163163 } else if (controller == 7 ) { // Volume
@@ -329,7 +329,7 @@ void SamplerDevice::processAudio(float * output, uint32_t nFrames, uint32_t samp
329329
330330void SamplerDevice::loadSample (uint8_t note, const std::string & filePath)
331331{
332- if (note >= 128 ) {
332+ if (note >= maxSamples ) {
333333 return ;
334334 }
335335
@@ -371,7 +371,7 @@ void SamplerDevice::loadSample(uint8_t note, const std::string & filePath)
371371
372372void SamplerDevice::clearSample (uint8_t note)
373373{
374- if (note >= 128 ) {
374+ if (note >= maxSamples ) {
375375 return ;
376376 }
377377 std::lock_guard<std::mutex> lock { m_mutex };
@@ -381,15 +381,15 @@ void SamplerDevice::clearSample(uint8_t note)
381381
382382const SamplerDevice::Sample * SamplerDevice::sample (uint8_t note) const
383383{
384- if (note >= 128 ) {
384+ if (note >= maxSamples ) {
385385 return nullptr ;
386386 }
387387 return m_samples.at (note).get ();
388388}
389389
390390std::string SamplerDevice::absoluteFilePath (uint8_t note) const
391391{
392- if (note >= 128 || !m_samples.at (note)) {
392+ if (note >= maxSamples || !m_samples.at (note)) {
393393 return " " ;
394394 }
395395
@@ -404,15 +404,15 @@ std::string SamplerDevice::absoluteFilePath(uint8_t note) const
404404float SamplerDevice::samplePan (uint8_t note) const
405405{
406406 std::lock_guard<std::mutex> lock { m_mutex };
407- if (note >= 128 || !m_samples.at (note)) {
407+ if (note >= maxSamples || !m_samples.at (note)) {
408408 return 0 .5f ;
409409 }
410410 return m_samples.at (note)->pan ;
411411}
412412
413413void SamplerDevice::setSamplePan (uint8_t note, float pan)
414414{
415- if (note >= 128 ) {
415+ if (note >= maxSamples ) {
416416 return ;
417417 }
418418 std::lock_guard<std::mutex> lock { m_mutex };
@@ -431,15 +431,15 @@ void SamplerDevice::setSamplePan(uint8_t note, float pan)
431431float SamplerDevice::sampleVolume (uint8_t note) const
432432{
433433 std::lock_guard<std::mutex> lock { m_mutex };
434- if (note >= 128 || !m_samples.at (note)) {
434+ if (note >= maxSamples || !m_samples.at (note)) {
435435 return 1 .0f ;
436436 }
437437 return m_samples.at (note)->volume ;
438438}
439439
440440void SamplerDevice::setSampleVolume (uint8_t note, float volume)
441441{
442- if (note >= 128 ) {
442+ if (note >= maxSamples ) {
443443 return ;
444444 }
445445 std::lock_guard<std::mutex> lock { m_mutex };
@@ -458,15 +458,15 @@ void SamplerDevice::setSampleVolume(uint8_t note, float volume)
458458float SamplerDevice::sampleCutoff (uint8_t note) const
459459{
460460 std::lock_guard<std::mutex> lock { m_mutex };
461- if (note >= 128 || !m_samples.at (note)) {
461+ if (note >= maxSamples || !m_samples.at (note)) {
462462 return 1 .0f ;
463463 }
464464 return m_samples.at (note)->cutoff ;
465465}
466466
467467void SamplerDevice::setSampleCutoff (uint8_t note, float cutoff)
468468{
469- if (note >= 128 ) {
469+ if (note >= maxSamples ) {
470470 return ;
471471 }
472472 std::lock_guard<std::mutex> lock { m_mutex };
@@ -485,15 +485,15 @@ void SamplerDevice::setSampleCutoff(uint8_t note, float cutoff)
485485float SamplerDevice::sampleHpfCutoff (uint8_t note) const
486486{
487487 std::lock_guard<std::mutex> lock { m_mutex };
488- if (note >= 128 || !m_samples.at (note)) {
488+ if (note >= maxSamples || !m_samples.at (note)) {
489489 return 0 .0f ;
490490 }
491491 return m_samples.at (note)->hpfCutoff ;
492492}
493493
494494void SamplerDevice::setSampleHpfCutoff (uint8_t note, float cutoff)
495495{
496- if (note >= 128 ) {
496+ if (note >= maxSamples ) {
497497 return ;
498498 }
499499 std::lock_guard<std::mutex> lock { m_mutex };
@@ -509,6 +509,37 @@ void SamplerDevice::setSampleHpfCutoff(uint8_t note, float cutoff)
509509 }
510510}
511511
512+ double SamplerDevice::sampleStartOffset (uint8_t note) const
513+ {
514+ std::lock_guard<std::mutex> lock { m_mutex };
515+ if (note >= maxSamples || !m_samples.at (note)) {
516+ return 0.0 ;
517+ }
518+ return m_samples.at (note)->startOffset ;
519+ }
520+
521+ void SamplerDevice::setSampleStartOffset (uint8_t note, double offset)
522+ {
523+ if (note >= maxSamples) {
524+ return ;
525+ }
526+ std::lock_guard<std::mutex> lock { m_mutex };
527+ if (m_samples.at (note)) {
528+ m_samples.at (note)->startOffset = std::max (0.0 , offset);
529+ emit dataChanged ();
530+ }
531+ }
532+
533+ double SamplerDevice::sampleDuration (uint8_t note) const
534+ {
535+ std::lock_guard<std::mutex> lock { m_mutex };
536+ if (note >= maxSamples || !m_samples.at (note) || !m_samples.at (note)->data ) {
537+ return 0.0 ;
538+ }
539+ const auto & s = m_samples.at (note);
540+ return static_cast <double >(s->data ->size () / static_cast <size_t >(s->channels )) / static_cast <double >(s->sampleRate );
541+ }
542+
512543bool SamplerDevice::channelMode () const
513544{
514545 std::lock_guard<std::mutex> lock { m_mutex };
@@ -555,7 +586,7 @@ void SamplerDevice::serializeToXml(QXmlStreamWriter & writer) const
555586 writer.writeAttribute (Constants::NahdXml::xmlKeyId (), QString::number (id ()));
556587 writer.writeAttribute (Constants::NahdXml::xmlKeyChannelMode (), m_channelMode ? Constants::NahdXml::xmlValueTrue () : Constants::NahdXml::xmlValueFalse ());
557588
558- for (uint8_t note = 0 ; note < 128 ; note++) {
589+ for (uint8_t note = 0 ; note < maxSamples ; note++) {
559590 if (const auto & s = m_samples.at (note)) {
560591 writer.writeStartElement (Constants::NahdXml::xmlKeySample ());
561592 writer.writeAttribute (Constants::NahdXml::xmlKeyNote (), QString::number (note));
@@ -573,6 +604,7 @@ void SamplerDevice::serializeToXml(QXmlStreamWriter & writer) const
573604 writer.writeAttribute (Constants::NahdXml::xmlKeyVolume (), QString::number (std::round (s->manualVolume * 100 .0f )));
574605 writer.writeAttribute (Constants::NahdXml::xmlKeyCutoff (), QString::number (std::round (s->manualCutoff * 100 .0f )));
575606 writer.writeAttribute (Constants::NahdXml::xmlKeyHpfCutoff (), QString::number (std::round (s->manualHpfCutoff * 100 .0f )));
607+ writer.writeAttribute (Constants::NahdXml::xmlKeyStartOffset (), QString::number (std::round (s->startOffset * 1000.0 )));
576608 writer.writeEndElement ();
577609 }
578610 }
@@ -600,6 +632,7 @@ void SamplerDevice::deserializeFromXml(QXmlStreamReader & reader)
600632 const auto volume = Utils::Xml::readIntAttribute (reader, Constants::NahdXml::xmlKeyVolume (), false );
601633 const auto cutoff = Utils::Xml::readIntAttribute (reader, Constants::NahdXml::xmlKeyCutoff (), false );
602634 const auto hpfCutoff = Utils::Xml::readIntAttribute (reader, Constants::NahdXml::xmlKeyHpfCutoff (), false );
635+ const auto startOffset = Utils::Xml::readIntAttribute (reader, Constants::NahdXml::xmlKeyStartOffset (), false );
603636 if (note.has_value ()) {
604637 loadSample (static_cast <uint8_t >(note.value ()), path.toStdString ());
605638 if (pan.has_value ()) {
@@ -614,6 +647,9 @@ void SamplerDevice::deserializeFromXml(QXmlStreamReader & reader)
614647 if (hpfCutoff.has_value ()) {
615648 setSampleHpfCutoff (static_cast <uint8_t >(note.value ()), static_cast <float >(hpfCutoff.value ()) / 100 .0f );
616649 }
650+ if (startOffset.has_value ()) {
651+ setSampleStartOffset (static_cast <uint8_t >(note.value ()), static_cast <double >(startOffset.value ()) / 1000.0 );
652+ }
617653 }
618654 }
619655 reader.readNext ();
@@ -624,7 +660,7 @@ void SamplerDevice::deserializeFromXml(QXmlStreamReader & reader)
624660void SamplerDevice::saveState ()
625661{
626662 std::lock_guard<std::mutex> lock { m_mutex };
627- for (size_t i = 0 ; i < 128 ; ++i ) {
663+ for (size_t i = 0 ; i < maxSamples; i++ ) {
628664 if (m_samples.at (i)) {
629665 m_savedSamples.at (i) = std::make_unique<Sample>(*m_samples.at (i));
630666 } else {
@@ -636,7 +672,7 @@ void SamplerDevice::saveState()
636672void SamplerDevice::restoreState ()
637673{
638674 std::lock_guard<std::mutex> lock { m_mutex };
639- for (size_t i = 0 ; i < 128 ; ++i ) {
675+ for (size_t i = 0 ; i < maxSamples; i++ ) {
640676 m_samples.at (i) = std::move (m_savedSamples.at (i));
641677 m_savedSamples.at (i) = nullptr ;
642678 }
0 commit comments