diff --git a/include/DataFile.h b/include/DataFile.h index b504f93cb17..2a7cdb0a0fc 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -122,6 +122,7 @@ class LMMS_EXPORT DataFile : public QDomDocument void upgrade_automationNodes(); void upgrade_extendedNoteRange(); void upgrade_defaultTripleOscillatorHQ(); + void upgrade_ppqn(); // List of all upgrade methods static const std::vector UPGRADE_METHODS; diff --git a/include/MidiTime.h b/include/MidiTime.h index 952b4b6d596..d524a889383 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -33,7 +33,7 @@ #include "lmms_basics.h" // note: a bar was erroneously called "tact" in older versions of LMMS -const int DefaultTicksPerBar = 192; +const int DefaultTicksPerBar = 1920; const int DefaultStepsPerBar = 16; const int DefaultBeatsPerBar = DefaultTicksPerBar / DefaultStepsPerBar; diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index 90ee358f1b1..7e64a0cf01b 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -536,10 +536,10 @@ bool MidiImport::readSMF( TrackContainer* tc ) { smfMidiChannel * ch = chs[evt->chan].create(tc, trackName, mappingForChannel(evt->chan)); Alg_note_ptr noteEvt = dynamic_cast( evt ); - int ticks = noteEvt->get_duration() * ticksPerBeat; + int ticks = std::round(noteEvt->get_duration() * ticksPerBeat); //int pitchCorrection = ch->it_inst->flags() & Instrument::IsMidiBased ? 0 : -12; Note n( (ticks < 1 ? 1 : ticks ), - noteEvt->get_start_time() * ticksPerBeat, + std::round(noteEvt->get_start_time() * ticksPerBeat), noteEvt->get_identifier(), std::round(noteEvt->get_loud() * (200.f / 127.f))); // Map from MIDI velocity to LMMS volume ch->addNote( n ); diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index ec9056be2ae..0ef06f49259 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -70,7 +70,8 @@ const std::vector DataFile::UPGRADE_METHODS = { &DataFile::upgrade_1_1_91 , &DataFile::upgrade_1_2_0_rc3, &DataFile::upgrade_1_3_0 , &DataFile::upgrade_noHiddenClipNames, &DataFile::upgrade_automationNodes , &DataFile::upgrade_extendedNoteRange, - &DataFile::upgrade_defaultTripleOscillatorHQ + &DataFile::upgrade_defaultTripleOscillatorHQ, + &DataFile::upgrade_ppqn }; // Vector of all versions that have upgrade routines. @@ -1759,6 +1760,57 @@ void DataFile::upgrade_defaultTripleOscillatorHQ() } +/** \brief Default PPQN has been changed from 48 to 480 + * + * Older projects will be shortened by 10 times without this upgrade routine + */ +void DataFile::upgrade_ppqn() +{ + const int scaleFactor = 10; // 48 to 480 + auto scaleAttr = [scaleFactor] (QDomElement& e, const QString& name) { + e.setAttribute(name, e.attribute(name).toInt() * scaleFactor); + }; + + QDomNodeList aps = elementsByTagName("automationpattern"); + for (int i = 0; i < aps.size(); ++i) + { + QDomElement ap = aps.item(i).toElement(); + scaleAttr(ap, "pos"); + scaleAttr(ap, "len"); + + QDomNodeList times = ap.elementsByTagName("time"); + for (int j=0; j < times.size(); ++j) + { + QDomElement el = times.item(j).toElement(); + scaleAttr(el, "pos"); + } + } + + QDomNodeList ps = elementsByTagName("pattern"); + for (int i = 0; i < ps.size(); ++i) + { + QDomElement p = ps.item(i).toElement(); + scaleAttr(p, "pos"); + + QDomNodeList notes = p.elementsByTagName("note"); + for (int j=0; j < notes.size(); ++j) + { + QDomElement el = notes.item(j).toElement(); + scaleAttr(el, "pos"); + scaleAttr(el, "len"); + } + } + + QDomNodeList stcos = elementsByTagName("sampletco"); + for (int i = 0; i < stcos.size(); ++i) + { + QDomElement stco = stcos.item(i).toElement(); + scaleAttr(stco, "pos"); + scaleAttr(stco, "len"); + } +} + + void DataFile::upgrade() { // Runs all necessary upgrade methods diff --git a/src/core/VstSyncController.cpp b/src/core/VstSyncController.cpp index c09ce946b45..56b8aa8491c 100644 --- a/src/core/VstSyncController.cpp +++ b/src/core/VstSyncController.cpp @@ -88,10 +88,11 @@ VstSyncController::~VstSyncController() void VstSyncController::setAbsolutePosition( double ticks ) { + const double ppqn = DefaultTicksPerBar / 4.0; #ifdef VST_SNC_LATENCY - m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 ) - m_syncData->m_latency; + m_syncData->ppqPos = ( ( ticks + 0 ) / ppqn ) - m_syncData->m_latency; #else - m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 ); + m_syncData->ppqPos = ( ( ticks + 0 ) / ppqn ); #endif } @@ -111,9 +112,10 @@ void VstSyncController::setTempo( int newTempo ) void VstSyncController::startCycle( int startTick, int endTick ) { + const float ppqn = DefaultTicksPerBar / 4.0f; m_syncData->isCycle = true; - m_syncData->cycleStart = startTick / (float)48; - m_syncData->cycleEnd = endTick / (float)48; + m_syncData->cycleStart = startTick / ppqn; + m_syncData->cycleEnd = endTick / ppqn; } diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index 4e718a1d880..60d784e700e 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -208,6 +208,6 @@ double MidiTime::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ) double MidiTime::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute) { - // 60 * 1000 / 48 = 1250 - return ( ticks * 1250 ) / beatsPerMinute; + const double msOfTickAt1Bpm = 240000.0 / DefaultTicksPerBar; + return ( ticks * msOfTickAt1Bpm ) / beatsPerMinute; }