From 546cb17e5f0f8640f4954d0f9329a7770269bef1 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sun, 21 Jun 2015 22:55:14 +0000 Subject: [PATCH 1/5] Simpler nextFullTact() algorithm --- include/MidiTime.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/MidiTime.h b/include/MidiTime.h index 788e6fb57..fe44ab4da 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -30,6 +30,7 @@ #include "lmms_basics.h" #include "export.h" +// note: 1 "Tact" = 1 Measure const int DefaultTicksPerTact = 192; const int DefaultStepsPerTact = 16; const int DefaultBeatsPerTact = DefaultTicksPerTact / DefaultStepsPerTact; @@ -85,6 +86,7 @@ public: return *this; } + // return the tact, rounded down and 0-based tact_t getTact() const { return m_ticks / s_ticksPerTact; @@ -92,11 +94,7 @@ public: tact_t nextFullTact() const { - if( m_ticks % s_ticksPerTact == 0 ) - { - return m_ticks / s_ticksPerTact; - } - return m_ticks / s_ticksPerTact + 1; + return (m_ticks + (s_ticksPerTact-1)) / s_ticksPerTact; } void setTicks( tick_t ticks ) From 335b1c1c75f54abf43055ca626bb819378ac9b49 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Mon, 22 Jun 2015 00:15:30 +0000 Subject: [PATCH 2/5] const-correctness for Song::getPlayPos() --- include/Song.h | 4 ++++ src/core/ProjectRenderer.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/Song.h b/include/Song.h index 3f52cbbb1..2e5fa2401 100644 --- a/include/Song.h +++ b/include/Song.h @@ -186,6 +186,10 @@ public: { return m_playPos[pm]; } + inline const PlayPos & getPlayPos( PlayModes pm ) const + { + return m_playPos[pm]; + } void updateLength(); tact_t length() const diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index e8a91c77d..2aaf5665a 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -163,7 +163,7 @@ void ProjectRenderer::run() //skip first empty buffer Engine::mixer()->nextBuffer(); - Song::PlayPos & pp = Engine::getSong()->getPlayPos( + const Song::PlayPos & pp = Engine::getSong()->getPlayPos( Song::Mode_PlaySong ); m_progress = 0; const int sl = ( Engine::getSong()->length() + 1 ) * 192; From 8edfdc05438354b7d40149cc189e7e45eee59e02 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Mon, 22 Jun 2015 00:17:17 +0000 Subject: [PATCH 3/5] Remove unused function 'isTempoAutomated()' --- include/Song.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/Song.h b/include/Song.h index 2e5fa2401..5280cea30 100644 --- a/include/Song.h +++ b/include/Song.h @@ -136,10 +136,6 @@ public: { return currentFrame(); } - inline bool isTempoAutomated() - { - return m_tempoModel.isAutomated(); - } inline bool isPaused() const { return m_paused; From 18e1d69cac04b32cfc0b7d6452050bd381305d48 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Mon, 22 Jun 2015 00:41:33 +0000 Subject: [PATCH 4/5] Offload most Midi processing from Song into MidiTime class --- include/MidiTime.h | 47 +++++++++++++++++++++++++++++++++++- include/Song.h | 14 +++++------ src/core/CMakeLists.txt | 1 + src/core/midi/MidiTime.cpp | 49 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/core/midi/MidiTime.cpp diff --git a/include/MidiTime.h b/include/MidiTime.h index fe44ab4da..0204075ee 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -27,8 +27,10 @@ #ifndef MIDI_TIME_H #define MIDI_TIME_H -#include "lmms_basics.h" +#include + #include "export.h" +#include "lmms_basics.h" // note: 1 "Tact" = 1 Measure const int DefaultTicksPerTact = 192; @@ -36,6 +38,25 @@ const int DefaultStepsPerTact = 16; const int DefaultBeatsPerTact = DefaultTicksPerTact / DefaultStepsPerTact; +class MeterModel; + +class EXPORT TimeSig +{ +public: + // in a time signature, + // the numerator represents the number of beats in a measure. + // the denominator indicates which type of note represents a beat. + // example: 6/8 means 6 beats in a measure, where each beat has duration equal to one 8th-note. + TimeSig( int num, int denom ); + TimeSig( const MeterModel &model ); + int numerator() const; + int denominator() const; +private: + int m_num; + int m_denom; +}; + + class EXPORT MidiTime { public: @@ -112,6 +133,26 @@ public: return m_ticks; } + tick_t ticksPerBeat( const TimeSig &sig ) const + { + return ticksPerTact(sig) / sig.numerator(); + } + // Remainder ticks after bar is removed + tick_t getTickWithinBar( const TimeSig &sig ) const + { + return m_ticks % ticksPerTact(sig); + } + // Returns the beat position inside the bar, 0-based + tick_t getBeatWithinBar( const TimeSig &sig ) const + { + return getTickWithinBar(sig) / ticksPerBeat(sig); + } + // Remainder ticks after bar and beat are removed + tick_t getTickWithinBeat( const TimeSig &sig ) const + { + return getTickWithinBar(sig) % ticksPerBeat(sig); + } + // calculate number of frame that are needed this time f_cnt_t frames( const float framesPerTick ) const { @@ -132,6 +173,10 @@ public: { return s_ticksPerTact; } + static tick_t ticksPerTact( const TimeSig &sig ) const + { + return DefaultTicksPerTact * sig.numerator() / sig.denominator(); + } static int stepsPerTact() { diff --git a/include/Song.h b/include/Song.h index 5280cea30..7c65641ec 100644 --- a/include/Song.h +++ b/include/Song.h @@ -111,22 +111,18 @@ public: inline int ticksPerTact() const { - return DefaultTicksPerTact * - m_timeSigModel.getNumerator() / - m_timeSigModel.getDenominator(); + return MidiTime::ticksPerTact(m_timeSigModel); } // Returns the beat position inside the bar, 0-based inline int getBeat() const { - return ( currentTick() - currentTact() * ticksPerTact() ) / - ( ticksPerTact() / m_timeSigModel.getNumerator() ); + return getPlayPos().getBeatWithinBar(m_timeSigModel); } // the remainder after bar and beat are removed inline int getBeatTicks() const { - return ( currentTick() - currentTact() * ticksPerTact() ) % - ( ticksPerTact() / m_timeSigModel.getNumerator() ); + return getPlayPos().getTickWithinBeat(m_timeSigModel); } inline int getTicks() const { @@ -186,6 +182,10 @@ public: { return m_playPos[pm]; } + inline const PlayPos & getPlayPos() const + { + return getPlayPos(m_playMode); + } void updateLength(); tact_t length() const diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e974d151f..6d6ae4d98 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -82,6 +82,7 @@ set(LMMS_SRCS core/midi/MidiController.cpp core/midi/MidiOss.cpp core/midi/MidiPort.cpp + core/midi/MidiTime.cpp core/midi/MidiWinMM.cpp PARENT_SCOPE diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp new file mode 100644 index 000000000..f93136144 --- /dev/null +++ b/src/core/midi/MidiTime.cpp @@ -0,0 +1,49 @@ +/* + * MidiTime.cpp - Class that encapsulates the position of a note/event in terms of + * its bar, beat and tick. + * + * Copyright (c) 2004-2014 Tobias Doerffel Date: Mon, 22 Jun 2015 01:37:49 +0000 Subject: [PATCH 5/5] Move MidiTime implementation into .cpp file --- include/MidiTime.h | 140 ++++++---------------------------- src/core/midi/MidiTime.cpp | 151 +++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 116 deletions(-) diff --git a/include/MidiTime.h b/include/MidiTime.h index 0204075ee..ce5ead739 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -60,135 +60,43 @@ private: class EXPORT MidiTime { public: - MidiTime( const tact_t tact, const tick_t ticks ) : - m_ticks( tact * s_ticksPerTact + ticks ) - { - } + MidiTime( const tact_t tact, const tick_t ticks ); + MidiTime( const tick_t ticks = 0 ); + MidiTime( const MidiTime& time ); - MidiTime( const tick_t ticks = 0 ) : - m_ticks( ticks ) - { - } + MidiTime toNearestTact() const; + MidiTime toAbsoluteTact() const; - MidiTime( const MidiTime& time ) : - m_ticks( time.m_ticks ) - { - } - - MidiTime toNearestTact() const - { - if( m_ticks % s_ticksPerTact >= s_ticksPerTact/2 ) - { - return ( getTact() + 1 ) * s_ticksPerTact; - } - return getTact() * s_ticksPerTact; - } - - MidiTime toAbsoluteTact() const - { - return getTact() * s_ticksPerTact; - } - - MidiTime& operator=( const MidiTime& time ) - { - m_ticks = time.m_ticks; - return *this; - } - - MidiTime& operator+=( const MidiTime& time ) - { - m_ticks += time.m_ticks; - return *this; - } - - MidiTime& operator-=( const MidiTime& time ) - { - m_ticks -= time.m_ticks; - return *this; - } + MidiTime& operator=( const MidiTime& time ); + MidiTime& operator+=( const MidiTime& time ); + MidiTime& operator-=( const MidiTime& time ); // return the tact, rounded down and 0-based - tact_t getTact() const - { - return m_ticks / s_ticksPerTact; - } + tact_t getTact() const; + // return the tact, rounded up and 0-based + tact_t nextFullTact() const; - tact_t nextFullTact() const - { - return (m_ticks + (s_ticksPerTact-1)) / s_ticksPerTact; - } + void setTicks( tick_t ticks ); + tick_t getTicks() const; - void setTicks( tick_t ticks ) - { - m_ticks = ticks; - } + operator int() const; - tick_t getTicks() const - { - return m_ticks; - } - - operator int() const - { - return m_ticks; - } - - tick_t ticksPerBeat( const TimeSig &sig ) const - { - return ticksPerTact(sig) / sig.numerator(); - } + tick_t ticksPerBeat( const TimeSig &sig ) const; // Remainder ticks after bar is removed - tick_t getTickWithinBar( const TimeSig &sig ) const - { - return m_ticks % ticksPerTact(sig); - } + tick_t getTickWithinBar( const TimeSig &sig ) const; // Returns the beat position inside the bar, 0-based - tick_t getBeatWithinBar( const TimeSig &sig ) const - { - return getTickWithinBar(sig) / ticksPerBeat(sig); - } + tick_t getBeatWithinBar( const TimeSig &sig ) const; // Remainder ticks after bar and beat are removed - tick_t getTickWithinBeat( const TimeSig &sig ) const - { - return getTickWithinBar(sig) % ticksPerBeat(sig); - } + tick_t getTickWithinBeat( const TimeSig &sig ) const; // calculate number of frame that are needed this time - f_cnt_t frames( const float framesPerTick ) const - { - if( m_ticks >= 0 ) - { - return static_cast( m_ticks * framesPerTick ); - } - return 0; - } - - static MidiTime fromFrames( const f_cnt_t frames, const float framesPerTick ) - { - return MidiTime( static_cast( frames / framesPerTick ) ); - } - - - static tick_t ticksPerTact() - { - return s_ticksPerTact; - } - static tick_t ticksPerTact( const TimeSig &sig ) const - { - return DefaultTicksPerTact * sig.numerator() / sig.denominator(); - } - - static int stepsPerTact() - { - int steps = ticksPerTact() / DefaultBeatsPerTact; - return qMax( 1, steps ); - } - - static void setTicksPerTact( tick_t _tpt ) - { - s_ticksPerTact = _tpt; - } + f_cnt_t frames( const float framesPerTick ) const; + static MidiTime fromFrames( const f_cnt_t frames, const float framesPerTick ); + static tick_t ticksPerTact(); + static tick_t ticksPerTact( const TimeSig &sig ); + static int stepsPerTact(); + static void setTicksPerTact( tick_t tpt ); private: tick_t m_ticks; diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index f93136144..b80c31b85 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -39,11 +39,162 @@ TimeSig::TimeSig( const MeterModel &model ) : { } + int TimeSig::numerator() const { return m_num; } + int TimeSig::denominator() const { return m_denom; } + + + + +MidiTime::MidiTime( const tact_t tact, const tick_t ticks ) : + m_ticks( tact * s_ticksPerTact + ticks ) +{ +} + +MidiTime::MidiTime( const tick_t ticks ) : + m_ticks( ticks ) +{ +} + +MidiTime::MidiTime( const MidiTime& time ) : + m_ticks( time.m_ticks ) +{ +} + + +MidiTime MidiTime::toNearestTact() const +{ + if( m_ticks % s_ticksPerTact >= s_ticksPerTact/2 ) + { + return ( getTact() + 1 ) * s_ticksPerTact; + } + return getTact() * s_ticksPerTact; +} + + +MidiTime MidiTime::toAbsoluteTact() const +{ + return getTact() * s_ticksPerTact; +} + + +MidiTime& MidiTime::operator=( const MidiTime& time ) +{ + m_ticks = time.m_ticks; + return *this; +} + + +MidiTime& MidiTime::operator+=( const MidiTime& time ) +{ + m_ticks += time.m_ticks; + return *this; +} + + +MidiTime& MidiTime::operator-=( const MidiTime& time ) +{ + m_ticks -= time.m_ticks; + return *this; +} + + +tact_t MidiTime::getTact() const +{ + return m_ticks / s_ticksPerTact; +} + + +tact_t MidiTime::nextFullTact() const +{ + return (m_ticks + (s_ticksPerTact-1)) / s_ticksPerTact; +} + + +void MidiTime::setTicks( tick_t ticks ) +{ + m_ticks = ticks; +} + + +tick_t MidiTime::getTicks() const +{ + return m_ticks; +} + + +MidiTime::operator int() const +{ + return m_ticks; +} + + +tick_t MidiTime::ticksPerBeat( const TimeSig &sig ) const +{ + // (number of ticks per bar) divided by (number of beats per bar) + return ticksPerTact(sig) / sig.numerator(); +} + + +tick_t MidiTime::getTickWithinBar( const TimeSig &sig ) const +{ + return m_ticks % ticksPerTact(sig); +} + +tick_t MidiTime::getBeatWithinBar( const TimeSig &sig ) const +{ + return getTickWithinBar(sig) / ticksPerBeat(sig); +} + +tick_t MidiTime::getTickWithinBeat( const TimeSig &sig ) const +{ + return getTickWithinBar(sig) % ticksPerBeat(sig); +} + + +f_cnt_t MidiTime::frames( const float framesPerTick ) const +{ + if( m_ticks >= 0 ) + { + return static_cast( m_ticks * framesPerTick ); + } + return 0; +} + + +MidiTime MidiTime::fromFrames( const f_cnt_t frames, const float framesPerTick ) +{ + return MidiTime( static_cast( frames / framesPerTick ) ); +} + + +tick_t MidiTime::ticksPerTact() +{ + return s_ticksPerTact; +} + + +tick_t MidiTime::ticksPerTact( const TimeSig &sig ) +{ + return DefaultTicksPerTact * sig.numerator() / sig.denominator(); +} + + +int MidiTime::stepsPerTact() +{ + int steps = ticksPerTact() / DefaultBeatsPerTact; + return qMax( 1, steps ); +} + + +void MidiTime::setTicksPerTact( tick_t tpt ) +{ + s_ticksPerTact = tpt; +}