bool MakeSingleTrackTemplateChunk(WDL_FastString* _in, WDL_FastString* _out, bool _delItems, bool _delEnvs, int _tmpltIdx, bool _obeyOffset) { if (_in && _in->GetLength() && _out && _in!=_out) { _out->Set(""); // truncate to the track #_tmpltIdx found in the template SNM_ChunkParserPatcher pin(_in); if (pin.GetSubChunk("TRACK", 1, _tmpltIdx, _out) >= 0) { int* offsOpt = _obeyOffset ? (int*)GetConfigVar("templateditcursor") : NULL; // >= REAPER v4.15 // remove receives from the template as we deal with a single track // note: possible with multiple tracks in a same template file (w/ routings between those tracks) SNM_TrackEnvParserPatcher pout(_out); pout.RemoveLine("TRACK", "AUXRECV", 1, -1, "MIDIOUT"); if (_delItems) // remove items from template (in one go) pout.RemoveSubChunk("ITEM", 2, -1); else if (offsOpt && *offsOpt) { // or offset them if needed double add = GetCursorPositionEx(NULL); pout.ParsePatch(SNM_D_ADD, 2, "ITEM", "POSITION", -1, 1, &add); } if (_delEnvs) // remove all envs from template (in one go) pout.RemoveEnvelopes(); else if (offsOpt && *offsOpt) // or offset them if needed pout.OffsetEnvelopes(GetCursorPositionEx(NULL)); return true; } } return false; }
void GetTimeSegmentPositions(TimeSegment timeSegment, double &dStartPos, double &dEndPos, MediaItem* item) { double dOrgCursorPos = GetCursorPositionEx(0); bool bRefreshCurPos = false; switch(timeSegment) { case eTIMESEGMENT_TIMESEL: //Main_OnCommandEx(ID_GOTO_TIMESEL_END, 0, 0); //dEndPos = GetCursorPositionEx(0); //Main_OnCommandEx(ID_GOTO_TIMESEL_START, 0, 0); //dStartPos = GetCursorPositionEx(0); GetSet_LoopTimeRange2(0, false, false, &dStartPos, &dEndPos, false); break; case eTIMESEGMENT_SELITEM: if(item != NULL) { dStartPos = GetMediaItemInfo_Value(item, "D_POSITION"); dEndPos = dStartPos + GetMediaItemInfo_Value(item, "D_LENGTH"); } else { Main_OnCommandEx(ID_GOTO_SELITEM_END, 0, 0); dEndPos = GetCursorPositionEx(0); Main_OnCommandEx(ID_GOTO_SELITEM_START, 0, 0); dStartPos = GetCursorPositionEx(0); bRefreshCurPos = true; } break; case eTIMESEGMENT_LOOP: //Main_OnCommandEx(ID_GOTO_LOOP_END, 0, 0); //dEndPos = GetCursorPositionEx(0); //Main_OnCommandEx(ID_GOTO_LOOP_START, 0, 0); //dStartPos = GetCursorPositionEx(0); GetSet_LoopTimeRange2(0, false, true, &dStartPos, &dEndPos, false); break; case eTIMESEGMENT_PROJECT: Main_OnCommandEx(ID_GOTO_PROJECT_END, 0, 0); dEndPos = GetCursorPositionEx(0); //Main_OnCommandEx(ID_GOTO_PROJECT_START, 0, 0); //dStartPos = GetCursorPositionEx(0); dStartPos = *(int*)GetConfigVar("projtimeoffs"); bRefreshCurPos = true; break; //case eTIMESEGMENT_CURRENTMEASURE: // Main_OnCommandEx(ID_GOTO_CURMEASURE_START, 0, 0); // dStartPos = GetCursorPositionEx(0); // Main_OnCommandEx(ID_GOTO_NEXTMEASURE_START, 0, 0); // dEndPos = GetCursorPositionEx(0); //break; default: break; } if(bRefreshCurPos) SetEditCurPos2(0, dOrgCursorPos, true, false); }
void ME_CCEventAtEditCursor (COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { BR_MouseInfo mouseInfo(BR_MouseInfo::MODE_MIDI_EDITOR_ALL); if (mouseInfo.GetMidiEditor()) { if (MediaItem_Take* take = MIDIEditor_GetTake(mouseInfo.GetMidiEditor())) { double positionPPQ = MIDI_GetPPQPosFromProjTime(take, GetCursorPositionEx(NULL)); int lane, value; if (mouseInfo.GetCCLane(&lane, &value, NULL) && value >= 0) { if (lane == CC_TEXT_EVENTS || lane == CC_SYSEX || lane == CC_BANK_SELECT || lane == CC_VELOCITY) MessageBox((HWND)mouseInfo.GetMidiEditor(), __LOCALIZE("Can't insert in velocity, text, sysex and bank select lanes","sws_mbox"), __LOCALIZE("SWS/BR - Warning","sws_mbox"), MB_OK); else { bool do14bit = (lane >= CC_14BIT_START) ? true : false; int type = (lane == CC_PROGRAM) ? (STATUS_PROGRAM) : (lane == CC_CHANNEL_PRESSURE ? STATUS_CHANNEL_PRESSURE : (lane == CC_PITCH ? STATUS_PITCH : STATUS_CC)); int channel = MIDIEditor_GetSetting_int(mouseInfo.GetMidiEditor(), "default_note_chan"); int msg2 = CheckBounds(lane, 0, 127) ? ((value >> 7) | 0) : (value & 0x7F); int msg3 = CheckBounds(lane, 0, 127) ? (value & 0x7F) : ((value >> 7) | 0); int targetLane = (do14bit) ? lane - CC_14BIT_START : lane; int targetLane2 = (do14bit) ? targetLane + 32 : lane; MIDI_InsertCC(take, true, false, positionPPQ, type, channel, (CheckBounds(targetLane, 0, 127) ? targetLane : msg2), msg3); if (do14bit) MIDI_InsertCC(take, true, false, positionPPQ, type, channel, targetLane2, msg2); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); } } } }
// replace or paste items sub-chunk _tmpltItems // _paste==false for replace, paste otherwise // _p: optional (to factorize chunk updates) bool ReplacePasteItemsFromTrackTemplate(MediaTrack* _tr, WDL_FastString* _tmpltItems, bool _paste, SNM_ChunkParserPatcher* _p) { bool updated = false; if (_tr && _tr != GetMasterTrack(NULL) && _tmpltItems) // no items on master { SNM_ChunkParserPatcher* p = (_p ? _p : new SNM_ChunkParserPatcher(_tr)); // delete current items? if (!_paste) updated |= p->RemoveSubChunk("ITEM", 2, -1); // insert template items if (_tmpltItems->GetLength()) { WDL_FastString tmpltItems(_tmpltItems); // do not alter _tmpltItems! // offset items if needed int* offsOpt = (int*)GetConfigVar("templateditcursor"); // >= REAPER v4.15 if (offsOpt && *offsOpt) { double add = GetCursorPositionEx(NULL); SNM_ChunkParserPatcher pitems(&tmpltItems); pitems.ParsePatch(SNM_D_ADD, 1, "ITEM", "POSITION", -1, 1, &add); } p->GetChunk()->Insert(tmpltItems.Get(), p->GetChunk()->GetLength()-2); // -2: before ">\n" p->IncUpdates(); // as we directly work on the chunk updated = true; } if (!_p) DELETE_NULL(p); // + auto-commit if needed } return updated; }
void InsertSilence(COMMAND_T* _ct) { char val[64]=""; lstrcpyn(val, g_lastSilenceVal[(int)_ct->user], sizeof(val)); if (PromptUserForString(GetMainHwnd(), SWS_CMD_SHORTNAME(_ct), val, sizeof(val)) && *val) { double pos = GetCursorPositionEx(NULL), len = 0.0; switch ((int)_ct->user) { case 0: // s len = parse_timestr_len(val, pos, 3); break; case 1: // meas.beat { /* no! would not take get tempo markers into account since 'val' is not inserted yet len = parse_timestr_len(val, pos, 2); break; */ int in_meas = atoi(val); double in_beats = 0.0; char* p = strchr(val, '.'); if (p && p[1]) in_beats = atof(p+1); double bpm; int num, den; TimeMap_GetTimeSigAtTime(NULL, pos, &num, &den, &bpm); len = in_beats*(60.0/bpm) + in_meas*((240.0*num/den)/bpm); break; } case 2: // smp len = parse_timestr_len(val, pos, 4); break; } if (len>0.0) { lstrcpyn(g_lastSilenceVal[(int)_ct->user], val, sizeof(val)); InsertSilence(SWS_CMD_SHORTNAME(_ct), pos, len); // includes an undo point } else MessageBox(GetMainHwnd(), __LOCALIZE("Invalid input!","sws_mbox"), __LOCALIZE("S&M - Error","sws_mbox"), MB_OK); } }
EnvelopeProcessor::ErrorCode EnvelopeProcessor::generateSelectedTrackEnvLfo() { TrackEnvelope* envelope = GetSelectedTrackEnvelope(0); if(!envelope) return eERRORCODE_NOENVELOPE; Undo_BeginBlock2(0); //! \todo: use insert/goto actions AFTER error returns double dStartPos, dEndPos; GetTimeSegmentPositions(_parameters.timeSegment, dStartPos, dEndPos); if(dStartPos==dEndPos) return eERRORCODE_NULLTIMESELECTION; double dOrgCursorPos = GetCursorPositionEx(0); SetEditCurPos2(0, dStartPos-EPSILON_TIME, false, false); Main_OnCommandEx(ID_ENVELOPE_INSERT_POINT, 0, 0); SetEditCurPos2(0, dEndPos+EPSILON_TIME, false, false); Main_OnCommandEx(ID_ENVELOPE_INSERT_POINT, 0, 0); SetEditCurPos2(0, dOrgCursorPos, false, false); //Main_OnCommandEx(ID_MOVE_TIMESEL_NUDGE_LEFTEDGE_LEFT, 0, 0); //Main_OnCommandEx(ID_MOVE_TIMESEL_NUDGE_RIGHTEDGE_RIGHT, 0, 0); //Main_OnCommandEx(ID_GOTO_TIMESEL_START, 0, 0); //Main_OnCommandEx(ID_ENVELOPE_INSERT_POINT, 0, 0); //Main_OnCommandEx(ID_GOTO_TIMESEL_END, 0, 0); //Main_OnCommandEx(ID_ENVELOPE_INSERT_POINT, 0, 0); //Main_OnCommandEx(ID_MOVE_TIMESEL_NUDGE_LEFTEDGE_RIGHT, 0, 0); //Main_OnCommandEx(ID_MOVE_TIMESEL_NUDGE_RIGHTEDGE_LEFT, 0, 0); //Main_OnCommandEx(ID_ENVELOPE_DELETE_ALL_POINTS_TIMESEL, 0, 0); ErrorCode res = generateTrackLfo(envelope, dStartPos, dEndPos, _parameters.waveParams, _parameters.precision); //UpdateTimeline(); Undo_EndBlock2(NULL, __LOCALIZE("Track envelope LFO","sws_undo"), UNDO_STATE_TRACKCFG); return res; }
bool FindWnd::FindMarkerRegion(int _dir) { if (!_dir) return false; bool update = false, found = false; if (g_searchStr && *g_searchStr) { double startPos = GetCursorPositionEx(NULL); int id, x = 0; bool bR; double dPos, dRend, dMinMaxPos = _dir < 0 ? -DBL_MAX : DBL_MAX; const char *cName; while ((x=EnumProjectMarkers2(NULL, x, &bR, &dPos, &dRend, &cName, &id))) { if (_dir == 1 && dPos > startPos) { if (stristr(cName, g_searchStr)) { found = true; dMinMaxPos = min(dPos, dMinMaxPos); } } else if (_dir == -1 && dPos < startPos) { if (stristr(cName, g_searchStr)) { found = true; dMinMaxPos = max(dPos, dMinMaxPos); } } } UpdateNotFoundMsg(found); if (found) { SetEditCurPos2(NULL, dMinMaxPos, true, false); update = true; } } if (update) Undo_OnStateChangeEx2(NULL, __LOCALIZE("Find: change edit cursor position","sws_undo"), UNDO_STATE_ALL, -1); // in case the pref "undo pt for edit cursor positions" is enabled.. return update; }
void InsertMarker(COMMAND_T* _ct) { AddProjectMarker2(NULL, false, (int)_ct->user && (GetPlayStateEx(NULL)&1) ? GetPlayPositionEx(NULL) : GetCursorPositionEx(NULL), 0.0, "", -1, 0); UpdateTimeline(); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_MISCCFG, -1); }
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); }