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 ME_ShowUsedCCLanesDetect14Bit (COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { if (MediaItem_Take* take = MIDIEditor_GetTake(MIDIEditor_GetActive())) { RprTake rprTake(take); if (RprMidiCCLane* laneView = new (nothrow) RprMidiCCLane(rprTake)) { int defaultHeight = 67; // same height FNG versions use (to keep behavior identical) set<int> usedCC = GetUsedCCLanes(MIDIEditor_GetTake(MIDIEditor_GetActive()), 2); for (int i = 0; i < laneView->countShown(); ++i) if (usedCC.find(laneView->getIdAt(i)) == usedCC.end()) laneView->remove(i--); // Special case: Bank select and CC0 (from FNG version to keep behavior identical) if (usedCC.find(0) != usedCC.end() && usedCC.find(CC_BANK_SELECT) != usedCC.end() && !laneView->isShown(131)) laneView->append(131, defaultHeight); for (set<int>::iterator it = usedCC.begin(); it != usedCC.end(); ++it) { if (!laneView->isShown(*it)) laneView->append(*it, defaultHeight); else { for (int i = 0; i < laneView->countShown(); ++i) { if (laneView->getIdAt(i) == *it && laneView->getHeight(i) == 0) laneView->setHeightAt(i, defaultHeight); } } } if (laneView->countShown() == 0) laneView->append(-1, 0); delete laneView; Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); } } }
void SetMIDIInputChannel(COMMAND_T* _ct) { bool updated = false; int ch = (int)_ct->user; // 0: all channels for (int i=1; i <= GetNumTracks(); i++) // skip master { MediaTrack* tr = CSurf_TrackFromID(i, false); if (tr && *(int*)GetSetMediaTrackInfo(tr, "I_SELECTED", NULL)) { int in = *(int*)GetSetMediaTrackInfo(tr, "I_RECINPUT", NULL); if (((in & 0x1000) == 0x1000) && ((in & 0x1F) != ch)) { in &= 0x1FE0; in |= ch; GetSetMediaTrackInfo(tr, "I_RECINPUT", &in); updated = true; } } } if (updated) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
void PasteTrackGrouping(COMMAND_T* _ct) { int updates = 0; for (int i=0; i <= GetNumTracks(); i++) // incl. master { MediaTrack* tr = CSurf_TrackFromID(i, false); if (tr && *(int*)GetSetMediaTrackInfo(tr, "I_SELECTED", NULL)) { SNM_ChunkParserPatcher p(tr); updates += p.RemoveLines("GROUP_FLAGS", true); // brutal removing ok: "GROUP_FLAGS" is not part of freeze data int patchPos = p.Parse(SNM_GET_CHUNK_CHAR, 1, "TRACK", "TRACKHEIGHT", 0, 0, NULL, NULL, "MAINSEND"); if (patchPos > 0) { p.GetChunk()->Insert(g_trackGrpClipboard.Get(), --patchPos); p.IncUpdates(); // as we're directly working on the cached chunk.. updates++; } } } if (updates) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
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 startLimit, endLimit; double positionPPQ = GetOriginalPpqPos(take, MIDI_GetPPQPosFromProjTime(take, GetCursorPositionEx(NULL)), NULL, &startLimit, &endLimit); if (!CheckBounds(positionPPQ, startLimit, endLimit)) return; 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 || lane == CC_VELOCITY_OFF) 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); } } } }
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 GotoMarker(COMMAND_T* _ct) { if (GotoMarkerRegion(NULL, ((int)_ct->user)+1, SNM_MARKER_MASK)) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
static void HideUnusedCCLanes(COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { HideUnusedCCLanes(UNDO_STATE_ITEMS, &ct->user); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); }
void ContinuousActionStopAll () { if (g_actionInProgress && g_actionInProgress->DoUndo && g_actionInProgress->DoUndo()) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(SWSGetCommandByID(g_actionInProgress->cmd)), UNDO_STATE_ALL, -1); ContinuousActionInit(false, 0, NULL); }
void EditTempoGradual (COMMAND_T* ct) { // Get tempo map BR_Envelope tempoMap(GetTempoEnv()); if (!tempoMap.CountSelected()) return; // Get values and type of operation to be performed bool percentage = false; double diff; if (GetFirstDigit((int)ct->user) == 1) diff = (double)ct->user / 1000; else { diff = (double)ct->user / 200000; percentage = true; } // Loop through selected points and perform BPM calculations int skipped = 0; for (int i = 0; i < tempoMap.CountSelected(); ++i) { int id = tempoMap.GetSelected(i); // Hold new values for selected and next point double Nb1, Nt1; vector<double> selPos; vector<double> selBpm; ///// CURRENT POINT ///// ///////////////////////// // Store new values for selected points into vectors int offset = 0; while (true) { // Get point currently in the loop and points surrounding it double t0, t1, t2, b0, b1, b2; int s0, s1; bool P0 = tempoMap.GetPoint(id+offset-1, &t0, &b0, &s0, NULL); tempoMap.GetPoint(id+offset, &t1, &b1, &s1, NULL); tempoMap.GetPoint(id+offset+1, &t2, &b2, NULL, NULL); // If square or not selected, break if (s1 == SQUARE || !tempoMap.GetSelection(id+offset)) { // If breaking on the first selected point, don't adjust i (so for loop doesn't go backwards). i += (offset == 0) ? (0) : (offset-1); --offset; // since this point is not taken into account, correct offset break; } // Get new BPM double bpm = b1 + ((percentage) ? (b1*diff) : (diff)); if (bpm < MIN_BPM) bpm = MIN_BPM; else if (bpm > MAX_BPM) bpm = MAX_BPM; // Get new position (special case for the first point) double position; if (offset == 0) { if (P0 && s0 == LINEAR) { position = (t1*(b0+b1) + t0*(bpm-b1)) / (b0 + bpm); // first point moves but the one before it if (position - t0 < MIN_TEMPO_DIST) // doesn't so check if their distance is legal break; } else position = t1; } else position = ((b0+b1)*(t1-t0) + selPos.back() * (selBpm.back() + bpm)) / (selBpm.back() + bpm); // Store new values selPos.push_back(position); selBpm.push_back(bpm); ++offset; } // Check for illegal position/no linear points encountered (in that case offset is -1 so skipped won't change) if (!selPos.size()) SKIP(skipped, offset+1); ///// NEXT POINT ///// ////////////////////// // Get points after the last selected point double t1, t2; double b1, b2; int s2; bool P1 = tempoMap.GetPoint(id+offset+1, &t1, &b1, &s2, NULL); bool P2 = tempoMap.GetPoint(id+offset+2, &t2, &b2, NULL, NULL); // Calculate new value and position for the next point if (P1) { // Get last selected tempo point (old and new) double Nb0 = selBpm.back(); double Nt0 = selPos.back(); double t0, b0; tempoMap.GetPoint(id+offset, &t0, &b0, NULL, NULL); if (P2) { if (s2 == SQUARE) { double f1 = (b0+b1)*(t1-t0); double f2 = b1*(t2-t1); double a = Nb0; double b = (a*(Nt0+t2) + f1+f2) / 2; double c = a*(Nt0*t2) + f1*t2 + f2*Nt0; Nt1 = c / (b + sqrt(pow(b,2) - a*c)); Nb1 = f2 / (t2-Nt1); } else { double f1 = (b0+b1)*(t1-t0); double f2 = (b1+b2)*(t2-t1); double a = Nb0 - b2; double b = (a*(Nt0+t2) + f1+f2) / 2; double c = a*(Nt0*t2) + f1*t2 + f2*Nt0; Nt1 = c / (b + sqrt(pow(b,2) - a*c)); Nb1 = f2 / (t2-Nt1) - b2; } } else { Nt1 = t1; Nb1 = (b0+b1)*(t1-t0) / (t1-Nt0) - Nb0; } // If points after selected point don't exist, fake them if (!P1) Nt1 = Nt0 + 1; if (!P2) t2 = Nt1 + 1; // Check new value is legal if (Nb1 > MAX_BPM || Nb1 < MIN_BPM) SKIP(skipped, offset+1); if ((Nt1-Nt0) < MIN_TEMPO_DIST || (t2 - Nt1) < MIN_TEMPO_DIST) SKIP(skipped, offset+1); } ///// SET NEW BPM ///// /////////////////////// // Current point(s) for (int i = 0; i < (int)selPos.size(); ++i) tempoMap.SetPoint(id+i, &selPos[i], &selBpm[i], NULL, NULL); // Next point if (P1) tempoMap.SetPoint(id+offset+1, &Nt1, &Nb1, NULL, NULL); } // Commit changes if (tempoMap.Commit()) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -1); // Warn user if some points weren't processed static bool s_warnUser = true; if (s_warnUser && skipped != 0 && tempoMap.CountSelected() > 1 ) { 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; } }
// Command version with undo point and wnd update void DeleteAllRegions(COMMAND_T* ct) { DeleteAllRegions(); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_MISCCFG, -1); g_pMarkerList->Update(); }
void CueBuss(COMMAND_T* _ct) { CueBuss(SWS_CMD_SHORTNAME(_ct), (int)_ct->user); }
void SetTrackToFirstUnusedGroup(COMMAND_T* _ct) { if (SetTrackGroup(FindFirstUnusedGroup())) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
void SetTrackGroup(COMMAND_T* _ct) { if (SetTrackGroup((int)_ct->user)) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -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 EditTempo (COMMAND_T* ct) { // Get tempo map BR_Envelope tempoMap(GetTempoEnv()); if (!tempoMap.CountSelected()) return; // Get values and type of operation to be performed bool percentage = false; double diff; if (GetFirstDigit((int)ct->user) == 1) diff = (double)ct->user / 1000; else { diff = (double)ct->user / 200000; percentage = true; } // Loop through selected points and perform BPM calculations int skipped = 0; for (int i = 0; i < tempoMap.CountSelected(); ++i) { int id = tempoMap.GetSelected(i); // Hold new values for selected and surrounding points double Nt1, Nt3, Nb1, Nb3; vector<double> selPos; vector<double> selBpm; ///// CURRENT POINT ///// ///////////////////////// // Get all consequentially selected points into a vector with their new values. In case // there is consequential selection, middle musical position of a transition between first // and last selected point will preserve it's time position (where possible) int offset = 0; if (tempoMap.GetSelection(id+1)) { // Store new values for selected points into vectors double musicalMiddle = 0; vector<double> musicalLength; while (true) { // Once unselected point is encountered, break if (!tempoMap.GetSelection(id+offset)) { --offset; // since this point is not taken into account, correct offset i += offset; // in case of consequential selection, points are treated as break; // one big transition, so skip them all } // Get point currently in the loop and surrounding points double t0, t1, t2, b0, b1, b2; int s0, s1; bool P0 = tempoMap.GetPoint(id+offset-1, &t0, &b0, &s0, NULL); tempoMap.GetPoint(id+offset, &t1, &b1, &s1, NULL); tempoMap.GetPoint(id+offset+1, &t2, &b2, NULL, NULL); // Get musical length for every transition but the last double mLen = 0; if (tempoMap.GetSelection(id+offset+1)) { if (s1 == SQUARE) mLen = b1*(t2-t1) / 240; else mLen = (b1+b2)*(t2-t1) / 480; } musicalMiddle += mLen; // Get new BPM double bpm = b1 + (percentage ? (b1*diff) : (diff)); if (bpm < MIN_BPM) bpm = MIN_BPM; else if (bpm > MAX_BPM) bpm = MAX_BPM; // Get new position (special case for the first point) double position; if (!offset) { if (P0 && s0 == LINEAR) position = (t1*(b0+b1) + t0*(bpm-b1)) / (b0 + bpm); else position = t1; } else { if (s0 == LINEAR) position = (480*musicalLength.back() + selPos.back()*(bpm + selBpm.back())) / (bpm + selBpm.back()); else position = (240*musicalLength.back() + selPos.back()*selBpm.back()) / selBpm.back(); } // Store new values selPos.push_back(position); selBpm.push_back(bpm); musicalLength.push_back(mLen); ++offset; } // Find time position of musical middle and move all point so time position // of musical middle is preserved (only if previous point exists) musicalMiddle /= 2; if (tempoMap.GetPoint(id-1, NULL, NULL, NULL, NULL)) { double temp = 0; for (int i = 0; i < (int)selPos.size()-1; ++i) { temp += musicalLength[i]; if (temp >= musicalMiddle) { // Get length between the points that contain musical middle double len = musicalMiddle - (temp-musicalLength[i]); // Find original time position of musical middle double t0, t1, b0, b1; int s0; tempoMap.GetPoint(id+i, &t0, &b0, &s0, NULL); tempoMap.GetPoint(id+i+1, &t1, &b1, NULL, NULL); double prevPos = t0 + PositionAtMeasure (b0, (s0 == 1 ? b0 : b1), t1-t0, len); // Find new time position of musical middle double newPos = t0 + PositionAtMeasure (selBpm[i], (s0 == 1 ? selBpm[i] : selBpm[i+1]), selPos[i+1] - selPos[i], len); // Reset time positions of selected points double diff = newPos - prevPos; for (size_t i = 0; i < selPos.size(); ++i) selPos[i] -= diff; break; } } } } else { // Get selected point double t, b; tempoMap.GetPoint(id, &t, &b, NULL, NULL); // Get new BPM b += (percentage) ? (b*diff) : (diff); if (b < MIN_BPM) b = MIN_BPM; else if (b > MAX_BPM) b = MAX_BPM; // Store it selPos.push_back(t); selBpm.push_back(b); } ///// PREVIOUS POINT ///// ////////////////////////// // Get points before selected points double t0, t1, b0, b1; int s0, s1; bool P0 = tempoMap.GetPoint(id-2, &t0, &b0, &s0, NULL); bool P1 = tempoMap.GetPoint(id-1, &t1, &b1, &s1, NULL); if (P1) { // Get first selected point (old and new) double t2, b2; tempoMap.GetPoint(id, &t2, &b2, NULL, NULL); double Nb2 = selBpm.front(); double Nt2 = selPos.front(); // If point behind previous doesn't exist, fake it as square if (!P0) s0 = SQUARE; // Calculate new value and position for previous point if (!P0 || s0 == SQUARE) { if (s1 == SQUARE) { Nt1 = t1; Nb1 = b1*(t2-t1) / (Nt2-Nt1); } else { Nt1 = t1; Nb1 = (b1+b2)*(t2-t1) / (Nt2-Nt1) - Nb2; } } else { if (s1 == SQUARE) { double f1 = (b0+b1) *(t1-t0); double f2 = b1*(t2-t1); double a = b0; double b = (a*(t0+Nt2) + f1+f2) / 2; double c = a*(t0*Nt2) + f1*Nt2 + f2*t0; Nt1 = c / (b + sqrt(pow(b,2) - a*c)); Nb1 = f2 / (Nt2 - Nt1); } else { double f1 = (b0+b1)*(t1-t0); double f2 = (b1+b2)*(t2-t1); double a = b0 - Nb2; double b = (a*(t0+Nt2) + f1+f2) / 2; double c = a*(t0*Nt2) + f1*Nt2 + f2*t0; Nt1 = c / (b + sqrt(pow(b,2) - a*c)); Nb1 = f2 / (Nt2 - Nt1) - Nb2; } } // If point behind previous doesn't exist, fake it's position so it can pass legality check if (!P0) t0 = Nt1 - 1; // Check new value is legal if (Nb1 > MAX_BPM || Nb1 < MIN_BPM) SKIP(skipped, offset+1); if ((Nt1-t0) < MIN_TEMPO_DIST || (Nt2 - Nt1) < MIN_TEMPO_DIST) SKIP(skipped, offset+1 ); } ///// NEXT POINT ///// ////////////////////// // Get points after selected points double t3, t4, b3, b4; int s3; bool P3 = tempoMap.GetPoint(id+offset+1, &t3, &b3, &s3, NULL); bool P4 = tempoMap.GetPoint(id+offset+2, &t4, &b4, NULL, NULL); if (P3) { // Get last selected point (old and new) double t2, b2; int s2; tempoMap.GetPoint(id+offset, &t2, &b2, &s2, NULL); double Nb2 = selBpm.back(); double Nt2 = selPos.back(); // Calculate new value and position for next point if (s2 == SQUARE) { if (P4) { if (s3 == SQUARE) { Nt3 = (b2*(t3-t2) + Nb2*Nt2) / Nb2; Nb3 = b3*(t4-t3) / (t4-Nt3); } else { Nt3 = (b2*(t3-t2) + Nb2*Nt2) / Nb2; Nb3 = (b3+b4)*(t4-t3) / (t4-Nt3) - b4; } } else { Nt3 = (b2*(t3-t2) + Nb2*Nt2) / Nb2; Nb3 = b3; } } else { if (P4) { if (s3 == SQUARE) { double f1 = (b2+b3)*(t3-t2); double f2 = b3*(t4-t3); double a = Nb2; double b = (a*(Nt2+t4) + f1+f2) / 2; double c = a*(Nt2*t4) + f1*t4 + f2*Nt2; Nt3 = c / (b + sqrt(pow(b,2) - a*c)); Nb3 = f2 / (t4-Nt3); } else { double f1 = (b2+b3)*(t3-t2); double f2 = (b3+b4)*(t4-t3); double a = Nb2 - b4; double b = (a*(Nt2+t4) + f1+f2) / 2; double c = a*(Nt2*t4) + f1*t4 + f2*Nt2; Nt3 = c / (b + sqrt(pow(b,2) - a*c)); Nb3 = f2 / (t4-Nt3) - b4; } } else { Nt3 = t3; Nb3 = (b2+b3)*(t3-t2) / (Nt3-Nt2) - Nb2; } } // If point after the next doesn't exist fake it's position so it can pass legality check if (!P4) t4 = Nt3 + 1; // Check new value is legal if (Nb3 > MAX_BPM || Nb3 < MIN_BPM) SKIP(skipped, offset+1); if ((Nt3-Nt2) < MIN_TEMPO_DIST || (t4 - Nt3) < MIN_TEMPO_DIST) SKIP(skipped, offset+1); } ///// SET BPM ///// /////////////////// // Previous point if (P1) tempoMap.SetPoint(id-1, &Nt1, &Nb1, NULL, NULL); // Current point(s) for (int i = 0; i < (int)selPos.size(); ++i) tempoMap.SetPoint(id+i, &selPos[i], &selBpm[i], NULL, NULL); // Next point if (P3) tempoMap.SetPoint(id+offset+1, &Nt3, &Nb3, NULL, NULL); } // Commit changes if (tempoMap.Commit()) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -1); // Warn user if some points weren't processed static bool s_warnUser = true; if (s_warnUser && skipped != 0 && tempoMap.CountSelected() > 1) { 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 RestoreSelItems(COMMAND_T* ct) { g_selItems.Get()->Restore(NULL); Undo_OnStateChangeEx(SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); UpdateTimeline(); }
void DeleteTempo (COMMAND_T* ct) { // Get tempo map BR_Envelope tempoMap(GetTempoEnv()); if (!tempoMap.CountSelected()) return; int offset = 0; // Loop through selected points and perform BPM calculations int skipped = 0; for (int i = 0; i < tempoMap.CountSelected(); ++i) { int id = tempoMap.GetSelected(i) + offset; if (id == 0) continue; // Get tempo points double t1, t2, t3, t4; double b1, b2, b3, b4; int s0, s1, s2, s3; tempoMap.GetPoint(id, &t2, &b2, &s2, NULL); bool P0 = tempoMap.GetPoint(id-2, NULL, NULL, &s0, NULL); bool P1 = tempoMap.GetPoint(id-1, &t1, &b1, &s1, NULL); bool P3 = tempoMap.GetPoint(id+1, &t3, &b3, &s3, NULL); bool P4 = tempoMap.GetPoint(id+2, &t4, &b4, NULL, NULL); // Hold new values double Nt1, Nb1; double Nt3, Nb3; // If previous point doesn't exist, fake it if (!P0) s0 = SQUARE; // Get P2-P3 length double m2; if (s2 == SQUARE) m2 = b2*(t3-t2) / 240; else m2 = (b2+b3)*(t3-t2) / 480; ///// CALCULATE BPM VALUES ///// //////////////////////////////// if (P3) { if (s0 == SQUARE) { if (s1 == SQUARE) { Nt1 = t1; Nb1 = (240*m2 + b1*(t2-t1)) / (t3-t1); } else { Nt1 = t1; Nb1 = (480*m2 + (b1+b2)*(t2-t1)) / (t3-t1) - b3; } // Check new value is legal if (Nb1 > MAX_BPM || Nb1 < MIN_BPM) SKIP(skipped, 1); // Next point stays the same P3 = false; } else { // If P4 exists... if (P4) { if (s1 == SQUARE) { if (s3 == SQUARE) { Nt3 = t2 + 240*m2 / b1; Nb3 = b3*(t4-t3) / (t4-Nt3); } else { Nt3 = t2 + 240*m2 / b1; Nb3 = (b3+b4)*(t4-t3) / (t4-Nt3) - b4; } } else { if (s3 == SQUARE) { double f1 = (b1+b2)*(t2-t1) + 480*m2; double f2 = b3*(t4-t3); double a = b1; double b = (a*(t1+t4) + f1+f2) / 2; double c = a*(t1*t4) + f1*t4 + f2*t1; Nt3 = c / (b + sqrt(pow(b,2) - a*c)); Nb3 = f2 / (t4 - Nt3); } else { double f1 = (b1+b2)*(t2-t1) + 480*m2; double f2 = (b3+b4)*(t4-t3); double a = b1-b4; double b = (a*(t1+t4) + f1+f2) / 2; double c = a*(t1*t4) + f1*t4 + f2*t1; Nt3 = c / (b + sqrt(pow(b,2) - a*c)); Nb3 = f2 / (t4 - Nt3) - b4; } } // Check new position is legal if ((Nt3 - t1) < MIN_TEMPO_DIST || (t4 - Nt3) < MIN_TEMPO_DIST) SKIP(skipped, 1); } // If P4 does not exist else { if (s1 == SQUARE) { Nt3 = t2 + 240*m2 / b1; Nb3 = b3; } else { Nt3 = t3; Nb3 = (480*m2 + (b1+b2)*(t2-t1)) / (t3-t1) - b1; } // Check new position is legal if ((Nt3 - t1) < MIN_TEMPO_DIST) SKIP(skipped, 1); } // Check new value is legal if (Nb3 > MAX_BPM || Nb3 < MIN_BPM) SKIP(skipped, 1); // Previous point stays the same P1 = false; } } else { // No surrounding points get edited P1 = false; P3 = false; } ///// SET NEW BPM ///// /////////////////////// // Previous point if (P1) tempoMap.SetPoint(id-1, &Nt1, &Nb1, NULL, NULL); // Next point if (P3) tempoMap.SetPoint(id+1, &Nt3, &Nb3, NULL, NULL); // Delete point tempoMap.DeletePoint(id); --offset; } // Commit changes if (tempoMap.Commit()) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -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 MainHideCCLanes(COMMAND_T* _ct) { if (replaceCCLanes("VELLANE -1 0 0\n")) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
void SetStartupAction(COMMAND_T* _ct) { int type=(int)_ct->user; if (PromptClearStartupAction(type, false) == IDNO) return; char idstr[SNM_MAX_ACTION_CUSTID_LEN]; lstrcpyn(idstr, __LOCALIZE("Paste command ID or identifier string here","sws_startup_action"), sizeof(idstr)); if (PromptUserForString(GetMainHwnd(), SWS_CMD_SHORTNAME(_ct), idstr, sizeof(idstr), true)) { WDL_FastString msg; if (int cmdId = SNM_NamedCommandLookup(idstr)) { // more checks: http://forum.cockos.com/showpost.php?p=1252206&postcount=1618 if (int tstNum = CheckSwsMacroScriptNumCustomId(idstr)) { // localization note: msgs shared with the CA editor msg.SetFormatted(512, __LOCALIZE_VERFMT("%s failed: unreliable command ID '%s'!","sws_startup_action"), SWS_CMD_SHORTNAME(_ct), idstr); msg.Append("\r\n"); if (tstNum==-1) msg.Append(__LOCALIZE("For SWS/S&M actions, you must use identifier strings (e.g. _SWS_ABOUT), not command IDs (e.g. 47145).\nTip: to copy such identifiers, right-click the action in the Actions window > Copy selected action cmdID/identifier string.","sws_startup_action")); else if (tstNum==-2) msg.Append(__LOCALIZE("For macros/scripts, you must use identifier strings (e.g. _f506bc780a0ab34b8fdedb67ed5d3649), not command IDs (e.g. 47145).\nTip: to copy such identifiers, right-click the macro/script in the Actions window > Copy selected action cmdID/identifier string.","sws_startup_action")); MessageBox(GetMainHwnd(), msg.Get(), __LOCALIZE("S&M - Error","sws_mbox"), MB_OK); } else { if (!type) { g_prjActions.Get()->Set(idstr); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_MISCCFG, -1); msg.SetFormatted(512, __LOCALIZE_VERFMT("'%s' is defined as project startup action","sws_startup_action"), kbd_getTextFromCmd(cmdId, NULL)); char prjFn[SNM_MAX_PATH] = ""; EnumProjects(-1, prjFn, sizeof(prjFn)); if (*prjFn) { msg.Append("\r\n"); msg.AppendFormatted(SNM_MAX_PATH, __LOCALIZE_VERFMT("for %s","sws_startup_action"), prjFn); msg.Append(".\r\n\r\n"); msg.Append(__LOCALIZE("Note: do not forget to save this project","sws_startup_action")); } } else { g_globalAction.Set(idstr); WritePrivateProfileString("Misc", "GlobalStartupAction", idstr, g_SNM_IniFn.Get()); msg.SetFormatted(512, __LOCALIZE_VERFMT("'%s' is defined as global startup action","sws_startup_action"), kbd_getTextFromCmd(cmdId, NULL)); } msg.Append("."); MessageBox(GetMainHwnd(), msg.Get(), SWS_CMD_SHORTNAME(_ct), MB_OK); } } else { msg.SetFormatted(512, __LOCALIZE_VERFMT("%s failed: command ID or identifier string '%s' not found in the 'Main' section of the action list!","sws_startup_action"), SWS_CMD_SHORTNAME(_ct), idstr); MessageBox(GetMainHwnd(), msg.Get(), __LOCALIZE("S&M - Error","sws_mbox"), MB_OK); } } }
static void SelectAllNearestEditCursor(COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { SelectAllNearestEditCursor(0, &ct->user); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); }
static void CycleThroughMidiLanes(COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { CycleThroughMidiLanes(UNDO_STATE_ITEMS, &ct->user); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); }
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 ShowOnlyTopCCLane(COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { ShowOnlyTopCCLane(UNDO_STATE_ITEMS, &ct->user); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); }
void TempoShapeSquare (COMMAND_T* ct) { // Get tempo map BR_Envelope tempoMap (GetTempoEnv()); if (!tempoMap.CountSelected()) return; // Get splitting options double splitRatio; bool split = GetTempoShapeOptions(&splitRatio); // Loop through selected points and perform BPM calculations int skipped = 0; int count = tempoMap.Count()-1; for (int i = 0; i < tempoMap.CountSelected(); ++i) { int id = tempoMap.GetSelected(i); // Skip selected point if already square double t1, b1; int s1; tempoMap.GetPoint(id, &t1, &b1, &s1, NULL); if (s1 == SQUARE) continue; else s1 = SQUARE; // Get next point double b2; bool P2; if (id < count) // since we're creating points at the end of tempo map, check if dealing with the last point P2 = tempoMap.GetPoint(id+1, NULL, &b2, NULL, NULL); else P2 = false; // Get previous point double t0, b0; int s0; bool P0 = tempoMap.GetPoint(id-1, &t0, &b0, &s0, NULL); // Get new bpm of selected point double Nb1; if (P2 && b1 != b2) Nb1 = (b1+b2) / 2; else Nb1 = b1; // Check if new bpm is legal, if not, skip if (Nb1 < MIN_BPM || Nb1 > MAX_BPM) SKIP(skipped, 1); ///// SET NEW SHAPE ///// ///////////////////////// // Create middle point(s) is needed if (P0 && s0 == LINEAR && P2 && Nb1 != b2) { // Get middle point's position and BPM double position, bpm = 120, measure = (b0+b1)*(t1-t0) / 480; FindMiddlePoint(&position, &bpm, measure, t0, t1, b0, Nb1); // Don't split middle point if (!split) { if (bpm<= MAX_BPM && bpm>=MIN_BPM && (position-t0)>=MIN_TEMPO_DIST && (t1-position)>=MIN_TEMPO_DIST) tempoMap.CreatePoint(tempoMap.Count(), position, bpm, LINEAR, 0, false); else SKIP(skipped, 1); } // Split middle point else { double position1, position2, bpm1, bpm2; SplitMiddlePoint (&position1, &position2, &bpm1, &bpm2, splitRatio, measure, t0, position, t1, b0, bpm, Nb1); if (bpm1>=MIN_BPM && bpm1<=MAX_BPM && bpm2>=MIN_BPM && bpm2<=MAX_BPM && (position1-t0)>=MIN_TEMPO_DIST && (position2-position1)>=MIN_TEMPO_DIST && (t1-position2)>=MIN_TEMPO_DIST) { tempoMap.CreatePoint(tempoMap.Count(), position1, bpm1, LINEAR, 0, false); tempoMap.CreatePoint(tempoMap.Count(), position2, bpm2, LINEAR, 0, false); } else SKIP(skipped, 1); } } // Change shape of the selected point tempoMap.SetPoint(id, NULL, &Nb1, &s1, NULL); } // Commit changes if (tempoMap.Commit()) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ALL, -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 GotoAnsSelectRegion(COMMAND_T* _ct) { if (GotoMarkerRegion(NULL, ((int)_ct->user)+1, SNM_REGION_MASK, true)) Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(_ct), UNDO_STATE_ALL, -1); }
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); }
static void ApplyGrooveInMidiEditor(COMMAND_T* ct, int val, int valhw, int relmode, HWND hwnd) { ApplyGrooveInMidiEditor(0, &ct->user); Undo_OnStateChangeEx2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS, -1); }
// Import local files from m3u/pls playlists onto a new track void PlaylistImport(COMMAND_T* ct) { char cPath[256]; vector<SPlaylistEntry> filelist; GetProjectPath(cPath, 256); string listpath = BrowseForFiles(__LOCALIZE("Import playlist","sws_mbox"), cPath, NULL, false, "Playlist files (*.m3u,*.pls)\0*.m3u;*.pls\0All Files (*.*)\0*.*\0"); string ext = ParseFileExtension(listpath); // Decide what kind of playlist we have if(ext == "m3u") { ParseM3U(listpath, filelist); } else if(ext == "pls") { ParsePLS(listpath, filelist); } if(filelist.empty()) { ShowMessageBox(__LOCALIZE("Failed to import playlist. No files found.","sws_mbox"), __LOCALIZE("Import playlist","sws_mbox"), 0); return; } // Validate files vector<string> badfiles; for(int i = 0, c = (int)filelist.size(); i < c; i++) { SPlaylistEntry e = filelist[i]; if(!file_exists(e.path.c_str())) { badfiles.push_back(e.path); } } // If files can't be found, ask user what to do. bool includeMissing = false; if(!badfiles.empty()) { stringstream ss; ss << __LOCALIZE("Cannot find some files. Create items anyway?\n","sws_mbox"); unsigned int limit = min((int)badfiles.size(), 9); // avoid enormous messagebox for(unsigned int i = 0; i < limit; i++) { ss << "\n " << badfiles[i]; } if(badfiles.size() > limit) { ss << "\n +" << badfiles.size() - limit << __LOCALIZE(" more files","sws_mbox"); } switch(ShowMessageBox(ss.str().c_str(), __LOCALIZE("Import playlist","sws_mbox"), 3)) { case 6 : // Yes includeMissing = true; break; case 7 : // No break; default : return; } } Undo_BeginBlock2(NULL); // Add new track int idx = GetNumTracks(); int panMode = 5; // Stereo pan double panLaw = 1.0; // 0dB InsertTrackAtIndex(idx, false); MediaTrack *pTrack = GetTrack(NULL, idx); GetSetMediaTrackInfo(pTrack, "P_NAME", (void*) listpath.c_str()); GetSetMediaTrackInfo(pTrack, "I_PANMODE", (void*) &panMode); GetSetMediaTrackInfo(pTrack, "D_PANLAW", (void*) &panLaw); SetOnlyTrackSelected(pTrack); // Add new items to track double pos = 0.0; for(int i = 0, c = (int)filelist.size(); i < c; i++) { SPlaylistEntry e = filelist[i]; //TODO: Would be better if missing files were offline rather than just empty items. PCM_source *pSrc = PCM_Source_CreateFromFile(e.path.c_str()); if(pSrc || includeMissing) { MediaItem *pItem = AddMediaItemToTrack(pTrack); if(pItem) { MediaItem_Take *pTake = AddTakeToMediaItem(pItem); if(pTake) { GetSetMediaItemTakeInfo(pTake, "P_SOURCE", pSrc); GetSetMediaItemTakeInfo(pTake, "P_NAME", (void*) e.title.c_str()); SetMediaItemPosition(pItem, pos, false); SetMediaItemLength(pItem, e.length, false); pos += e.length; } } } } Undo_EndBlock2(NULL, SWS_CMD_SHORTNAME(ct), UNDO_STATE_ITEMS|UNDO_STATE_TRACKCFG); TrackList_AdjustWindows(false); UpdateTimeline(); Main_OnCommand(40047, 0); // Build missing peaks }