@@ -44,11 +44,17 @@ SamplerDevice::SamplerDevice(std::string name, AudioFileReaderU audioFileReader)
4444 , m_audioFileReader { audioFileReader ? std::move (audioFileReader) : std::make_unique<SndFileReader>() }
4545{
4646 addParameter (Parameter { Constants::NahdXml::xmlKeyChannelMode ().toStdString (), 0 .0f , 0 , 1 , 0 , 1 });
47+ addParameter (Parameter { Constants::NahdXml::xmlKeyVolume ().toStdString (), 1 .0f , 0 , 100 , 100 , 1 });
48+ addParameter (Parameter { Constants::NahdXml::xmlKeyGain ().toStdString (), 0 .5f , -30 , 30 , 0 , 1 , false });
4749
4850 m_voices.resize (m_maxVoices);
4951 for (auto && sample : m_samples) {
5052 sample = nullptr ;
5153 }
54+
55+ m_manualGain = m_gain;
56+ m_manualGlobalVolume = m_globalVolume;
57+ syncParameters ();
5258}
5359
5460SamplerDevice::~SamplerDevice () = default ;
@@ -153,6 +159,7 @@ void SamplerDevice::processMidiCc(uint8_t controller, uint8_t value, uint8_t cha
153159 if (controller == 121 ) { // Reset All Controllers
154160 m_globalPan = m_manualGlobalPan;
155161 m_globalVolume = m_manualGlobalVolume;
162+ m_gain = m_manualGain;
156163 m_globalCutoff = m_manualGlobalCutoff;
157164 m_globalHpfCutoff = m_manualGlobalHpfCutoff;
158165
@@ -170,6 +177,9 @@ void SamplerDevice::processMidiCc(uint8_t controller, uint8_t value, uint8_t cha
170177 }
171178 }
172179
180+ if (auto p = parameter (Constants::NahdXml::xmlKeyVolume ().toStdString ()); p) p->get ().setValue (m_globalVolume);
181+ if (auto p = parameter (Constants::NahdXml::xmlKeyGain ().toStdString ()); p) p->get ().setValue (m_gain);
182+
173183 for (auto && voice : m_voices) {
174184 if (voice.active && voice.sample ) {
175185 voice.pan = m_globalPan;
@@ -226,6 +236,7 @@ void SamplerDevice::processMidiCc(uint8_t controller, uint8_t value, uint8_t cha
226236 }
227237 } else if (controller == 7 ) { // Volume
228238 m_globalVolume = static_cast <float >(value) / 127 .0f ;
239+ if (auto p = parameter (Constants::NahdXml::xmlKeyVolume ().toStdString ()); p) p->get ().setValue (m_globalVolume);
229240 // Update all active voices' volume
230241 for (auto && voice : m_voices) {
231242 if (voice.active ) {
@@ -360,8 +371,8 @@ void SamplerDevice::processAudio(float * output, uint32_t nFrames, uint32_t samp
360371 }
361372 }
362373
363- output[i * 2 ] += left;
364- output[i * 2 + 1 ] += right;
374+ output[i * 2 ] += left * m_linearGain ;
375+ output[i * 2 + 1 ] += right * m_linearGain ;
365376
366377 voice.position += pitchScale;
367378 }
@@ -380,9 +391,7 @@ void SamplerDevice::reset()
380391 voice.active = false ;
381392 }
382393
383- if (auto p = parameter (Constants::NahdXml::xmlKeyChannelMode ().toStdString ()); p) {
384- m_channelMode = p->get ().value () > 0 .5f ;
385- }
394+ syncParameters ();
386395 }
387396
388397 emit dataChanged ();
@@ -770,9 +779,7 @@ void SamplerDevice::deserializeFromXml(QXmlStreamReader & reader)
770779 {
771780 std::lock_guard<std::mutex> lock { m_mutex };
772781 // Sync global fields
773- if (auto p = parameter (Constants::NahdXml::xmlKeyChannelMode ().toStdString ()); p) {
774- m_channelMode = p->get ().value () > 0 .5f ;
775- }
782+ syncParameters ();
776783 }
777784
778785 emit dataChanged ();
@@ -808,4 +815,62 @@ void SamplerDevice::setProjectPath(const std::string & projectPath)
808815 m_projectPath = projectPath;
809816}
810817
818+ float SamplerDevice::globalVolume () const
819+ {
820+ return m_globalVolume;
821+ }
822+
823+ void SamplerDevice::setGlobalVolume (float volume)
824+ {
825+ bool changed = false ;
826+ {
827+ std::lock_guard<std::mutex> lock { m_mutex };
828+ if (auto p = parameter (Constants::NahdXml::xmlKeyVolume ().toStdString ()); p) {
829+ p->get ().setValue (volume);
830+ m_manualGlobalVolume = p->get ().value ();
831+ syncParameters ();
832+ changed = true ;
833+ }
834+ }
835+ if (changed) {
836+ emit dataChanged ();
837+ }
838+ }
839+
840+ float SamplerDevice::gain () const
841+ {
842+ return m_gain;
843+ }
844+
845+ void SamplerDevice::setGain (float gain)
846+ {
847+ bool changed = false ;
848+ {
849+ std::lock_guard<std::mutex> lock { m_mutex };
850+ if (auto p = parameter (Constants::NahdXml::xmlKeyGain ().toStdString ()); p) {
851+ p->get ().setValue (gain);
852+ m_manualGain = p->get ().value ();
853+ syncParameters ();
854+ changed = true ;
855+ }
856+ }
857+ if (changed) {
858+ emit dataChanged ();
859+ }
860+ }
861+
862+ void SamplerDevice::syncParameters ()
863+ {
864+ if (auto p = parameter (Constants::NahdXml::xmlKeyChannelMode ().toStdString ()); p) {
865+ m_channelMode = p->get ().value () > 0 .5f ;
866+ }
867+ if (auto p = parameter (Constants::NahdXml::xmlKeyVolume ().toStdString ()); p) {
868+ m_globalVolume = p->get ().value ();
869+ }
870+ if (auto p = parameter (Constants::NahdXml::xmlKeyGain ().toStdString ()); p) {
871+ m_gain = p->get ().value ();
872+ m_linearGain = std::pow (10 .0f , ((m_gain - 0 .5f ) * 60 .0f ) / 20 .0f );
873+ }
874+ }
875+
811876} // namespace noteahead
0 commit comments