diff --git a/include/Instrument.h b/include/Instrument.h index 243bdba61f6..0c28e7f3ab8 100644 --- a/include/Instrument.h +++ b/include/Instrument.h @@ -34,6 +34,9 @@ #include "Plugin.h" #include "TimePos.h" +#include + + namespace lmms { @@ -91,15 +94,26 @@ class LMMS_EXPORT Instrument : public Plugin virtual f_cnt_t beatLen( NotePlayHandle * _n ) const; - // some instruments need a certain number of release-frames even - // if no envelope is active - such instruments can re-implement this - // method for returning how many frames they at least like to have for - // release - virtual f_cnt_t desiredReleaseFrames() const + // This method can be overridden by instruments that need a certain + // release time even if no envelope is active. It returns the time + // in milliseconds that these instruments would like to have for + // their release stage. + virtual float desiredReleaseTimeMs() const + { + return 0.f; + } + + // Converts the desired release time in milliseconds to the corresponding + // number of frames depending on the sample rate. + f_cnt_t desiredReleaseFrames() const { - return 0; + const sample_rate_t sampleRate = getSampleRate(); + + return static_cast(std::ceil(desiredReleaseTimeMs() * sampleRate / 1000.f)); } + sample_rate_t getSampleRate() const; + virtual Flags flags() const { return Flag::NoFlags; @@ -142,6 +156,8 @@ class LMMS_EXPORT Instrument : public Plugin // desiredReleaseFrames() frames are left void applyRelease( sampleFrame * buf, const NotePlayHandle * _n ); + float computeReleaseTimeMsByFrameCount(f_cnt_t frames) const; + private: InstrumentTrack * m_instrumentTrack; diff --git a/plugins/AudioFileProcessor/AudioFileProcessor.h b/plugins/AudioFileProcessor/AudioFileProcessor.h index 7ade1ec4fc3..00ad9212910 100644 --- a/plugins/AudioFileProcessor/AudioFileProcessor.h +++ b/plugins/AudioFileProcessor/AudioFileProcessor.h @@ -56,9 +56,9 @@ class AudioFileProcessor : public Instrument auto beatLen(NotePlayHandle* note) const -> int override; - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return 128; + return 3.f; } gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/BitInvader/BitInvader.h b/plugins/BitInvader/BitInvader.h index 6dce9db8315..f4d248ec89f 100644 --- a/plugins/BitInvader/BitInvader.h +++ b/plugins/BitInvader/BitInvader.h @@ -85,9 +85,9 @@ class BitInvader : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return( 64 ); + return 1.5f; } gui::PluginView * instantiateView( QWidget * _parent ) override; diff --git a/plugins/FreeBoy/FreeBoy.cpp b/plugins/FreeBoy/FreeBoy.cpp index f2dc95699ed..5a5581bc06b 100644 --- a/plugins/FreeBoy/FreeBoy.cpp +++ b/plugins/FreeBoy/FreeBoy.cpp @@ -220,22 +220,10 @@ QString FreeBoyInstrument::nodeName() const -/*f_cnt_t FreeBoyInstrument::desiredReleaseFrames() const +float FreeBoyInstrument::desiredReleaseTimeMs() const { - const float samplerate = Engine::audioEngine()->processingSampleRate(); - int maxrel = 0; - for( int i = 0 ; i < 3 ; ++i ) - { - if( maxrel < m_voice[i]->m_releaseModel.value() ) - maxrel = m_voice[i]->m_releaseModel.value(); - } - - return f_cnt_t( float(relTime[maxrel])*samplerate/1000.0 ); -}*/ - -f_cnt_t FreeBoyInstrument::desiredReleaseFrames() const -{ - return f_cnt_t( 1000 ); + // Previous implementation was 1000 samples. At 44.1 kHz this is somewhat shy of 23. ms. + return 23.f; } diff --git a/plugins/FreeBoy/FreeBoy.h b/plugins/FreeBoy/FreeBoy.h index 747305414ba..501377715c1 100644 --- a/plugins/FreeBoy/FreeBoy.h +++ b/plugins/FreeBoy/FreeBoy.h @@ -62,7 +62,7 @@ class FreeBoyInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override; + float desiredReleaseTimeMs() const override; gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/GigPlayer/GigPlayer.h b/plugins/GigPlayer/GigPlayer.h index 986018654a7..85b1736a035 100644 --- a/plugins/GigPlayer/GigPlayer.h +++ b/plugins/GigPlayer/GigPlayer.h @@ -259,11 +259,6 @@ class GigInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override - { - return 0; - } - Flags flags() const override { return Flag::IsSingleStreamed | Flag::IsNotBendable; diff --git a/plugins/Kicker/Kicker.h b/plugins/Kicker/Kicker.h index b5d065598c5..820265dd556 100644 --- a/plugins/Kicker/Kicker.h +++ b/plugins/Kicker/Kicker.h @@ -69,9 +69,9 @@ class KickerInstrument : public Instrument return Flag::IsNotBendable; } - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return( 512 ); + return 12.f; } gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/Lb302/Lb302.h b/plugins/Lb302/Lb302.h index 237a3f3f8be..2f4f64dcbce 100644 --- a/plugins/Lb302/Lb302.h +++ b/plugins/Lb302/Lb302.h @@ -168,11 +168,6 @@ class Lb302Synth : public Instrument return Flag::IsSingleStreamed; } - f_cnt_t desiredReleaseFrames() const override - { - return 0; //4048; - } - gui::PluginView* instantiateView( QWidget * _parent ) override; private: diff --git a/plugins/Monstro/Monstro.cpp b/plugins/Monstro/Monstro.cpp index 3de9fbce691..65da50ea658 100644 --- a/plugins/Monstro/Monstro.cpp +++ b/plugins/Monstro/Monstro.cpp @@ -1326,13 +1326,12 @@ QString MonstroInstrument::nodeName() const return monstro_plugin_descriptor.name; } - -f_cnt_t MonstroInstrument::desiredReleaseFrames() const +float MonstroInstrument::desiredReleaseTimeMs() const { - return qMax( 64, qMax( m_env1_relF, m_env2_relF ) ); + const auto maxEnvelope = std::max(m_env1_rel, m_env2_rel); + return std::max(1.5f, maxEnvelope); } - gui::PluginView* MonstroInstrument::instantiateView( QWidget * _parent ) { return( new gui::MonstroView( this, _parent ) ); diff --git a/plugins/Monstro/Monstro.h b/plugins/Monstro/Monstro.h index 919409b2de5..0df18d5c423 100644 --- a/plugins/Monstro/Monstro.h +++ b/plugins/Monstro/Monstro.h @@ -366,7 +366,7 @@ class MonstroInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override; + float desiredReleaseTimeMs() const override; gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/Nes/Nes.h b/plugins/Nes/Nes.h index a05b3a2f85c..39e0a67192a 100644 --- a/plugins/Nes/Nes.h +++ b/plugins/Nes/Nes.h @@ -222,9 +222,9 @@ class NesInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return( 8 ); + return 0.2f; } gui::PluginView* instantiateView( QWidget * parent ) override; diff --git a/plugins/Patman/Patman.h b/plugins/Patman/Patman.h index 486524522d4..16b98deeefa 100644 --- a/plugins/Patman/Patman.h +++ b/plugins/Patman/Patman.h @@ -71,9 +71,9 @@ class PatmanInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return( 128 ); + return 3.f; } gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/Sf2Player/Sf2Player.h b/plugins/Sf2Player/Sf2Player.h index 1af370e05eb..4760d572e0f 100644 --- a/plugins/Sf2Player/Sf2Player.h +++ b/plugins/Sf2Player/Sf2Player.h @@ -80,11 +80,6 @@ class Sf2Instrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override - { - return 0; - } - Flags flags() const override { return Flag::IsSingleStreamed; diff --git a/plugins/Sid/SidInstrument.cpp b/plugins/Sid/SidInstrument.cpp index d85939eb844..b646836b574 100644 --- a/plugins/Sid/SidInstrument.cpp +++ b/plugins/Sid/SidInstrument.cpp @@ -221,24 +221,18 @@ QString SidInstrument::nodeName() const } - - -f_cnt_t SidInstrument::desiredReleaseFrames() const +float SidInstrument::desiredReleaseTimeMs() const { - const float samplerate = Engine::audioEngine()->processingSampleRate(); int maxrel = 0; for (const auto& voice : m_voice) { - if( maxrel < voice->m_releaseModel.value() ) - maxrel = (int)voice->m_releaseModel.value(); + maxrel = std::max(maxrel, static_cast(voice->m_releaseModel.value())); } - return f_cnt_t( float(relTime[maxrel])*samplerate/1000.0 ); + return computeReleaseTimeMsByFrameCount(relTime[maxrel]); } - - static int sid_fillbuffer(unsigned char* sidreg, reSID::SID *sid, int tdelta, short *ptr, int samples) { int total = 0; diff --git a/plugins/Sid/SidInstrument.h b/plugins/Sid/SidInstrument.h index 1a133b58b1b..8d5af8df065 100644 --- a/plugins/Sid/SidInstrument.h +++ b/plugins/Sid/SidInstrument.h @@ -111,7 +111,7 @@ class SidInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override; + float desiredReleaseTimeMs() const override; gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/TripleOscillator/TripleOscillator.h b/plugins/TripleOscillator/TripleOscillator.h index 4b6d97835e9..011352de4ba 100644 --- a/plugins/TripleOscillator/TripleOscillator.h +++ b/plugins/TripleOscillator/TripleOscillator.h @@ -121,9 +121,9 @@ class TripleOscillator : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return( 128 ); + return 3.f; } gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/plugins/Watsyn/Watsyn.h b/plugins/Watsyn/Watsyn.h index d238edbdea6..b34e28f60a2 100644 --- a/plugins/Watsyn/Watsyn.h +++ b/plugins/Watsyn/Watsyn.h @@ -150,9 +150,9 @@ class WatsynInstrument : public Instrument QString nodeName() const override; - f_cnt_t desiredReleaseFrames() const override + float desiredReleaseTimeMs() const override { - return( 64 ); + return 1.5f; } gui::PluginView* instantiateView( QWidget * _parent ) override; diff --git a/src/core/Instrument.cpp b/src/core/Instrument.cpp index a7cfc467ba4..2dfdc78f5d6 100644 --- a/src/core/Instrument.cpp +++ b/src/core/Instrument.cpp @@ -195,7 +195,16 @@ void Instrument::applyRelease( sampleFrame * buf, const NotePlayHandle * _n ) } } +float Instrument::computeReleaseTimeMsByFrameCount(f_cnt_t frames) const +{ + return frames / getSampleRate() * 1000.; +} + +sample_rate_t Instrument::getSampleRate() const +{ + return Engine::audioEngine()->processingSampleRate(); +} QString Instrument::fullDisplayName() const