bool InsertSilence(const char* _undoTitle, double _pos, double _len) { if (_pos>=0.0 && _len>0.0 && _pos<SNM_GetProjectLength()) { if (_undoTitle) Undo_BeginBlock2(NULL); PreventUIRefresh(1); double timeSel1, timeSel2, d=_pos+_len; GetSet_LoopTimeRange2(NULL, false, false, &timeSel1, &timeSel2, false); GetSet_LoopTimeRange2(NULL, true, false, &_pos, &d, false); Main_OnCommand(40200, 0); // insert space at time sel // restore time sel, enlarge if needed (mimic native behavior) if (timeSel1>_pos) timeSel1+=_len; if (_pos<timeSel2) timeSel2+=_len; GetSet_LoopTimeRange2(NULL, true, false, &timeSel1, &timeSel2, false); PreventUIRefresh(-1); if (_undoTitle) Undo_EndBlock2(NULL, _undoTitle, UNDO_STATE_ALL); return true; } return false; }
void SelItems::Restore(MediaTrack* tr) { bool* bUsed = NULL; if (m_selItems.GetSize()) { bUsed = new bool[m_selItems.GetSize()]; memset(bUsed, 0, sizeof(bool) * m_selItems.GetSize()); } if (tr == NULL) { PreventUIRefresh(1); for (int i = 1; i <= GetNumTracks(); i++) Match(CSurf_TrackFromID(i, false), bUsed); PreventUIRefresh(-1); } else Match(tr, bUsed); // Delete unused items for (int i = m_selItems.GetSize()-1; i >= 0 ; i--) if (!bUsed[i]) m_selItems.Delete(i, true); delete[] bUsed; }
// bUsed is an array of bools with size == m_selItems.GetSize(), used to "check off" when an item from that list is used // caller initializes bUsed void SelItems::Match(MediaTrack* tr, bool* bUsed) { PreventUIRefresh(1); int nbitems=GetTrackNumMediaItems(tr); for (int i = 0; i < nbitems; i++) { MediaItem* mi = GetTrackMediaItem(tr, i); GetSetMediaItemInfo(mi, "B_UISEL", &g_bFalse); GUID* g = (GUID*)GetSetMediaItemInfo(mi, "GUID", NULL); for (int j = 0; j < m_selItems.GetSize(); j++) if (!bUsed[j] && GuidsEqual(m_selItems.Get(j), g)) { bUsed[j] = true; GetSetMediaItemInfo(mi, "B_UISEL", &g_bTrue); break; } } PreventUIRefresh(-1); }
bool GotoMarkerRegion(ReaProject* _proj, int _num, int _flags, bool _select = false) { bool isrgn; double pos, end; int x=0, n; while ((x = EnumProjectMarkers3(_proj, x, &isrgn, &pos, &end, NULL, &n, NULL))) if (n == _num && ((!isrgn && _flags&SNM_MARKER_MASK) || (isrgn && _flags&SNM_REGION_MASK))) { PreventUIRefresh(1); if (_select && isrgn && (_flags&SNM_REGION_MASK)) GetSet_LoopTimeRange2(NULL, true, true, &pos, &end, false); // seek is managed below int* opt = (int*)GetConfigVar("smoothseek"); // obeys smooth seek SetEditCurPos2(_proj, pos, true, opt && *opt); // includes an undo point, if enabled in prefs PreventUIRefresh(-1); return true; } return false; }
void RestoreLastSelItemTrack(COMMAND_T* ct) { PreventUIRefresh(1); for (int i = 1; i <= GetNumTracks(); i++) { MediaTrack* tr = CSurf_TrackFromID(i, false); if (*(int*)GetSetMediaTrackInfo(tr, "I_SELECTED", NULL)) { GUID* g = (GUID*)GetSetMediaTrackInfo(tr, "GUID", NULL); for (int j = 0; j < g_selItemsTrack.Get()->GetSize(); j++) if (GuidsEqual(g, &g_selItemsTrack.Get()->Get(j)->m_guid)) { g_selItemsTrack.Get()->Get(j)->PreviousSelection(tr); break; } } } PreventUIRefresh(-1); Undo_OnStateChangeEx(SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); UpdateArrange(); }
void SetTrackHeight(MediaTrack* track, int height, bool useChunk) { if (!useChunk) { GetSetMediaTrackInfo(track, "I_HEIGHTOVERRIDE", &height); PreventUIRefresh(1); Main_OnCommand(41327, 0); Main_OnCommand(41328, 0); PreventUIRefresh(-1); } else { SNM_ChunkParserPatcher p(track); char pTrackLine[BUFFER_SIZE] = ""; if (p.Parse(SNM_GET_CHUNK_CHAR, 1, "TRACK", "TRACKHEIGHT", 0, 1, pTrackLine)) { _snprintfSafe(pTrackLine, BUFFER_SIZE, "%d", height); p.ParsePatch(SNM_SET_CHUNK_CHAR, 1, "TRACK", "TRACKHEIGHT", 0, 1, pTrackLine); } } }
void RestoreSelTrackSelItems(int iSlot) { PreventUIRefresh(1); for (int i = 1; i <= GetNumTracks(); i++) { MediaTrack* tr = CSurf_TrackFromID(i, false); if (*(int*)GetSetMediaTrackInfo(tr, "I_SELECTED", NULL)) { GUID* g = (GUID*)GetSetMediaTrackInfo(tr, "GUID", NULL); for (int j = 0; j < g_selItemsTrack.Get()->GetSize(); j++) if (GuidsEqual(g, &g_selItemsTrack.Get()->Get(j)->m_guid)) { g_selItemsTrack.Get()->Get(j)->Restore(tr, iSlot); break; } } } PreventUIRefresh(-1); char cUndoText[256]; sprintf(cUndoText, __LOCALIZE_VERFMT("Restore selected track(s) selected item(s), slot %d","sws_undo"), iSlot+1); Undo_OnStateChangeEx(cUndoText, UNDO_STATE_ITEMS, -1); UpdateArrange(); }
void MoveTempo (COMMAND_T* ct) { BR_Envelope tempoMap(GetTempoEnv()); if (!tempoMap.Count()) return; double cursor = GetCursorPositionEx(NULL); double tDiff = 0; int targetId = -1; // Find tempo marker closest to the edit cursor if ((int)ct->user == 3) { targetId = tempoMap.FindClosest(cursor); if (targetId == 0) ++targetId; if (!tempoMap.ValidateId(targetId)) return; double cTime; tempoMap.GetPoint(targetId, &cTime, NULL, NULL, NULL); tDiff = cursor - cTime; } // Just get time difference for selected points else { if ((int)ct->user == 2 || (int)ct->user == -2) tDiff = 1 / GetHZoomLevel() * (double)ct->user / 2; else tDiff = (double)ct->user/10000; } if (tDiff == 0) return; // Loop through selected points int skipped = 0; int count = (targetId != -1) ? (1) : (tempoMap.CountSelected()); for (int i = 0; i < count; ++i) { if (int id = ((int)ct->user == 3) ? (targetId) : (tempoMap.GetSelected(i))) // skip first point skipped += (MoveTempo(tempoMap, id, tDiff)) ? (0) : (1); } // Commit changes PreventUIRefresh(1); // prevent jumpy cursor if (tempoMap.Commit()) { if ((int)ct->user == 3) SetEditCurPos2(NULL, cursor, false, false); // always keep cursor position when moving to closest tempo marker Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -1); } PreventUIRefresh(-1); // Warn user if some points weren't processed static bool s_warnUser = true; if (s_warnUser && skipped != 0) { char buffer[512]; _snprintfSafe(buffer, sizeof(buffer), __LOCALIZE_VERFMT("%d of the selected points didn't get processed because some points would end up with illegal BPM or position. Would you like to be warned if it happens again?", "sws_mbox"), skipped); int userAnswer = ShowMessageBox(buffer, __LOCALIZE("SWS - Warning", "sws_mbox"), 4); if (userAnswer == 7) s_warnUser = false; } }
void MoveGridToEditPlayCursor (COMMAND_T* ct) { // Find cursor immediately (in case of playback we want the most accurate position) double cursor = ((int)ct->user == 1 || (int)ct->user == 3) ? (GetPlayPositionEx(NULL)) : (GetCursorPositionEx(NULL)); // Make sure tempo map already has at least one point created (for some reason it won't work if creating it directly in chunk) InitTempoMap(); BR_Envelope tempoMap(GetTempoEnv()); if (!tempoMap.Count()) return; // Set preferences to prevent play cursor from jumping int seekmodes = 0; if ((int)ct->user == 1 || (int)ct->user == 3) { GetConfig("seekmodes", seekmodes); SetConfig("seekmodes", ClearBit(seekmodes, 5)); } // Find closest grid double grid = 0; if ((int)ct->user == 0 || (int)ct->user == 1) grid = GetClosestGrid(cursor); else if ((int)ct->user == 2 || (int)ct->user == 3) grid = GetClosestMeasureGrid(cursor); else if ((int)ct->user == 4) grid = GetClosestLeftSideGrid(cursor); else grid = GetClosestRightSideGrid(cursor); int targetId = tempoMap.Find(grid, MIN_TEMPO_DIST); // No tempo marker on grid, create it if (!tempoMap.ValidateId(targetId)) { int prevId = tempoMap.FindPrevious(grid); double value = tempoMap.ValueAtPosition(grid); int shape; tempoMap.GetPoint(prevId, NULL, NULL, &shape, NULL); tempoMap.CreatePoint(prevId+1, grid, value, shape, 0, false); targetId = prevId+1; } double tDiff = cursor - grid; // Commit changes and warn user if needed if (tDiff != 0) { if (MoveTempo(tempoMap, targetId, tDiff)) { PreventUIRefresh(1); // prevent jumpy cursor if (tempoMap.Commit()) { // Restore edit cursor only if moving to it if ((int)ct->user != 1 && (int)ct->user != 3) SetEditCurPos2(NULL, cursor, false, false); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -1); } PreventUIRefresh(-1); } else { static bool s_warnUser = true; if (s_warnUser) { int userAnswer = ShowMessageBox(__LOCALIZE("Moving grid failed because some tempo markers would end up with illegal BPM or position. Would you like to be warned if it happens again?", "sws_mbox"), __LOCALIZE("SWS - Warning", "sws_mbox"), 4); if (userAnswer == 7) s_warnUser = false; } } } // Restore preferences if ((int)ct->user == 1 || (int)ct->user == 3) SetConfig("seekmodes", seekmodes); }
void DeleteTempoPreserveItems (COMMAND_T* ct) { BR_Envelope tempoMap(GetTempoEnv()); if (!tempoMap.CountSelected()) return; // Get items' position info and set their timebase to time vector<BR_MidiItemTimePos> items; double firstMarker; tempoMap.GetPoint(tempoMap.GetSelected(0), &firstMarker, NULL, NULL, NULL); int itemCount = ((int)ct->user) ? CountSelectedMediaItems(NULL) : CountMediaItems(NULL); items.reserve(itemCount); for (int i = 0; i < itemCount; ++i) { MediaItem* item = ((int)ct->user) ? GetSelectedMediaItem(NULL, i) : GetMediaItem(NULL, i); double itemEnd = GetMediaItemInfo_Value(item, "D_POSITION") + GetMediaItemInfo_Value(item, "D_LENGTH"); if (itemEnd >= firstMarker) { items.push_back(BR_MidiItemTimePos(item)); SetMediaItemInfo_Value(item, "C_BEATATTACHMODE", 0); } } // Readjust unselected tempo markers double offset = 0; for (int i = 0; i < tempoMap.CountConseq(); ++i) { int startId, endId; tempoMap.GetConseq (i, &startId, &endId); if (endId == tempoMap.Count()-1) continue; // no points after selection, nothing to adjust if (startId == 0 && (++startId > endId)) continue; // skip first point // Get musical length of selection double musicalLen = 0; for (int i = startId - 1; i <= endId; ++i ) { double t0, t1, b0, b1; int s0; tempoMap.GetPoint(i, &t0, &b0, &s0, NULL); tempoMap.GetPoint(i+1, &t1, &b1, NULL, NULL); if (i == startId-1) t0 -= offset; // readjust position to original (earlier iterations moved it) if (s0 == SQUARE) musicalLen += (t1-t0) * b0 / 240; else musicalLen += (t1-t0) * (b0+b1) / 480; } // Readjust points after selection double t0, t1, b0, b1; int s0; tempoMap.GetPoint(startId - 1, &t0, &b0, &s0, NULL); tempoMap.GetPoint(endId + 1, &t1, &b1, NULL, NULL); if (s0 == SQUARE) offset = (t0 + (240*musicalLen) / b0) - t1; else offset = (t0 + (480*musicalLen) / (b0 + b1)) - t1; while (!tempoMap.GetSelection(++endId) && endId < tempoMap.Count()) { double t; tempoMap.GetPoint(endId, &t, NULL, NULL, NULL); t += offset; tempoMap.SetPoint (endId, &t, NULL, NULL, NULL); } } // Delete selected tempo markers int idOffset = 0; for (int i = 0; i < tempoMap.CountSelected(); ++i) { int id = tempoMap.GetSelected(i) - idOffset; if (id != 0) // skip first point { tempoMap.DeletePoint(id); ++idOffset; } } // Commit tempo map and restore position info PreventUIRefresh(1); if (tempoMap.Commit(false)) { for (size_t i = 0; i < items.size(); ++i) items[i].Restore(); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -1); } PreventUIRefresh(-1); }
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); } }
// param _allTakes only makes sense if jobTake() is used bool FindWnd::FindMediaItem(int _dir, bool _allTakes, bool (*jobTake)(MediaItem_Take*,const char*), bool (*jobItem)(MediaItem*,const char*)) { bool update = false, found = false, sel = true; if (g_searchStr && *g_searchStr) { PreventUIRefresh(1); MediaItem* startItem = NULL; bool clearCurrentSelection = false; if (_dir) { WDL_PtrList<MediaItem> items; SNM_GetSelectedItems(NULL, &items); if (items.GetSize()) { startItem = FindPrevNextItem(_dir, items.Get(_dir > 0 ? 0 : items.GetSize()-1)); clearCurrentSelection = (startItem != NULL); } else startItem = FindPrevNextItem(_dir, NULL); } else { startItem = FindPrevNextItem(1, NULL); clearCurrentSelection = (startItem != NULL); } if (clearCurrentSelection) { Undo_BeginBlock2(NULL); Main_OnCommand(40289,0); // unselect all items update = true; } MediaItem* item = NULL; MediaTrack* startTr = startItem ? GetMediaItem_Track(startItem) : NULL; int startTrIdx = startTr ? CSurf_TrackToID(startTr, false) : -1; if (startTr && startItem && startTrIdx>=0) { // find startItem idx int startItemIdx=-1; while (item != startItem) item = GetTrackMediaItem(startTr,++startItemIdx); bool firstItem=true, breakSelection=false; for (int i=startTrIdx; !breakSelection && i <= CountTracks(NULL) && i>=1; i += (!_dir ? 1 : _dir)) { MediaTrack* tr = CSurf_TrackFromID(i, false); int nbItems = GetTrackNumMediaItems(tr); for (int j = (firstItem ? startItemIdx : (_dir >= 0 ? 0 : (nbItems-1))); tr && !breakSelection && j < nbItems && j >= 0; j += (!_dir ? 1 : _dir)) { item = GetTrackMediaItem(tr,j); firstItem = false; // search at item level if (jobItem) { if (jobItem(item, g_searchStr)) { if (!update) Undo_BeginBlock2(NULL); update = found = true; GetSetMediaItemInfo(item, "B_UISEL", &sel); if (_dir) breakSelection = true; } } // search at take level else if (jobTake) { int nbTakes = GetMediaItemNumTakes(item); for (int k=0; item && k < nbTakes; k++) { MediaItem_Take* tk = GetMediaItemTake(item, k); if (tk && (_allTakes || (!_allTakes && tk == GetActiveTake(item)))) { if (jobTake(tk, g_searchStr)) { if (!update) Undo_BeginBlock2(NULL); update = found = true; GetSetMediaItemInfo(item, "B_UISEL", &sel); if (_dir) { breakSelection = true; break; } } } } } } } } UpdateNotFoundMsg(found); if (found && m_zoomSrollItems) { if (!_dir) ZoomToSelItems(); else if (item) ScrollToSelItem(item); } PreventUIRefresh(-1); } if (update) { UpdateTimeline(); Undo_EndBlock2(NULL, __LOCALIZE("Find: change media item selection","sws_undo"), UNDO_STATE_ALL); } return update; }