double GetMidiSourceLengthPPQ (MediaItem_Take* take, bool accountPlayrateIfIgnoringProjTempo, bool* isMidiSource /*=NULL*/) { bool isMidi = false; double length = 0; if (take && IsMidi(take)) { MediaItem* item = GetMediaItemTake_Item(take); double itemStart = GetMediaItemInfo_Value(item, "D_POSITION"); double takeOffset = GetMediaItemTakeInfo_Value(take, "D_STARTOFFS"); double sourceLength = GetMediaItemTake_Source(take)->GetLength(); double startPPQ = MIDI_GetPPQPosFromProjTime(take, itemStart - takeOffset); double endPPQ = MIDI_GetPPQPosFromProjTime(take, itemStart - takeOffset + sourceLength); isMidi = true; length = endPPQ - startPPQ; if (accountPlayrateIfIgnoringProjTempo) { bool ignoreProjTempo; if (GetMidiTakeTempoInfo(take, &ignoreProjTempo, NULL, NULL, NULL) && ignoreProjTempo) length /= GetMediaItemTakeInfo_Value(take, "D_PLAYRATE"); } } WritePtr(isMidiSource, isMidi); return length; }
bool replaceCCLanes(const char* _newCClanes) { bool updated = false; HWND me = MIDIEditor_GetActive(); MediaItem_Take* tk = me ? MIDIEditor_GetTake(me) : NULL; if (tk) { MediaItem* item = GetMediaItemTake_Item(tk); int tkIdx = GetTakeIndex(item, tk); // NULL item managed if (tkIdx >= 0) { SNM_TakeParserPatcher p(item, CountTakes(item)); WDL_FastString takeChunk; int tkPos, tklen; if (p.GetTakeChunk(tkIdx, &takeChunk, &tkPos, &tklen)) { SNM_ChunkParserPatcher ptk(&takeChunk, false); int pos = ptk.Parse(SNM_GET_CHUNK_CHAR, 1, "SOURCE", "VELLANE", 0, 0); if (pos > 0) { pos--; // see SNM_ChunkParserPatcher // Remove all lanes for this take if (ptk.RemoveLines("VELLANE")) { ptk.GetChunk()->Insert(_newCClanes, pos); // default lane (min sized) updated = p.ReplaceTake(tkPos, tklen, ptk.GetChunk()); } } } } } return updated; }
bool SNM_GetSetSourceState2(MediaItem_Take* _tk, WDL_FastString* _state, bool _setnewvalue) { if (_tk) if (MediaItem* item = GetMediaItemTake_Item(_tk)) { int tkIdx = GetTakeIndex(item, _tk); if (tkIdx >= 0) return SNM_GetSetSourceState(item, tkIdx, _state, _setnewvalue); } return false; }
void MainSaveCCLanes(COMMAND_T* _ct) { HWND me = MIDIEditor_GetActive(); MediaItem_Take* tk = me ? MIDIEditor_GetTake(me) : NULL; if (tk) { MediaItem* item = GetMediaItemTake_Item(tk); int tkIdx = GetTakeIndex(item, tk); // NULL item managed if (tkIdx >= 0) { SNM_TakeParserPatcher p(item, CountTakes(item)); WDL_FastString takeChunk; if (p.GetTakeChunk(tkIdx, &takeChunk)) { SNM_ChunkParserPatcher ptk(&takeChunk, false); // check start/end position of lanes in the chunk int firstPos = 0, lastPos = 0, laneCpt = 0; int pos = ptk.Parse(SNM_GET_CHUNK_CHAR, 1, "SOURCE", "VELLANE", laneCpt, 0); while (pos > 0) { lastPos = pos; if (!firstPos) firstPos = pos; pos = ptk.Parse(SNM_GET_CHUNK_CHAR, 1, "SOURCE", "VELLANE", ++laneCpt, 0); } if (firstPos > 0) { firstPos--; // see SNM_ChunkParserPatcher char laneSlot[SNM_MAX_CC_LANES_LEN] = ""; int eolLastPos = lastPos; const char* pp = ptk.GetChunk()->Get(); //ok 'cause read only while (pp[eolLastPos] && pp[eolLastPos] != '\n') eolLastPos++; int i = firstPos, j=0; while (pp[i] && i<eolLastPos && j < (SNM_MAX_CC_LANES_LEN-1) ) { //-1 see string termination if (pp[i] != '\n') laneSlot[j++] = pp[i]; else laneSlot[j++] = '|'; i++; } laneSlot[j] = 0; // store lanes char slot[32] = ""; if (_snprintfStrict(slot, sizeof(slot), "cc_lanes_slot%d", (int)_ct->user + 1) > 0) WritePrivateProfileString("MidiEditor", slot, laneSlot, g_SNM_IniFn.Get()); } } } } }
bool IsOpenInInlineEditor (MediaItem_Take* take) { bool inProject = false; if (GetActiveTake(GetMediaItemTake_Item(take)) == take && IsMidi(take, &inProject) && inProject) { if (PCM_source* source = GetMediaItemTake_Source(take)) { if (source->Extended(PCM_SOURCE_EXT_INLINEEDITOR, 0, 0, 0) > 0) return true; } } return false; }
void MainCreateCCLane(COMMAND_T* _ct) { bool updated = false; HWND me = MIDIEditor_GetActive(); MediaItem_Take* tk = me ? MIDIEditor_GetTake(me) : NULL; if (tk) { MediaItem* item = GetMediaItemTake_Item(tk); int tkIdx = GetTakeIndex(item, tk); // null item managed there if (tkIdx >= 0) { SNM_TakeParserPatcher p(item, CountTakes(item)); WDL_FastString takeChunk; int tkPos, tklen; if (p.GetTakeChunk(tkIdx, &takeChunk, &tkPos, &tklen)) { SNM_ChunkParserPatcher ptk(&takeChunk, false); // check current lanes bool lanes[SNM_MAX_CC_LANE_ID+1]; int i=0; while(i <= SNM_MAX_CC_LANE_ID) lanes[i++]=false; char lastLaneId[4] = ""; //max in v3.6: "133" int tkFirstPos = 0, laneCpt = 0; int pos = ptk.Parse(SNM_GET_CHUNK_CHAR, 1, "SOURCE", "VELLANE", laneCpt, 1, lastLaneId); while (pos > 0) { if (!tkFirstPos) tkFirstPos = pos; lanes[atoi(lastLaneId)] = true; // atoi: 0 on failure, lane 0 won't be used anyway.. pos = ptk.Parse(SNM_GET_CHUNK_CHAR, 1, "SOURCE", "VELLANE", ++laneCpt, 1, lastLaneId); } if (tkFirstPos > 0) { tkFirstPos--; // see SNM_ChunkParserPatcher // find the first unused index i=1; while(lanes[i] && i <= SNM_MAX_CC_LANE_ID) i++; char newLane[SNM_MAX_CHUNK_LINE_LENGTH] = ""; if (_snprintfStrict(newLane, sizeof(newLane), "VELLANE %d 50 0\n", i) > 0) ptk.GetChunk()->Insert(newLane, tkFirstPos); // "update" take updated = p.ReplaceTake(tkPos, tklen, ptk.GetChunk()); } } } } if (updated) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
EnvelopeProcessor::ErrorCode EnvelopeProcessor::generateTakeLfo(MediaItem_Take* take) { MediaItem* parentItem = GetMediaItemTake_Item(take); double dItemStartPos = GetMediaItemInfo_Value(parentItem, "D_POSITION"); double dItemEndPos = dItemStartPos + GetMediaItemInfo_Value(parentItem, "D_LENGTH"); double dStartPos, dEndPos; GetTimeSegmentPositions(_parameters.timeSegment, dStartPos, dEndPos, parentItem); if(dEndPos>dItemEndPos) dEndPos = dItemEndPos; if(dStartPos<dItemStartPos) dStartPos = dItemStartPos; dStartPos -= dItemStartPos; dEndPos -= dItemStartPos; return generateTakeLfo(take, dStartPos, dEndPos, _parameters.takeEnvType, _parameters.waveParams, _parameters.precision); }
EnvelopeProcessor::ErrorCode EnvelopeProcessor::processTakeEnv(MediaItem_Take* take) { MediaItem* parentItem = GetMediaItemTake_Item(take); double dItemStartPos = GetMediaItemInfo_Value(parentItem, "D_POSITION"); double dItemEndPos = dItemStartPos + GetMediaItemInfo_Value(parentItem, "D_LENGTH"); double dStartPos, dEndPos; GetTimeSegmentPositions(_envModParams.timeSegment, dStartPos, dEndPos, parentItem); if(dEndPos>dItemEndPos) dEndPos = dItemEndPos; if(dStartPos<dItemStartPos) dStartPos = dItemStartPos; dStartPos -= dItemStartPos; dEndPos -= dItemStartPos; return processTakeEnv(take, dStartPos, dEndPos, _envModParams.takeEnvType, _envModParams.type, _envModParams.strength, _envModParams.offset); }
void ME_PreviewActiveTake (COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { if (MediaItem_Take* take = MIDIEditor_GetTake(MIDIEditor_GetActive())) { MediaItem* item = GetMediaItemTake_Item(take); vector<int> options = GetDigits((int)ct->user); int toggle = options[0]; int type = options[1]; int selNotes = options[2]; int pause = options[3]; MediaTrack* track = GetMediaItem_Track(item); double volume = GetMediaItemInfo_Value(item, "D_VOL"); double start = 0; double measure = (type == 3) ? 1 : 0; bool pausePlay = (pause == 2) ? true : false; if (type == 2) { double mousePosition = ME_PositionAtMouseCursor(true, true); if (mousePosition != -1) start = mousePosition - GetMediaItemInfo_Value(item, "D_POSITION"); else return; } vector<int> muteState; if (selNotes == 2 && !AreAllNotesUnselected(take)) muteState = MuteSelectedNotes(take); MidiTakePreview(toggle, take, track, volume, start, measure, pausePlay); if (muteState.size() > 0) SetMutedNotes(take, muteState); } }
double EffectiveMidiTakeStart (MediaItem_Take* take, bool ignoreMutedEvents, bool ignoreTextEvents, bool ignoreEventsOutsideItemBoundaries) { int noteCount, ccCount, sysCount; if (take && MIDI_CountEvts(take, ¬eCount, &ccCount, &sysCount)) { MediaItem* item = GetMediaItemTake_Item(take); double itemStart = GetMediaItemInfo_Value(item, "D_POSITION"); double itemStartPPQ = MIDI_GetPPQPosFromProjTime(take, itemStart); double itemEndPPQ = (!ignoreEventsOutsideItemBoundaries) ? 0 : MIDI_GetPPQPosFromProjTime(take, GetMediaItemInfo_Value(item, "D_LENGTH") + itemStart); int loopCount = (!ignoreEventsOutsideItemBoundaries) ? 0 : GetLoopCount(take, 0, NULL); double sourceLenPPQ = (!ignoreEventsOutsideItemBoundaries) ? 0 : GetMidiSourceLengthPPQ(take, true); bool validNote = false, validCC = false, validSys = false; double noteStart, ccStart, sysStart; double loopOffset = 0; for (int i = 0; i < noteCount; ++i) { bool muted; double start, end; MIDI_GetNote(take, i, NULL, &muted, &start, &end, NULL, NULL, NULL); if ((ignoreMutedEvents && !muted) || !ignoreMutedEvents) { if (!ignoreEventsOutsideItemBoundaries) { noteStart = start; validNote = true; break; } else { start += loopOffset; end += loopOffset; if (AreOverlapped(start, end, itemStartPPQ, itemEndPPQ)) { if (itemStartPPQ > start) start = itemStartPPQ; noteStart = start; validNote = true; break; } } } if (ignoreEventsOutsideItemBoundaries && loopCount > 0 && i == noteCount - 1) { if (sourceLenPPQ > 0 && loopOffset == 0) { loopOffset = sourceLenPPQ; i = -1; } } } loopOffset = 0; for (int i = 0; i < ccCount; ++i) { bool muted; double pos; MIDI_GetCC(take, i, NULL, &muted, &pos, NULL, NULL, NULL, NULL); if ((ignoreMutedEvents && !muted) || !ignoreMutedEvents) { if (!ignoreEventsOutsideItemBoundaries) { ccStart = pos; validCC = true; break; } else { pos += loopOffset; if (CheckBounds(pos, itemStartPPQ, itemEndPPQ)) { ccStart = pos; validCC = true; break; } } } if (ignoreEventsOutsideItemBoundaries && loopCount > 0 && i == ccCount - 1) { if (sourceLenPPQ > 0 && loopOffset == 0) { loopOffset = sourceLenPPQ; i = -1; } } } for (int i = 0; i < sysCount; ++i) { bool muted; double pos; int type; MIDI_GetTextSysexEvt(take, i, NULL, &muted, &pos, &type, NULL, NULL); if (((ignoreMutedEvents && !muted) || !ignoreMutedEvents) && ((ignoreTextEvents && type == -1) || !ignoreTextEvents)) { if (!ignoreEventsOutsideItemBoundaries) { sysStart = pos; validSys = true; break; } else { pos += loopOffset; if (CheckBounds(pos, itemStartPPQ, itemEndPPQ)) { sysStart = pos; validSys = true; break; } } } if (ignoreEventsOutsideItemBoundaries && loopCount > 0 && i == sysCount - 1) { if (sourceLenPPQ > 0 && loopOffset == 0) { loopOffset = sourceLenPPQ; i = -1; } } } if (validNote || validCC || validSys) { if (!validNote) noteStart = (validSys) ? sysStart : ccStart; if (!validCC) ccStart = (validSys) ? sysStart : noteStart; if (!validSys) sysStart = (ccStart) ? ccStart : noteStart; return MIDI_GetProjTimeFromPPQPos(take, min(min(noteStart, ccStart), sysStart)); } else { return GetMediaItemInfo_Value(item, "D_POSITION"); } } else { return GetMediaItemInfo_Value(GetMediaItemTake_Item(take), "D_POSITION"); } }
inline void SetArrangeScrollTo(MediaItem_Take* take, VerticalZoomCenter center) { SetArrangeScrollTo(GetMediaItemTake_Item(take), center); }
static void MidiTakePreview (int mode, MediaItem_Take* take, MediaTrack* track, double volume, double startOffset, double measureSync, bool pauseDuringPrev) { /* mode: 0 -> stop * * 1 -> start * * 2 -> toggle */ if (IsRecording()) // Reaper won't preview anything during recording but extension will still think preview is in progress (could disrupt toggle states and send unneeded CC123) return; if (g_itemPreviewPlaying) { if (g_ItemPreview.preview_track) { StopTrackPreview(&g_ItemPreview); SendAllNotesOff((MediaTrack*)g_ItemPreview.preview_track); } else { StopPreview(&g_ItemPreview); } g_itemPreviewPlaying = false; delete g_ItemPreview.src; if (g_itemPreviewPaused && mode != 1) // requesting new preview while old one is still playing shouldn't unpause playback { if (IsPaused()) OnPauseButton(); g_itemPreviewPaused = false; } if (mode == 2) return; } if (mode == 0) return; if (take) { MediaItem* item = GetMediaItemTake_Item(take); MediaItem_Take* oldTake = GetActiveTake(item); bool itemMuteState = *(bool*)GetSetMediaItemInfo(item, "B_MUTE", NULL); double effectiveTakeLen = EffectiveMidiTakeLength(take, true, true); GetSetMediaItemInfo(item, "B_MUTE", &g_bFalse); // needs to be set before getting the source SetActiveTake(take); // active item take and editor take may differ PCM_source* src = ((PCM_source*)item)->Duplicate(); // must be item source otherwise item/take volume won't get accounted for if (src && effectiveTakeLen > 0 && effectiveTakeLen > startOffset) { GetSetMediaItemInfo((MediaItem*)src, "D_POSITION", &g_d0); GetSetMediaItemInfo((MediaItem*)src, "D_LENGTH", &effectiveTakeLen); if (!g_ItemPreview.src) { #ifdef _WIN32 InitializeCriticalSection(&g_ItemPreview.cs); #else pthread_mutex_init(&g_ItemPreview.mutex, NULL); #endif g_ItemPreview.loop = false; } g_ItemPreview.src = src; g_ItemPreview.m_out_chan = (track) ? (-1) : (0); g_ItemPreview.curpos = startOffset; g_ItemPreview.volume = volume; g_ItemPreview.preview_track = track; // Pause before preview otherwise MidiTakePreviewPlayState will stop it g_itemPreviewPaused = pauseDuringPrev; if (g_itemPreviewPaused && IsPlaying() && !IsPaused()) OnPauseButton(); if (g_ItemPreview.preview_track) g_itemPreviewPlaying = !!PlayTrackPreview2Ex(NULL, &g_ItemPreview, (measureSync) ? (1) : (0), measureSync); else g_itemPreviewPlaying = !!PlayPreviewEx(&g_ItemPreview, (measureSync) ? (1) : (0), measureSync); if (g_itemPreviewPlaying) plugin_register("timer",(void*)MidiTakePreviewTimer); else delete g_ItemPreview.src; } SetActiveTake(oldTake); GetSetMediaItemInfo(item, "B_MUTE", &itemMuteState); } }
static void MidiTakePreview (int mode, MediaItem_Take* take, MediaTrack* track, double volume, double startOffset, double measureSync, bool pauseDuringPrev) { /* mode: 0 -> stop * * 1 -> start * * 2 -> toggle */ // First stop any ongoing preview RegisterCsurfPlayState(false, MidiTakePreviewPlayState); if (g_itemPreviewPlaying) { if (g_ItemPreview.preview_track) { StopTrackPreview(&g_ItemPreview); SendAllNotesOff((MediaTrack*)g_ItemPreview.preview_track); } else { StopPreview(&g_ItemPreview); } g_itemPreviewPlaying = false; plugin_register("-timer",(void*)MidiTakePreviewTimer); delete g_ItemPreview.src; if (g_itemPreviewPaused && mode != 1) // requesting new preview while old one is still playing shouldn't unpause playback { if (IsPaused(NULL)) OnPauseButtonEx(NULL); g_itemPreviewPaused = false; } // Toggled preview off...treat it as stop if (mode == 2) mode = 0; } // About IsRecording: REAPER won't preview anything during recording but extension will still think preview is in progress if we let it continue here if (mode == 0 || IsRecording(NULL)) return; if (take) { PreventUIRefresh(1); // item may get resized temporarily so hide it from the user MediaItem* item = GetMediaItemTake_Item(take); MediaItem_Take* oldTake = GetActiveTake(item); bool itemMuteState = *(bool*)GetSetMediaItemInfo(item, "B_MUTE", NULL); GetSetMediaItemInfo(item, "B_MUTE", &g_bFalse); // needs to be set before getting the source SetActiveTake(take); // active item take and editor take may differ // If timebase in MIDI editor is set to Beats (source), make sure item is croped so full MIDI source is visible beforing getting the source double itemStart = -1; double itemEnd = -1; double takeOffset = 0; double itemPositionOffset = 0; if (GetToggleCommandState2(SectionFromUniqueID(SECTION_MIDI_EDITOR), 40470) > 0) // Timebase: Beats(source) { itemStart = GetMediaItemInfo_Value(item, "D_POSITION"); itemEnd = itemStart + GetMediaItemInfo_Value(item, "D_LENGTH"); takeOffset = GetMediaItemTakeInfo_Value(take, "D_STARTOFFS"); double sourceLenPPQ = GetMidiSourceLengthPPQ(take, NULL); if (takeOffset != 0) SetMediaItemTakeInfo_Value(take, "D_STARTOFFS", 0); double itemSourceStart = MIDI_GetProjTimeFromPPQPos(take, 0); if (itemSourceStart < 0) { itemPositionOffset = abs(itemSourceStart); SetMediaItemInfo_Value(item, "D_POSITION", itemStart + itemPositionOffset); itemSourceStart = MIDI_GetProjTimeFromPPQPos(take, 0); } SetMediaItemInfo_Value(item, "D_POSITION", itemSourceStart); SetMediaItemInfo_Value(item, "D_LENGTH", MIDI_GetProjTimeFromPPQPos(take, sourceLenPPQ) - itemSourceStart); } double effectiveTakeLen = EffectiveMidiTakeEnd(take, true, true, true) - GetMediaItemInfo_Value(item, "D_POSITION"); PCM_source* src = DuplicateSource((PCM_source*)item); // must be item source otherwise item/take volume won't get accounted for if (src && effectiveTakeLen > 0) { GetSetMediaItemInfo((MediaItem*)src, "D_POSITION", &g_d0); GetSetMediaItemInfo((MediaItem*)src, "D_LENGTH", &effectiveTakeLen); if (!g_ItemPreview.src) { #ifdef _WIN32 InitializeCriticalSection(&g_ItemPreview.cs); #else pthread_mutex_init(&g_ItemPreview.mutex, NULL); #endif g_ItemPreview.loop = false; } g_ItemPreview.src = src; g_ItemPreview.m_out_chan = (track) ? (-1) : (0); g_ItemPreview.curpos = startOffset; g_ItemPreview.volume = volume; g_ItemPreview.preview_track = track; // Pause before preview otherwise MidiTakePreviewPlayState will stop it g_itemPreviewPaused = pauseDuringPrev; if (g_itemPreviewPaused && IsPlaying(NULL) && !IsPaused(NULL)) OnPauseButton(); if (g_ItemPreview.preview_track) g_itemPreviewPlaying = !!PlayTrackPreview2Ex(NULL, &g_ItemPreview, 1, measureSync); else g_itemPreviewPlaying = !!PlayPreviewEx(&g_ItemPreview, 1, measureSync); if (g_itemPreviewPlaying) { plugin_register("timer",(void*)MidiTakePreviewTimer); RegisterCsurfPlayState(true, MidiTakePreviewPlayState); } else delete g_ItemPreview.src; } if (itemStart != -1) { SetMediaItemInfo_Value(item, "D_POSITION", itemStart + itemPositionOffset); SetMediaItemInfo_Value(item, "D_LENGTH", itemEnd - itemStart); if (itemPositionOffset != 0) SetMediaItemInfo_Value(item, "D_POSITION", itemStart); if (takeOffset != 0) SetMediaItemTakeInfo_Value(take, "D_STARTOFFS", takeOffset); } SetActiveTake(oldTake); GetSetMediaItemInfo(item, "B_MUTE", &itemMuteState); PreventUIRefresh(-1); } }
void ME_PreviewActiveTake (COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { HWND midiEditor = MIDIEditor_GetActive(); if (MediaItem_Take* take = MIDIEditor_GetTake(midiEditor)) { MediaItem* item = GetMediaItemTake_Item(take); vector<int> options = GetDigits((int)ct->user); int toggle = options[0]; int type = options[1]; int selNotes = options[2]; int pause = options[3]; MediaTrack* track = GetMediaItem_Track(item); double volume = GetMediaItemInfo_Value(item, "D_VOL"); double start = 0; double measure = (type == 3) ? 1 : 0; bool pausePlay = (pause == 2) ? true : false; if (type == 2) { double mousePosition = ME_PositionAtMouseCursor(true, true); if (mousePosition != -1) { if (GetToggleCommandState2(SectionFromUniqueID(SECTION_MIDI_EDITOR), 40470) > 0) // Timebase: Beats(source) start = mousePosition - MIDI_GetProjTimeFromPPQPos(take, 0); else start = mousePosition - GetMediaItemInfo_Value(item, "D_POSITION"); } else return; } vector<int> muteState; if (selNotes == 2) { if (!AreAllNotesUnselected(take)) { muteState = MuteUnselectedNotes(take); if (type != 2) { BR_MidiEditor editor(midiEditor); double time; MIDI_GetNote(take, FindFirstSelectedNote(take, &editor), NULL, NULL, &time, NULL, NULL, NULL, NULL); start = MIDI_GetProjTimeFromPPQPos(take, time) - GetMediaItemInfo_Value(item, "D_POSITION"); if (start < 0) start = 0; } } else if (type != 2) { BR_MidiEditor editor(midiEditor); int id = FindFirstNote(take, &editor); if (id != -1) { double time; MIDI_GetNote(take, id, NULL, NULL, &time, NULL, NULL, NULL, NULL); start = MIDI_GetProjTimeFromPPQPos(take, time) - GetMediaItemInfo_Value(item, "D_POSITION"); if (start < 0) start = 0; } } } MidiTakePreview(toggle, take, track, volume, start, measure, pausePlay); if (muteState.size() > 0) SetMutedNotes(take, muteState); } }
double EffectiveMidiTakeEnd (MediaItem_Take* take, bool ignoreMutedEvents, bool ignoreTextEvents, bool ignoreEventsOutsideItemBoundaries) { int noteCount, ccCount, sysCount; if (take && MIDI_CountEvts(take, ¬eCount, &ccCount, &sysCount)) { MediaItem* item = GetMediaItemTake_Item(take); double itemStart = GetMediaItemInfo_Value(item, "D_POSITION"); double itemStartPPQ = MIDI_GetPPQPosFromProjTime(take, itemStart); double itemEndPPQ = (!ignoreEventsOutsideItemBoundaries) ? 0 : MIDI_GetPPQPosFromProjTime(take, GetMediaItemInfo_Value(item, "D_LENGTH") + itemStart); int loopCount = GetLoopCount(take, 0, NULL); double sourceLenPPQ = GetMidiSourceLengthPPQ(take, true); double effectiveTakeEndPPQ = -1; for (int i = 0; i < noteCount; ++i) { bool muted; double noteStart, noteEnd; MIDI_GetNote(take, i, NULL, &muted, ¬eStart, ¬eEnd, NULL, NULL, NULL); if (((ignoreMutedEvents && !muted) || !ignoreMutedEvents)) { noteEnd += loopCount*sourceLenPPQ; if (!ignoreEventsOutsideItemBoundaries) { if (noteEnd > effectiveTakeEndPPQ) effectiveTakeEndPPQ = noteEnd; } else { noteStart += loopCount*sourceLenPPQ; if (CheckBounds(noteStart, itemStartPPQ, itemEndPPQ)) { if (noteEnd > itemEndPPQ) noteEnd = itemEndPPQ; if (noteEnd > effectiveTakeEndPPQ) effectiveTakeEndPPQ = noteEnd; } else if (loopCount > 0) { noteStart -= sourceLenPPQ; if (CheckBounds(noteStart, itemStartPPQ, itemEndPPQ)) { noteEnd -= sourceLenPPQ; if (noteEnd > itemEndPPQ) noteEnd = itemEndPPQ; if (noteEnd > effectiveTakeEndPPQ) effectiveTakeEndPPQ = noteEnd; } } } } } for (int i = ccCount - 1; i >= 0; --i) { bool muted; double pos; MIDI_GetCC(take, i, NULL, &muted, &pos, NULL, NULL, NULL, NULL); if ((ignoreMutedEvents && !muted) || !ignoreMutedEvents) { pos += loopCount*sourceLenPPQ; if (!ignoreEventsOutsideItemBoundaries) { if (pos > effectiveTakeEndPPQ) effectiveTakeEndPPQ = pos + 1; // add 1 ppq so length definitely includes that last event break; } else { if (CheckBounds(pos, itemStartPPQ, itemEndPPQ)) { if (pos > effectiveTakeEndPPQ) { effectiveTakeEndPPQ = pos + 1; break; } } else if (loopCount > 0) { pos -= sourceLenPPQ; if (CheckBounds(pos, itemStartPPQ, itemEndPPQ)) { if (pos > effectiveTakeEndPPQ) { effectiveTakeEndPPQ = pos + 1; break; } } } } } } for (int i = 0; i < sysCount; ++i) { bool muted; double pos; int type; MIDI_GetTextSysexEvt(take, i, NULL, &muted, &pos, &type, NULL, NULL); if (((ignoreMutedEvents && !muted) || !ignoreMutedEvents) && ((ignoreTextEvents && type == -1) || !ignoreTextEvents)) { pos += loopCount*sourceLenPPQ; if (!ignoreEventsOutsideItemBoundaries) { if (pos > effectiveTakeEndPPQ) effectiveTakeEndPPQ = pos + 1; // add 1 ppq so length definitely includes that last event } else { if (CheckBounds(pos, itemStartPPQ, itemEndPPQ)) { if (pos > effectiveTakeEndPPQ) effectiveTakeEndPPQ = pos + 1; } else if (loopCount > 0) { pos -= sourceLenPPQ; if (CheckBounds(pos, itemStartPPQ, itemEndPPQ)) { if (pos > effectiveTakeEndPPQ) effectiveTakeEndPPQ = pos + 1; } } } } } return (effectiveTakeEndPPQ == -1) ? itemStart : MIDI_GetProjTimeFromPPQPos(take, effectiveTakeEndPPQ); } return 0; }
double GetOriginalPpqPos (MediaItem_Take* take, double ppqPos, bool* loopedItem, double* posVisInsertStartPpq, double* posVisInsertEndPpq) { double returnPos = 0; MediaItem* item = GetMediaItemTake_Item(take); if (!take || !item || !IsMidi(take, NULL)) { WritePtr(loopedItem, false); WritePtr(posVisInsertStartPpq, 0.0); WritePtr(posVisInsertEndPpq, 0.0); } else { double itemStart = GetMediaItemInfo_Value(item, "D_POSITION"); double itemEnd = itemStart + GetMediaItemInfo_Value(item, "D_LENGTH"); if (GetMediaItemInfo_Value(item, "B_LOOPSRC") == 0) { WritePtr(loopedItem, false); WritePtr(posVisInsertStartPpq, MIDI_GetPPQPosFromProjTime(take, itemStart)); WritePtr(posVisInsertEndPpq, MIDI_GetPPQPosFromProjTime(take, itemEnd)); returnPos = ppqPos; } else { WritePtr(loopedItem, true); double visibleItemStartPpq = MIDI_GetPPQPosFromProjTime(take, itemStart); double visibleItemEndPpq = MIDI_GetPPQPosFromProjTime(take, itemEnd); double sourceLenPpq = GetMidiSourceLengthPPQ(take, true); // Deduct take offset to get correct current loop iteration double itemStartPpq = MIDI_GetPPQPosFromProjTime(take, itemStart - GetMediaItemTakeInfo_Value(take, "D_STARTOFFS")); int currentLoop; int loopCount = GetLoopCount(take, MIDI_GetProjTimeFromPPQPos(take, ppqPos), ¤tLoop); returnPos = (ppqPos >= visibleItemStartPpq) ? (ppqPos - (currentLoop * sourceLenPpq)) : ppqPos; if (ppqPos > visibleItemEndPpq) // position after item end { WritePtr(posVisInsertStartPpq, 0.0); WritePtr(posVisInsertEndPpq, 0.0); } else if (ppqPos < visibleItemStartPpq || currentLoop == 0) // position in first loop iteration or before it { WritePtr(posVisInsertStartPpq, visibleItemStartPpq); WritePtr(posVisInsertEndPpq, (visibleItemEndPpq - visibleItemStartPpq >= sourceLenPpq) ? itemStartPpq + sourceLenPpq : visibleItemEndPpq); } else if (currentLoop == loopCount) // position in last loop iteration { WritePtr(posVisInsertStartPpq, itemStartPpq); WritePtr(posVisInsertEndPpq, itemStartPpq + (visibleItemEndPpq - (currentLoop * sourceLenPpq))); } else // position in other loop iterations { WritePtr(posVisInsertStartPpq, itemStartPpq); WritePtr(posVisInsertEndPpq, itemStartPpq + sourceLenPpq); } } } return returnPos; }
bool BR_MidiEditor::Build () { m_take = (m_midiEditor) ? SWS_MIDIEditor_GetTake(m_midiEditor) : m_take; if (m_take) { MediaItem* item = GetMediaItemTake_Item(m_take); int takeId = GetTakeId(m_take, item); if (takeId >= 0) { SNM_TakeParserPatcher p(item, CountTakes(item)); WDL_FastString takeChunk; if (p.GetTakeChunk(takeId, &takeChunk)) { SNM_ChunkParserPatcher ptk(&takeChunk, false); LineParser lp(false); int laneId = 0; WDL_FastString lineLane; while (ptk.Parse(SNM_GET_SUBCHUNK_OR_LINE, 1, "SOURCE", "VELLANE", laneId++, -1, &lineLane)) { lp.parse(lineLane.Get()); m_ccLanes.push_back(lp.gettoken_int(1)); m_ccLanesHeight.push_back(lp.gettoken_int(((m_midiEditor) ? 2 : 3))); if (!m_midiEditor && m_ccLanesHeight.back() == 0) m_ccLanesHeight.back() = INLINE_MIDI_LANE_DIVIDER_H; // sometimes REAPER will return 0 when lane is completely hidden, but divider will still be visible lineLane.DeleteSub(0, lineLane.GetLength()); } WDL_FastString dataLine; if (ptk.Parse(SNM_GET_SUBCHUNK_OR_LINE, 1, "SOURCE", "HASDATA", 0, -1, &dataLine)) { lp.parse(dataLine.Get()); m_ppq = lp.gettoken_int(2); } else if (ptk.Parse(SNM_GET_SUBCHUNK_OR_LINE, 1, "SOURCE", "FILE", 0, -1, &dataLine)) { lp.parse(dataLine.Get()); m_ppq = GetMIDIFilePPQ (lp.gettoken_str(1)); if (!m_ppq) return false; } else return false; WDL_FastString lineView; if (ptk.Parse(SNM_GET_SUBCHUNK_OR_LINE, 1, "SOURCE", "CFGEDITVIEW", 0, -1, &lineView)) { lp.parse(lineView.Get()); m_startPos = (m_midiEditor) ? lp.gettoken_float(1) : GetMediaItemInfo_Value(GetMediaItemTake_Item(m_take), "D_POSITION"); m_hZoom = (m_midiEditor) ? lp.gettoken_float(2) : GetHZoomLevel(); m_vPos = (m_midiEditor) ? lp.gettoken_int(3) : lp.gettoken_int(7); m_vZoom = (m_midiEditor) ? lp.gettoken_int(4) : lp.gettoken_int(6); } else return false; WDL_FastString lineFilter; if (ptk.Parse(SNM_GET_SUBCHUNK_OR_LINE, 1, "SOURCE", "EVTFILTER", 0, -1, &lineFilter)) { lp.parse(lineFilter.Get()); m_filterEnabled = !!GetBit(lp.gettoken_int(7), 0); m_filterInverted = !!GetBit(lp.gettoken_int(7), 2); m_filterChannel = lp.gettoken_int(1); m_filterEventType = lp.gettoken_int(2); m_filterEventParam = !!lp.gettoken_int(16); m_filterEventVal = !!lp.gettoken_int(8); m_filterEventPos = !!lp.gettoken_int(14); m_filterEventLen = !!lp.gettoken_int(9); m_filterEventParamLo = lp.gettoken_int(17); m_filterEventParamHi = lp.gettoken_int(18); m_filterEventValLo = lp.gettoken_int(4); m_filterEventValHi = lp.gettoken_int(5); m_filterEventPosRepeat = lp.gettoken_float(15); m_filterEventPosLo = lp.gettoken_float(12); m_filterEventPosHi = lp.gettoken_float(13); m_filterEventLenLo = lp.gettoken_float(10); m_filterEventLenHi = lp.gettoken_float(11); } else return false; WDL_FastString lineProp; if (ptk.Parse(SNM_GET_SUBCHUNK_OR_LINE, 1, "SOURCE", "CFGEDIT", 0, -1, &lineProp)) { lp.parse(lineProp.Get()); m_pianoroll = (m_midiEditor) ? lp.gettoken_int(6) : 0; // inline midi editor doesn't have piano roll modes m_drawChannel = lp.gettoken_int(9) - 1; m_noteshow = lp.gettoken_int(18); m_timebase = (m_midiEditor) ? lp.gettoken_int(19) : PROJECT_SYNC; } else return false; // A few "corrections" for easier manipulation afterwards if (m_filterChannel == 0) m_filterChannel = ~m_filterChannel; if (m_filterEventParamLo < 0) m_filterEventParamLo = 0; if (m_filterEventParamHi < 0) m_filterEventParamHi = INT_MAX; if (m_filterEventValLo < 0) m_filterEventValLo = 0; if (m_filterEventValHi < 0) m_filterEventValHi = INT_MAX; if (m_filterEventPosLo < 0) m_filterEventPosLo = 0; if (m_filterEventPosHi < 0) m_filterEventPosHi = INT_MAX; m_filterEventLenLo = (m_filterEventLenLo < 0) ? (0) : (m_ppq * 4 * m_filterEventLenLo); m_filterEventLenHi = (m_filterEventLenHi < 0) ? (INT_MAX) : (m_ppq * 4 * m_filterEventLenHi); m_filterEventPosLo = (m_filterEventPosLo < 0) ? (0) : (m_ppq * 4 * m_filterEventPosLo); m_filterEventPosHi = (m_filterEventPosHi < 0) ? (INT_MAX) : (m_ppq * 4 * m_filterEventPosHi); m_filterEventPosRepeat = (m_filterEventPosRepeat < 0) ? (0) : (m_ppq * 4 * m_filterEventPosRepeat); return true; } } } return false; }