1 /*
2 * tracker/PatternEditor.cpp
3 *
4 * Copyright 2009 Peter Barth
5 *
6 * This file is part of Milkytracker.
7 *
8 * Milkytracker is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Milkytracker is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Milkytracker. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 /*
24 * PatternEditor.cpp
25 * MilkyTracker
26 *
27 * Created by Peter Barth on 16.11.07.
28 *
29 */
30
31 #include "PatternEditor.h"
32 #include "XModule.h"
33 #include "PatternTools.h"
34 #include "SimpleVector.h"
35
backup()36 void PatternEditor::Selection::backup()
37 {
38 startCopy = start;
39 endCopy = end;
40 copyValid = true;
41 }
42
restore()43 void PatternEditor::Selection::restore()
44 {
45 start = startCopy;
46 end = endCopy;
47 copyValid = false;
48 }
49
50 PatternEditor::ClipBoard* PatternEditor::ClipBoard::instances[PatternEditor::ClipBoardTypeLAST] = {NULL, NULL, NULL};
51
getInstance(ClipBoardTypes type)52 PatternEditor::ClipBoard* PatternEditor::ClipBoard::getInstance(ClipBoardTypes type)
53 {
54 if (instances[type] == NULL)
55 instances[type] = new ClipBoard();
56
57 return instances[type];
58 }
59
prepareUndo()60 void PatternEditor::prepareUndo()
61 {
62 PatternEditorTools patternEditorTools(pattern);
63 patternEditorTools.normalize();
64
65 undoUserData.clear();
66 notifyListener(NotificationFeedUndoData);
67
68 delete before;
69 before = new PatternUndoStackEntry(*pattern, cursor.channel, cursor.row, cursor.inner, &undoUserData);
70 }
71
finishUndo(LastChanges lastChange,bool nonRepeat)72 bool PatternEditor::finishUndo(LastChanges lastChange, bool nonRepeat/* = false*/)
73 {
74 bool result = false;
75
76 PatternEditorTools patternEditorTools(pattern);
77 patternEditorTools.normalize();
78
79 undoUserData.clear();
80 notifyListener(NotificationFeedUndoData);
81
82 PatternUndoStackEntry after(*pattern, cursor.channel, cursor.row, cursor.inner, &undoUserData);
83 if (*before != after)
84 {
85 PatternEditorTools::Position afterPos;
86 afterPos.channel = after.getCursorPositionChannel();
87 afterPos.row = after.getCursorPositionRow();
88 afterPos.inner = after.getCursorPositionInner();
89
90 PatternEditorTools::Position beforePos;
91 beforePos.channel = before->getCursorPositionChannel();
92 beforePos.row = before->getCursorPositionRow();
93 beforePos.inner = before->getCursorPositionInner();
94
95 result = true;
96
97 lastOperationDidChangeRows = after.GetPattern().rows != before->GetPattern().rows;
98 lastOperationDidChangeCursor = beforePos != afterPos;
99 notifyListener(NotificationChanges);
100 if (undoStack)
101 {
102 if (nonRepeat && this->lastChange != lastChange)
103 undoStack->Push(*before);
104 else if (!nonRepeat)
105 undoStack->Push(*before);
106 undoStack->Push(after);
107 undoStack->Pop();
108 }
109 }
110 this->lastChange = lastChange;
111
112 return result;
113 }
114
PatternEditor()115 PatternEditor::PatternEditor() :
116 EditorBase(),
117 pattern(NULL),
118 numVisibleChannels(-1),
119 autoResize(false),
120 currentInstrument(1),
121 instrumentEnabled(true),
122 instrumentBackTrace(false),
123 currentOctave(5),
124 before(NULL),
125 undoStack(NULL),
126 lastChange(LastChangeNone)
127 {
128 // Undo history
129 undoHistory = new UndoHistory<TXMPattern, PatternUndoStackEntry>(UNDOHISTORYSIZE_PATTERNEDITOR);
130
131 resetCursor();
132 resetSelection();
133
134 memset(effectMacros, 0, sizeof(effectMacros));
135 }
136
~PatternEditor()137 PatternEditor::~PatternEditor()
138 {
139 delete undoHistory;
140 delete undoStack;
141 delete before;
142 }
143
attachPattern(TXMPattern * pattern,XModule * module)144 void PatternEditor::attachPattern(TXMPattern* pattern, XModule* module)
145 {
146 if (this->pattern == pattern && this->module == module)
147 return;
148
149 // --------- update undo history information --------------------
150 if (undoStack)
151 {
152 // if the undo stack is empty, we don't need to save current undo stack
153 if (!undoStack->IsEmpty() || !undoStack->IsTop())
154 {
155 undoStack = undoHistory->getUndoStack(pattern, this->pattern, undoStack);
156 }
157 // delete it if it's empty
158 else
159 {
160 delete undoStack;
161 undoStack = NULL;
162
163 undoStack = undoHistory->getUndoStack(pattern, NULL, NULL);
164 }
165 }
166
167 attachModule(module);
168 this->pattern = pattern;
169
170 // couldn't get any from history, create new one
171 if (!undoStack)
172 {
173 undoStack = new PPUndoStack<PatternUndoStackEntry>(UNDODEPTH_PATTERNEDITOR);
174 }
175
176 notifyListener(NotificationReload);
177 }
178
reset()179 void PatternEditor::reset()
180 {
181 resetSelection();
182
183 delete undoHistory;
184 undoHistory = new UndoHistory<TXMPattern, PatternUndoStackEntry>(UNDOHISTORYSIZE_PATTERNEDITOR);
185
186 delete undoStack;
187 undoStack = new PPUndoStack<PatternUndoStackEntry>(UNDODEPTH_PATTERNEDITOR);
188 }
189
getNumChannels() const190 pp_int32 PatternEditor::getNumChannels() const
191 {
192 if (numVisibleChannels >= 0)
193 return numVisibleChannels;
194
195 if (pattern == NULL)
196 return 0;
197
198 return pattern->channum;
199 }
200
getNumRows() const201 pp_int32 PatternEditor::getNumRows() const
202 {
203 if (pattern == NULL)
204 return 0;
205
206 return pattern->rows;
207 }
208
hasValidSelection()209 bool PatternEditor::hasValidSelection()
210 {
211 return PatternEditorTools::hasValidSelection(pattern, selection.start, selection.end, getNumChannels());
212 }
213
selectionContains(const PatternEditorTools::Position & pos)214 bool PatternEditor::selectionContains(const PatternEditorTools::Position& pos)
215 {
216 return PatternEditorTools::selectionContains(pattern, selection.start, selection.end, pos);
217 }
218
canMoveSelection(pp_int32 channels,pp_int32 rows)219 bool PatternEditor::canMoveSelection(pp_int32 channels, pp_int32 rows)
220 {
221 PatternEditorTools::Position ss = selection.start;
222 PatternEditorTools::Position se = selection.end;
223 ss.channel += channels;
224 ss.row += rows;
225 se.channel += channels;
226 se.row += rows;
227 return PatternEditorTools::hasValidSelection(pattern, ss, se, getNumChannels());
228 }
229
selectChannel(pp_int32 channel)230 void PatternEditor::selectChannel(pp_int32 channel)
231 {
232 if (pattern == NULL)
233 return;
234
235 selection.start.channel = channel;
236 selection.start.row = 0;
237 selection.start.inner = 0;
238 selection.end.channel = channel;
239 selection.end.row = pattern->rows-1;
240 selection.end.inner = 7;
241 }
242
selectAll()243 void PatternEditor::selectAll()
244 {
245 if (pattern == NULL)
246 return;
247
248 selection.start.channel = 0;
249 selection.start.row = 0;
250 selection.start.inner = 0;
251 selection.end.channel = getNumChannels()-1;
252 selection.end.row = pattern->rows-1;
253 selection.end.inner = 7;
254 }
255
getCurrentActiveInstrument()256 pp_int32 PatternEditor::getCurrentActiveInstrument()
257 {
258 PatternTools patternTools;
259
260 if (pattern == NULL)
261 return -1;
262
263 if (pattern->patternData == NULL)
264 return -1;
265
266 if (!instrumentEnabled)
267 return 0;
268
269 if (instrumentBackTrace)
270 {
271 for (pp_int32 i = cursor.row; i >= 0; i--)
272 {
273 patternTools.setPosition(pattern, cursor.channel, i);
274
275 pp_int32 ins = patternTools.getInstrument();
276
277 if (ins != 0)
278 {
279 return ins;
280 }
281 }
282
283 //return -1;
284 }
285
286 return currentInstrument;
287 }
288
undo()289 bool PatternEditor::undo()
290 {
291 if (undoStack->IsEmpty()) return false;
292 if (undoStack)
293 return revoke(undoStack->Pop());
294 return false;
295 }
296
redo()297 bool PatternEditor::redo()
298 {
299 if (undoStack->IsTop()) return false;
300 if (undoStack)
301 return revoke(undoStack->Advance());
302 return false;
303 }
304
revoke(const PatternUndoStackEntry * stackEntry)305 bool PatternEditor::revoke(const PatternUndoStackEntry* stackEntry)
306 {
307 const TXMPattern& stackPattern = stackEntry->GetPattern();
308
309 enterCriticalSection();
310
311 bool res = false;
312
313 if (stackPattern.rows != pattern->rows ||
314 stackPattern.channum != pattern->channum ||
315 stackPattern.effnum != pattern->effnum)
316 {
317 pattern->rows = stackPattern.rows;
318 pattern->channum = stackPattern.channum;
319 pattern->effnum = stackPattern.effnum;
320
321 mp_sint32 patternSize = pattern->rows*pattern->channum*(2+pattern->effnum*2);
322
323 if (pattern->patternData)
324 {
325 delete[] pattern->patternData;
326 pattern->patternData = new mp_ubyte[patternSize];
327 memset(pattern->patternData, 0, patternSize);
328 }
329 }
330
331 if (stackPattern.rows == pattern->rows &&
332 stackPattern.channum == pattern->channum &&
333 stackPattern.effnum == pattern->effnum)
334 {
335 cursor.channel = stackEntry->getCursorPositionChannel();
336 cursor.row = stackEntry->getCursorPositionRow();
337 cursor.inner = stackEntry->getCursorPositionInner();
338
339 pattern->decompress(stackPattern.patternData, stackPattern.len);
340
341 // keep over userdata
342 undoUserData = stackEntry->getUserData();
343 notifyListener(NotificationFetchUndoData);
344
345 notifyListener(NotificationChanges);
346 res = true;
347 }
348
349 leaveCriticalSection();
350
351 return res;
352 }
353
clearRange(const PatternEditorTools::Position & rangeStart,const PatternEditorTools::Position & rangeEnd)354 void PatternEditor::clearRange(const PatternEditorTools::Position& rangeStart, const PatternEditorTools::Position& rangeEnd)
355 {
356 PatternEditorTools patternEditorTools(pattern);
357 patternEditorTools.clearSelection(rangeStart, rangeEnd);
358 }
359
clearSelection()360 void PatternEditor::clearSelection()
361 {
362 if (pattern == NULL)
363 return;
364
365 if (pattern->patternData == NULL)
366 return;
367
368 prepareUndo();
369
370 clearRange(selection.start, selection.end);
371
372 finishUndo(LastChangeDeleteSelection);
373 }
374
clearPattern()375 void PatternEditor::clearPattern()
376 {
377 if (pattern == NULL)
378 return;
379
380 if (pattern->patternData == NULL)
381 return;
382
383 pp_int32 patSize = pattern->channum * (pattern->effnum*2+2) * pattern->rows;
384
385 memset(pattern->patternData, 0, patSize);
386 }
387
cut(ClipBoard & clipBoard)388 void PatternEditor::cut(ClipBoard& clipBoard)
389 {
390 if (pattern == NULL)
391 return;
392
393 if (pattern->patternData == NULL)
394 return;
395
396 prepareUndo();
397
398 clipBoard.makeCopy(*pattern,
399 getSelection().start,
400 getSelection().end,
401 true);
402
403 finishUndo(LastChangeCut);
404 }
405
copy(ClipBoard & clipBoard)406 void PatternEditor::copy(ClipBoard& clipBoard)
407 {
408 clipBoard.makeCopy(*pattern,
409 getSelection().start,
410 getSelection().end);
411 }
412
paste(ClipBoard & clipBoard,bool transparent,pp_int32 fromChannel)413 void PatternEditor::paste(ClipBoard& clipBoard, bool transparent/* = false*/, pp_int32 fromChannel/* = -1*/)
414 {
415 if (pattern == NULL)
416 return;
417
418 if (pattern->patternData == NULL)
419 return;
420
421 prepareUndo();
422
423 if (autoResize && cursor.row + clipBoard.getNumRows() > pattern->rows)
424 {
425 pp_int32 newLen = cursor.row + clipBoard.getNumRows();
426 if (newLen > 256)
427 newLen = 256;
428 resizePattern(newLen, false);
429 }
430
431 if (fromChannel == -1)
432 clipBoard.paste(*pattern, cursor.channel, cursor.row, transparent);
433 else
434 clipBoard.paste(*pattern, fromChannel, cursor.row, transparent);
435
436 finishUndo(LastChangePaste);
437 }
438
cut(ClipBoardTypes clipBoardType)439 void PatternEditor::cut(ClipBoardTypes clipBoardType)
440 {
441 cut(*ClipBoard::getInstance(clipBoardType));
442 }
443
copy(ClipBoardTypes clipBoardType)444 void PatternEditor::copy(ClipBoardTypes clipBoardType)
445 {
446 copy(*ClipBoard::getInstance(clipBoardType));
447 }
448
paste(ClipBoardTypes clipBoardType,bool transparent,pp_int32 fromChannel)449 void PatternEditor::paste(ClipBoardTypes clipBoardType, bool transparent/* = false*/, pp_int32 fromChannel/* = -1*/)
450 {
451 paste(*ClipBoard::getInstance(clipBoardType), transparent, fromChannel);
452 }
453
resizePattern(pp_int32 newRowNum,bool withUndo)454 bool PatternEditor::resizePattern(pp_int32 newRowNum, bool withUndo /*= true*/)
455 {
456 if (newRowNum < 1 || newRowNum > 256)
457 return false;
458
459 if (pattern == NULL)
460 return false;
461
462 if (pattern->patternData == NULL)
463 return false;
464
465 if (newRowNum == pattern->rows)
466 return true;
467
468 enterCriticalSection();
469
470 mp_sint32 slotSize = pattern->effnum * 2 + 2;
471 // allocate half of the space of the current pattern
472 mp_sint32 patternSize = slotSize * pattern->channum * newRowNum;
473
474 mp_ubyte* newPatternData = new mp_ubyte[patternSize];
475
476 memset(newPatternData, 0, patternSize);
477
478 mp_sint32 numRows = newRowNum < pattern->rows ? newRowNum : pattern->rows;
479
480 for (mp_sint32 i = 0; i < numRows; i++)
481 {
482 mp_sint32 srcOffset = i * slotSize * pattern->channum;
483 mp_sint32 dstOffset = i * slotSize * pattern->channum;
484 for (mp_sint32 j = 0; j < slotSize * pattern->channum; j++)
485 newPatternData[dstOffset++] = pattern->patternData[srcOffset++];
486 }
487
488 if (withUndo)
489 {
490 prepareUndo();
491
492 delete[] pattern->patternData;
493
494 pattern->patternData = newPatternData;
495
496 pattern->rows = newRowNum;
497
498 // see if something has changed, if this is the case
499 // save original & changes
500 // Special treatment for pattern resizing:
501 // If user resizes pattern and the last stack entry has already been
502 // a resize modification we don't store the current changes
503 finishUndo(LastChangeResizePattern, true);
504 }
505 else
506 {
507 delete[] pattern->patternData;
508
509 pattern->patternData = newPatternData;
510
511 pattern->rows = newRowNum;
512
513 lastOperationDidChangeRows = true;
514 lastOperationDidChangeCursor = false;
515 notifyListener(NotificationChanges);
516 }
517
518 leaveCriticalSection();
519
520 return true;
521 }
522
expandPattern()523 bool PatternEditor::expandPattern()
524 {
525 if (pattern == NULL)
526 return false;
527
528 if (pattern->patternData == NULL)
529 return false;
530
531 enterCriticalSection();
532
533 prepareUndo();
534
535 PatternEditorTools patternEditorTools(pattern);
536 bool res = patternEditorTools.expandPattern();
537
538 // see if something has changed, if this is the case
539 // save original & changes
540 finishUndo(LastChangeExpandPattern);
541
542 leaveCriticalSection();
543
544 return res;
545 }
546
shrinkPattern()547 bool PatternEditor::shrinkPattern()
548 {
549 if (pattern == NULL)
550 return false;
551
552 if (pattern->patternData == NULL)
553 return false;
554
555 enterCriticalSection();
556
557 prepareUndo();
558
559 PatternEditorTools patternEditorTools(pattern);
560 bool res = patternEditorTools.shrinkPattern();
561
562 // see if something has changed, if this is the case
563 // save original & changes
564 finishUndo(LastChangeShrinkPattern);
565
566 leaveCriticalSection();
567
568 return res;
569 }
570
loadExtendedPattern(const PPSystemString & fileName)571 bool PatternEditor::loadExtendedPattern(const PPSystemString& fileName)
572 {
573 if (pattern == NULL)
574 return false;
575
576 if (pattern->patternData == NULL)
577 return false;
578
579 enterCriticalSection();
580
581 prepareUndo();
582
583 bool res = pattern->loadExtendedPattern(fileName);
584
585 // see if something has changed, if this is the case
586 // save original & changes
587 finishUndo(LastChangeLoadXPattern);
588
589 leaveCriticalSection();
590
591 return res;
592 }
593
saveExtendedPattern(const PPSystemString & fileName)594 bool PatternEditor::saveExtendedPattern(const PPSystemString& fileName)
595 {
596 if (pattern == NULL)
597 return false;
598
599 if (pattern->patternData == NULL)
600 return false;
601
602 return pattern->saveExtendedPattern(fileName);
603 }
604
loadExtendedTrack(const PPSystemString & fileName)605 bool PatternEditor::loadExtendedTrack(const PPSystemString& fileName)
606 {
607 if (pattern == NULL)
608 return 0;
609
610 if (pattern->patternData == NULL)
611 return 0;
612
613 enterCriticalSection();
614
615 prepareUndo();
616
617 bool res = pattern->loadExtendedTrack(fileName, cursor.channel);
618
619 // see if something has changed, if this is the case
620 // save original & changes
621 finishUndo(LastChangeLoadXTrack);
622
623 leaveCriticalSection();
624
625 return res;
626 }
627
saveExtendedTrack(const PPSystemString & fileName)628 bool PatternEditor::saveExtendedTrack(const PPSystemString& fileName)
629 {
630 if (pattern == NULL)
631 return false;
632
633 if (pattern->patternData == NULL)
634 return false;
635
636 return pattern->saveExtendedTrack(fileName, cursor.channel);
637 }
638
insRemapTrack(pp_int32 oldIns,pp_int32 newIns)639 pp_int32 PatternEditor::insRemapTrack(pp_int32 oldIns, pp_int32 newIns)
640 {
641 if (pattern == NULL)
642 return 0;
643
644 if (pattern->patternData == NULL)
645 return 0;
646
647 prepareUndo();
648
649 PatternEditorTools patternEditorTools(pattern);
650
651 pp_int32 resCnt = patternEditorTools.insRemapTrack(cursor.channel, oldIns, newIns);
652
653 finishUndo(LastChangeInsRemapTrack);
654
655 return resCnt;
656 }
657
insRemapPattern(pp_int32 oldIns,pp_int32 newIns)658 pp_int32 PatternEditor::insRemapPattern(pp_int32 oldIns, pp_int32 newIns)
659 {
660 if (pattern == NULL)
661 return 0;
662
663 if (pattern->patternData == NULL)
664 return 0;
665
666 prepareUndo();
667
668 PatternEditorTools patternEditorTools(pattern);
669
670 pp_int32 resCnt = patternEditorTools.insRemap(oldIns, newIns);
671
672 finishUndo(LastChangeInsRemapPattern);
673
674 return resCnt;
675 }
676
insIncSelection()677 pp_int32 PatternEditor::insIncSelection()
678 {
679 if (pattern == NULL)
680 return 0;
681
682 if (pattern->patternData == NULL)
683 return 0;
684
685 prepareUndo();
686
687 PatternEditorTools patternEditorTools(pattern);
688 pp_int32 resCnt = patternEditorTools.insIncSelection(getSelection().start, getSelection().end);
689
690 finishUndo(LastChangeInsIncSelection);
691
692 return resCnt;
693 }
694
insDecSelection()695 pp_int32 PatternEditor::insDecSelection()
696 {
697 if (pattern == NULL)
698 return 0;
699
700 if (pattern->patternData == NULL)
701 return 0;
702
703 prepareUndo();
704
705 PatternEditorTools patternEditorTools(pattern);
706 pp_int32 resCnt = patternEditorTools.insDecSelection(getSelection().start, getSelection().end);
707
708 finishUndo(LastChangeInsDecSelection);
709
710 return resCnt;
711 }
712
insIncTrack()713 pp_int32 PatternEditor::insIncTrack()
714 {
715 if (pattern == NULL)
716 return 0;
717
718 if (pattern->patternData == NULL)
719 return 0;
720
721 prepareUndo();
722
723 PatternEditorTools patternEditorTools(pattern);
724 pp_int32 resCnt = patternEditorTools.insIncTrack(getCursor().channel);
725
726 finishUndo(LastChangeInsIncTrack);
727
728 return resCnt;
729 }
730
insDecTrack()731 pp_int32 PatternEditor::insDecTrack()
732 {
733 if (pattern == NULL)
734 return 0;
735
736 if (pattern->patternData == NULL)
737 return 0;
738
739 prepareUndo();
740
741 PatternEditorTools patternEditorTools(pattern);
742 pp_int32 resCnt = patternEditorTools.insDecTrack(getCursor().channel);
743
744 finishUndo(LastChangeInsDecTrack);
745
746 return resCnt;
747 }
748
insRemapSelection(pp_int32 oldIns,pp_int32 newIns)749 pp_int32 PatternEditor::insRemapSelection(pp_int32 oldIns, pp_int32 newIns)
750 {
751 if (pattern == NULL)
752 return 0;
753
754 if (pattern->patternData == NULL)
755 return 0;
756
757 prepareUndo();
758
759 PatternEditorTools patternEditorTools(pattern);
760 pp_int32 resCnt = patternEditorTools.insRemapSelection(getSelection().start, getSelection().end, oldIns, newIns);
761
762 finishUndo(LastChangeInsRemapSelection);
763
764 return resCnt;
765 }
766
noteTransposeTrackCore(const PatternEditorTools::TransposeParameters & transposeParameters,bool evaluate)767 pp_int32 PatternEditor::noteTransposeTrackCore(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate)
768 {
769 if (pattern == NULL)
770 return 0;
771
772 if (pattern->patternData == NULL)
773 return 0;
774
775 prepareUndo();
776
777 pp_int32 resCnt = 0;
778 pp_int32 fuckupCnt = 0;
779
780 PatternEditorTools patternEditorTools(pattern);
781
782 if (!evaluate)
783 resCnt = patternEditorTools.noteTransposeTrack(cursor.channel, transposeParameters, evaluate);
784 else
785 fuckupCnt = patternEditorTools.noteTransposeTrack(cursor.channel, transposeParameters, evaluate);
786
787 finishUndo(LastChangeNoteTransposeTrack);
788
789 if (!evaluate)
790 return resCnt;
791 else
792 return fuckupCnt;
793 }
794
noteTransposePatternCore(const PatternEditorTools::TransposeParameters & transposeParameters,bool evaluate)795 pp_int32 PatternEditor::noteTransposePatternCore(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate)
796 {
797 if (pattern == NULL)
798 return 0;
799
800 if (pattern->patternData == NULL)
801 return 0;
802
803 prepareUndo();
804
805 PatternEditorTools patternEditorTools(pattern);
806
807 pp_int32 resCnt = 0;
808 pp_int32 fuckupCnt = 0;
809
810 if (!evaluate)
811 resCnt = patternEditorTools.noteTranspose(transposeParameters, evaluate);
812 else
813 fuckupCnt = patternEditorTools.noteTranspose(transposeParameters, evaluate);
814
815 finishUndo(LastChangeNoteTransposePattern);
816
817 if (!evaluate)
818 return resCnt;
819 else
820 return fuckupCnt;
821 }
822
noteTransposeSelectionCore(const PatternEditorTools::TransposeParameters & transposeParameters,bool evaluate)823 pp_int32 PatternEditor::noteTransposeSelectionCore(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate)
824 {
825 if (pattern == NULL)
826 return 0;
827
828 if (pattern->patternData == NULL)
829 return 0;
830
831 pp_int32 resCnt = 0;
832 pp_int32 fuckupCnt = 0;
833
834 prepareUndo();
835
836 PatternEditorTools patternEditorTools(pattern);
837
838 if (!evaluate)
839 resCnt = patternEditorTools.noteTransposeSelection(getSelection().start, getSelection().end, transposeParameters, evaluate);
840 else
841 fuckupCnt = patternEditorTools.noteTransposeSelection(getSelection().start, getSelection().end, transposeParameters, evaluate);
842
843 finishUndo(LastChangeNoteTransposeSelection);
844
845 if (!evaluate)
846 return resCnt;
847 else
848 return fuckupCnt;
849 }
850
interpolateValuesInSelection()851 pp_int32 PatternEditor::interpolateValuesInSelection()
852 {
853 if (pattern == NULL)
854 return 0;
855
856 if (pattern->patternData == NULL)
857 return 0;
858
859 pp_int32 stats = 0;
860
861 prepareUndo();
862
863 PatternEditorTools patternEditorTools(pattern);
864 stats = patternEditorTools.interpolateValuesInSelection(getSelection().start, getSelection().end);
865
866 finishUndo(LastChangeNoteInterpolate);
867
868 return stats;
869 }
870
splitTrack(pp_int32 useChannels,bool selectionOnly,bool insertNoteOff)871 pp_int32 PatternEditor::splitTrack(pp_int32 useChannels, bool selectionOnly, bool insertNoteOff)
872 {
873 if (pattern == NULL)
874 return 0;
875
876 if (pattern->patternData == NULL)
877 return 0;
878
879 pp_int32 stats = 0;
880
881 pp_int32 chn = cursor.channel;
882
883 pp_int32 fromRow = 0;
884 pp_int32 toRow = pattern->rows;
885
886 if (selectionOnly && hasValidSelection())
887 {
888 if (getSelection().start.channel != getSelection().end.channel)
889 return -1;
890
891 chn = getSelection().start.channel;
892 fromRow = getSelection().start.row;
893 toRow = getSelection().end.row+1;
894 }
895 else if (selectionOnly && !hasValidSelection())
896 return 0;
897
898 prepareUndo();
899
900 PatternEditorTools patternEditorTools(pattern);
901
902 stats = patternEditorTools.splitTrack(useChannels, insertNoteOff, chn, fromRow, toRow, getNumChannels());
903
904 finishUndo(LastChangeSplitTrack);
905
906 return stats;
907 }
908
swapChannels(pp_int32 dstChannel,pp_int32 srcChannel)909 pp_int32 PatternEditor::swapChannels(pp_int32 dstChannel, pp_int32 srcChannel)
910 {
911 if (pattern == NULL)
912 return 0;
913
914 if (pattern->patternData == NULL)
915 return 0;
916
917 if (dstChannel == srcChannel)
918 return 0;
919
920 prepareUndo();
921
922 PatternEditorTools patternEditorTools(pattern);
923
924 pp_int32 stats = patternEditorTools.swapChannels(dstChannel, srcChannel);
925
926 finishUndo(LastChangeSwapChannels);
927
928 return stats;
929 }
930
scaleVolume(const PatternEditorTools::Position & startSelection,const PatternEditorTools::Position & endSelection,float startScale,float endScale)931 pp_int32 PatternEditor::scaleVolume(const PatternEditorTools::Position& startSelection, const PatternEditorTools::Position& endSelection, float startScale, float endScale)
932 {
933 prepareUndo();
934
935 PatternEditorTools patternEditorTools(pattern);
936
937 pp_int32 stats = patternEditorTools.scaleVolume(startSelection,
938 endSelection,
939 startScale,
940 endScale,
941 getNumChannels(), module);
942
943 finishUndo(LastChangeScaleVolume);
944
945 return stats;
946 }
947
scaleVolumeTrack(float startScale,float endScale)948 pp_int32 PatternEditor::scaleVolumeTrack(float startScale, float endScale)
949 {
950 if (pattern == NULL)
951 return 0;
952
953 PatternEditorTools::Position startSel, endSel;
954
955 startSel.row = startSel.inner = 0;
956 startSel.channel = cursor.channel;
957 endSel = startSel;
958 endSel.row = pattern->rows-1;
959
960 return scaleVolume(startSel, endSel, startScale, endScale);
961 }
962
scaleVolumePattern(float startScale,float endScale)963 pp_int32 PatternEditor::scaleVolumePattern(float startScale, float endScale)
964 {
965 if (pattern == NULL)
966 return 0;
967
968 PatternEditorTools::Position startSel, endSel;
969
970 startSel.channel = startSel.row = startSel.inner = 0;
971 endSel.channel = pattern->channum-1; endSel.row = pattern->rows-1; endSel.inner = 7;
972
973 return scaleVolume(startSel, endSel, startScale, endScale);
974 }
975
scaleVolumeSelection(float startScale,float endScale)976 pp_int32 PatternEditor::scaleVolumeSelection(float startScale, float endScale)
977 {
978 if (pattern == NULL || !hasValidSelection())
979 return 0;
980
981 return scaleVolume(getSelection().start, getSelection().end, startScale, endScale);
982 }
983
zeroOperandsTrack(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)984 pp_int32 PatternEditor::zeroOperandsTrack(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
985 {
986 if (pattern == NULL)
987 return 0;
988
989 if (pattern->patternData == NULL)
990 return 0;
991
992 prepareUndo();
993
994 pp_int32 resCnt = 0;
995
996 PatternEditorTools patternEditorTools(pattern);
997
998 resCnt = patternEditorTools.zeroOperandsTrack(cursor.channel, optimizeParameters, evaluate);
999
1000 finishUndo(LastChangeZeroOperandsTrack);
1001
1002 return resCnt;
1003 }
1004
zeroOperandsPattern(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)1005 pp_int32 PatternEditor::zeroOperandsPattern(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
1006 {
1007 if (pattern == NULL)
1008 return 0;
1009
1010 if (pattern->patternData == NULL)
1011 return 0;
1012
1013 prepareUndo();
1014
1015 pp_int32 resCnt = 0;
1016
1017 PatternEditorTools patternEditorTools(pattern);
1018
1019 resCnt = patternEditorTools.zeroOperands(optimizeParameters, evaluate);
1020
1021 finishUndo(LastChangeZeroOperandsPattern);
1022
1023 return resCnt;
1024 }
1025
zeroOperandsSelection(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)1026 pp_int32 PatternEditor::zeroOperandsSelection(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
1027 {
1028 if (pattern == NULL)
1029 return 0;
1030
1031 if (pattern->patternData == NULL)
1032 return 0;
1033
1034 prepareUndo();
1035
1036 pp_int32 resCnt = 0;
1037
1038 PatternEditorTools patternEditorTools(pattern);
1039
1040 resCnt = patternEditorTools.zeroOperandsSelection(getSelection().start, getSelection().end, optimizeParameters, evaluate);
1041
1042 finishUndo(LastChangeZeroOperandsSelection);
1043
1044 return resCnt;
1045 }
1046
fillOperandsTrack(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)1047 pp_int32 PatternEditor::fillOperandsTrack(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
1048 {
1049 if (pattern == NULL)
1050 return 0;
1051
1052 if (pattern->patternData == NULL)
1053 return 0;
1054
1055 prepareUndo();
1056
1057 pp_int32 resCnt = 0;
1058
1059 PatternEditorTools patternEditorTools(pattern);
1060
1061 resCnt = patternEditorTools.fillOperandsTrack(cursor.channel, optimizeParameters, evaluate);
1062
1063 finishUndo(LastChangeFillOperandsTrack);
1064
1065 return resCnt;
1066 }
1067
fillOperandsPattern(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)1068 pp_int32 PatternEditor::fillOperandsPattern(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
1069 {
1070 if (pattern == NULL)
1071 return 0;
1072
1073 if (pattern->patternData == NULL)
1074 return 0;
1075
1076 prepareUndo();
1077
1078 pp_int32 resCnt = 0;
1079
1080 PatternEditorTools patternEditorTools(pattern);
1081
1082 resCnt = patternEditorTools.fillOperands(optimizeParameters, evaluate);
1083
1084 finishUndo(LastChangeFillOperandsPattern);
1085
1086 return resCnt;
1087 }
1088
fillOperandsSelection(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)1089 pp_int32 PatternEditor::fillOperandsSelection(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
1090 {
1091 if (pattern == NULL)
1092 return 0;
1093
1094 if (pattern->patternData == NULL)
1095 return 0;
1096
1097 prepareUndo();
1098
1099 pp_int32 resCnt = 0;
1100
1101 PatternEditorTools patternEditorTools(pattern);
1102
1103 resCnt = patternEditorTools.fillOperandsSelection(getSelection().start, getSelection().end, optimizeParameters, evaluate);
1104
1105 finishUndo(LastChangeFillOperandsSelection);
1106
1107 return resCnt;
1108 }
1109
relocateCommandsTrack(const PatternEditorTools::RelocateParameters & relocateParameters,bool evaluate)1110 pp_int32 PatternEditor::relocateCommandsTrack(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate)
1111 {
1112 if (pattern == NULL)
1113 return 0;
1114
1115 if (pattern->patternData == NULL)
1116 return 0;
1117
1118 prepareUndo();
1119
1120 pp_int32 resCnt = 0;
1121
1122 PatternEditorTools patternEditorTools(pattern);
1123
1124 resCnt = patternEditorTools.relocateCommandsTrack(cursor.channel, relocateParameters, evaluate);
1125
1126 finishUndo(LastChangeRelocateCommandsTrack);
1127
1128 return resCnt;
1129 }
1130
relocateCommandsPattern(const PatternEditorTools::RelocateParameters & relocateParameters,bool evaluate)1131 pp_int32 PatternEditor::relocateCommandsPattern(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate)
1132 {
1133 if (pattern == NULL)
1134 return 0;
1135
1136 if (pattern->patternData == NULL)
1137 return 0;
1138
1139 prepareUndo();
1140
1141 pp_int32 resCnt = 0;
1142
1143 PatternEditorTools patternEditorTools(pattern);
1144
1145 resCnt = patternEditorTools.relocateCommands(relocateParameters, evaluate);
1146
1147 finishUndo(LastChangeRelocateCommandsPattern);
1148
1149 return resCnt;
1150 }
1151
relocateCommandsSelection(const PatternEditorTools::RelocateParameters & relocateParameters,bool evaluate)1152 pp_int32 PatternEditor::relocateCommandsSelection(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate)
1153 {
1154 if (pattern == NULL)
1155 return 0;
1156
1157 if (pattern->patternData == NULL)
1158 return 0;
1159
1160 prepareUndo();
1161
1162 pp_int32 resCnt = 0;
1163
1164 PatternEditorTools patternEditorTools(pattern);
1165
1166 resCnt = patternEditorTools.relocateCommandsSelection(getSelection().start, getSelection().end, relocateParameters, evaluate);
1167
1168 finishUndo(LastChangeRelocateCommandsSelection);
1169
1170 return resCnt;
1171 }
1172
writeNote(pp_int32 note,bool withUndo,PatternAdvanceInterface * advanceImpl)1173 bool PatternEditor::writeNote(pp_int32 note,
1174 bool withUndo/* = false*/,
1175 PatternAdvanceInterface* advanceImpl/* = NULL*/)
1176 {
1177 if (withUndo)
1178 prepareUndo();
1179
1180 PatternTools patternTools;
1181 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1182
1183 // means to delete note
1184 if (note == 0xFF)
1185 {
1186 patternTools.setNote(0);
1187
1188 if (advanceImpl)
1189 advanceImpl->advance();
1190
1191 if (withUndo)
1192 finishUndo(LastChangeSlotChange);
1193 return true;
1194 }
1195
1196 if (note >= 1 && note <= PatternTools::getNoteOffNote())
1197 {
1198 pp_int32 currentInstrument = getCurrentActiveInstrument();
1199
1200 patternTools.setNote(note);
1201 if (currentInstrument && note != PatternTools::getNoteOffNote())
1202 patternTools.setInstrument(currentInstrument);
1203
1204 if (advanceImpl)
1205 advanceImpl->advance();
1206
1207 if (withUndo)
1208 finishUndo(LastChangeSlotChange);
1209 return true;
1210 }
1211
1212 return false;
1213 }
1214
writeDirectNote(pp_int32 note,pp_int32 track,pp_int32 row,pp_int32 order)1215 void PatternEditor::writeDirectNote(pp_int32 note,
1216 pp_int32 track/* = -1*/,
1217 pp_int32 row/* = -1*/,
1218 pp_int32 order/* = -1*/)
1219 {
1220 TXMPattern* pattern = this->pattern;
1221 if (order != -1)
1222 pattern = &module->phead[module->header.ord[order]];
1223
1224 if (track == -1)
1225 track = cursor.channel;
1226
1227 if (row == -1)
1228 row = cursor.row;
1229
1230 PatternTools patternTools;
1231 patternTools.setPosition(pattern, track, row);
1232
1233 // means to delete note
1234 if (note == 0xFF)
1235 {
1236 patternTools.setNote(0);
1237 }
1238
1239 if (note >= 1 && note <= PatternTools::getNoteOffNote())
1240 {
1241 pp_int32 currentInstrument = getCurrentActiveInstrument();
1242
1243 patternTools.setNote(note);
1244 if (currentInstrument && note != PatternTools::getNoteOffNote())
1245 patternTools.setInstrument(currentInstrument);
1246 }
1247 }
1248
writeEffect(pp_int32 effNum,pp_uint8 eff,pp_uint8 op,bool withUndo,PatternAdvanceInterface * advanceImpl)1249 bool PatternEditor::writeEffect(pp_int32 effNum, pp_uint8 eff, pp_uint8 op,
1250 bool withUndo/* = false*/,
1251 PatternAdvanceInterface* advanceImpl/* = NULL*/)
1252 {
1253 if (withUndo)
1254 prepareUndo();
1255
1256 PatternTools patternTools;
1257 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1258
1259 // only write effect, when valid effect
1260 // (0 is not a valid effect in my internal format, arpeggio is mapped to 0x20)
1261 if (eff)
1262 patternTools.setEffect(effNum, eff, op);
1263 else
1264 return false;
1265
1266 if (advanceImpl)
1267 advanceImpl->advance();
1268
1269 if (withUndo)
1270 finishUndo(LastChangeSlotChange);
1271 return true;
1272 }
1273
writeDirectEffect(pp_int32 effNum,pp_uint8 eff,pp_uint8 op,pp_int32 track,pp_int32 row,pp_int32 order)1274 void PatternEditor::writeDirectEffect(pp_int32 effNum, pp_uint8 eff, pp_uint8 op,
1275 pp_int32 track/* = -1*/,
1276 pp_int32 row/* = -1*/,
1277 pp_int32 order/* = -1*/)
1278 {
1279 TXMPattern* pattern = this->pattern;
1280 if (order != -1)
1281 pattern = &module->phead[module->header.ord[order]];
1282
1283 if (track == -1)
1284 track = cursor.channel;
1285
1286 if (row == -1)
1287 row = cursor.row;
1288
1289 PatternTools patternTools;
1290 patternTools.setPosition(pattern, track, row);
1291
1292 // only write effect, when valid effect
1293 // (0 is not a valid effect in my internal format, arpeggio is mapped to 0x20)
1294 if (eff)
1295 patternTools.setEffect(effNum, eff, op);
1296 }
1297
1298
writeInstrument(NibbleTypes nibleType,pp_uint8 value,bool withUndo,PatternAdvanceInterface * advanceImpl)1299 bool PatternEditor::writeInstrument(NibbleTypes nibleType, pp_uint8 value, bool withUndo/* = false*/, PatternAdvanceInterface* advanceImpl/* = NULL*/)
1300 {
1301 if (withUndo)
1302 prepareUndo();
1303
1304 PatternTools patternTools;
1305 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1306
1307 if (nibleType == NibbleTypeBoth)
1308 {
1309 patternTools.setInstrument(value);
1310
1311 if (advanceImpl)
1312 advanceImpl->advance();
1313
1314 if (withUndo)
1315 finishUndo(LastChangeSlotChange);
1316 return true;
1317 }
1318
1319 pp_uint32 i = patternTools.getInstrument();
1320
1321 if (nibleType == NibbleTypeHigh)
1322 {
1323 i &= 0x0F;
1324 i |= (pp_uint32)value << 4;
1325 patternTools.setInstrument(i);
1326
1327 if (advanceImpl)
1328 advanceImpl->advance();
1329
1330 if (withUndo)
1331 finishUndo(LastChangeSlotChange);
1332 return true;
1333 }
1334 else if (nibleType == NibbleTypeLow)
1335 {
1336 i &= 0xF0;
1337 i |= (pp_uint32)value;
1338 patternTools.setInstrument(i);
1339
1340 if (advanceImpl)
1341 advanceImpl->advance();
1342
1343 if (withUndo)
1344 finishUndo(LastChangeSlotChange);
1345 return true;
1346 }
1347
1348 return false;
1349 }
1350
writeFT2Volume(NibbleTypes nibleType,pp_uint8 value,bool withUndo,PatternAdvanceInterface * advanceImpl)1351 bool PatternEditor::writeFT2Volume(NibbleTypes nibleType, pp_uint8 value, bool withUndo/* = false*/, PatternAdvanceInterface* advanceImpl/* = NULL*/)
1352 {
1353 if (withUndo)
1354 prepareUndo();
1355
1356 PatternTools patternTools;
1357 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1358
1359 if (value == 0xFF)
1360 {
1361 patternTools.setFirstEffect(0, 0);
1362
1363 if (advanceImpl)
1364 advanceImpl->advance();
1365
1366 if (withUndo)
1367 finishUndo(LastChangeSlotChange);
1368 return true;
1369 }
1370
1371 pp_int32 eff,op;
1372
1373 patternTools.getFirstEffect(eff, op);
1374 patternTools.convertEffectsToFT2(eff, op);
1375
1376 pp_int32 volume = patternTools.getVolumeFromEffect(eff, op) - 0x10;
1377
1378 if (volume < 0)
1379 volume = 0;
1380
1381 if (volume >= 0xF0)
1382 return false;
1383
1384 if (volume >= 0)
1385 {
1386 if (nibleType == NibbleTypeHigh)
1387 {
1388 volume &= 0x0F;
1389 volume |= (pp_int32)value << 4;
1390
1391 if (volume>=0xF0)
1392 return false;
1393 else if ((volume > 0x40 && volume < 0x50))
1394 volume = 0x40;
1395
1396 if (volume >= 0x50 && ((volume & 0xF) == 0))
1397 {
1398 switch ((volume+0x10) >> 4)
1399 {
1400 // For the following effects we don't allow zero operand
1401 case 0x6: // Volslide down
1402 case 0x7: // Volslide up
1403 case 0x8: // Fine volslide down
1404 case 0x9: // Fine volslide up
1405 case 0xa: // Set vibrato speed
1406 case 0xd: // Panslide left
1407 case 0xe: // Panslide right
1408 volume |= 1;
1409 break;
1410 }
1411 }
1412 }
1413 else if (nibleType == NibbleTypeLow)
1414 {
1415 volume &= 0xF0;
1416 volume |= (pp_int32)value;
1417
1418 if (volume>=0xF0)
1419 return false;
1420 else if ((volume > 0x40 && volume < 0x50))
1421 volume = 0x40;
1422
1423 if (volume >= 0x50 && ((volume & 0xF) == 0))
1424 {
1425 switch ((volume+0x10) >> 4)
1426 {
1427 // For the following effects we don't allow zero operand
1428 case 0x6: // Volslide down
1429 case 0x7: // Volslide up
1430 case 0x8: // Fine volslide down
1431 case 0x9: // Fine volslide up
1432 case 0xa: // Set vibrato speed
1433 case 0xd: // Panslide left
1434 case 0xe: // Panslide right
1435 volume |= 1;
1436 break;
1437 }
1438 }
1439 }
1440
1441 patternTools.convertVolumeToEffect(volume + 0x10, eff, op);
1442 patternTools.setFirstEffect(eff, op);
1443
1444 if (advanceImpl)
1445 advanceImpl->advance();
1446
1447 if (withUndo)
1448 finishUndo(LastChangeSlotChange);
1449 return true;
1450 }
1451
1452 return false;
1453 }
1454
writeEffectNumber(pp_uint8 value,bool withUndo,PatternAdvanceInterface * advanceImpl)1455 bool PatternEditor::writeEffectNumber(pp_uint8 value, bool withUndo/* = false*/, PatternAdvanceInterface* advanceImpl/* = NULL*/)
1456 {
1457 if (withUndo)
1458 prepareUndo();
1459
1460 PatternTools patternTools;
1461 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1462
1463 // clear out entire effect + operand
1464 if (value == 0xFF)
1465 {
1466 patternTools.setEffect(1, 0, 0);
1467
1468 if (advanceImpl)
1469 advanceImpl->advance();
1470
1471 if (withUndo)
1472 finishUndo(LastChangeSlotChange);
1473 return true;
1474 }
1475
1476 pp_int32 eff,op;
1477
1478 // skip first effect (= volume command)
1479 patternTools.getFirstEffect(eff, op);
1480 patternTools.getNextEffect(eff, op);
1481
1482 patternTools.convertEffectsToFT2(eff, op);
1483
1484 pp_int32 newEff = value;
1485 patternTools.convertEffectsFromFT2(newEff, op);
1486
1487 if (newEff == 0x40)
1488 {
1489 newEff = 0x41;
1490 op &= 0x0F;
1491 }
1492 else if (newEff >= 0x43)
1493 {
1494 newEff = 0x42;
1495 op &= 0x0F;
1496 }
1497
1498 patternTools.setEffect(1, newEff, op);
1499
1500 if (advanceImpl)
1501 advanceImpl->advance();
1502
1503 if (withUndo)
1504 finishUndo(LastChangeSlotChange);
1505 return true;
1506 }
1507
writeEffectOperand(NibbleTypes nibleType,pp_uint8 value,bool withUndo,PatternAdvanceInterface * advanceImpl)1508 bool PatternEditor::writeEffectOperand(NibbleTypes nibleType, pp_uint8 value, bool withUndo/* = false*/, PatternAdvanceInterface* advanceImpl/* = NULL*/)
1509 {
1510 if (withUndo)
1511 prepareUndo();
1512
1513 PatternTools patternTools;
1514 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1515
1516 // clear out entire effect + operand
1517 if (value == 0xFF)
1518 {
1519 patternTools.setEffect(1, 0, 0);
1520
1521 if (advanceImpl)
1522 advanceImpl->advance();
1523
1524 if (withUndo)
1525 finishUndo(LastChangeSlotChange);
1526 return true;
1527 }
1528
1529 pp_int32 eff,op;
1530
1531 patternTools.getFirstEffect(eff, op);
1532 patternTools.getNextEffect(eff, op);
1533
1534 patternTools.convertEffectsToFT2(eff, op);
1535
1536 if (nibleType == NibbleTypeHigh)
1537 {
1538 op &= 0x0F;
1539 op |= (pp_int32)value << 4;
1540 }
1541 else if (nibleType == NibbleTypeLow)
1542 {
1543 op &= 0xF0;
1544 op |= (pp_int32)value;
1545 }
1546
1547 patternTools.convertEffectsFromFT2(eff, op);
1548
1549 if (eff == 0x40)
1550 eff = 0x41;
1551 if (eff >= 0x43)
1552 eff = 0x42;
1553
1554 patternTools.setEffect(1, eff, op);
1555
1556 if (advanceImpl)
1557 advanceImpl->advance();
1558
1559 if (withUndo)
1560 finishUndo(LastChangeSlotChange);
1561 return true;
1562 }
1563
storeMacroFromCursor(pp_int32 slot)1564 void PatternEditor::storeMacroFromCursor(pp_int32 slot)
1565 {
1566 if (pattern == NULL)
1567 return;
1568
1569 if (slot > 10 || slot < 0)
1570 return;
1571
1572 PatternTools patternTools;
1573 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1574
1575 pp_int32 eff, op;
1576
1577 if (cursor.inner >= 3 && cursor.inner <= 4)
1578 {
1579 patternTools.getEffect(0, eff, op);
1580 // feature shall also work with empty effects
1581 //if (!eff && !op)
1582 // return;
1583 effectMacros[slot].effect = (pp_uint8)eff;
1584 effectMacros[slot].operand = (pp_uint8)op;
1585 }
1586 else if (cursor.inner > 4)
1587 {
1588 patternTools.getEffect(1, eff, op);
1589 // feature shall also work with empty effects
1590 //if (!eff && !op)
1591 // return;
1592 effectMacros[slot+10].effect = (pp_uint8)eff;
1593 effectMacros[slot+10].operand = (pp_uint8)op;
1594 }
1595 }
1596
writeMacroToCursor(pp_int32 slot,PatternAdvanceInterface * advanceImpl)1597 void PatternEditor::writeMacroToCursor(pp_int32 slot, PatternAdvanceInterface* advanceImpl/* = NULL*/)
1598 {
1599 if (pattern == NULL)
1600 return;
1601
1602 if (slot > 10 || slot < 0)
1603 return;
1604
1605 prepareUndo();
1606
1607 PatternTools patternTools;
1608 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1609
1610 if (cursor.inner >= 3 && cursor.inner <= 4)
1611 {
1612 // feature shall also work with empty effects
1613 //if (!effectMacros[slot].effect && !effectMacros[slot].operand)
1614 // goto writeNothing;
1615 patternTools.setEffect(0, effectMacros[slot].effect, effectMacros[slot].operand);
1616 }
1617 else if (cursor.inner > 4)
1618 {
1619 // feature shall also work with empty effects
1620 //if (!effectMacros[slot+10].effect && !effectMacros[slot+10].operand)
1621 // goto writeNothing;
1622 patternTools.setEffect(1, effectMacros[slot+10].effect, effectMacros[slot+10].operand);
1623 }
1624
1625 if (advanceImpl)
1626 advanceImpl->advance();
1627
1628 //writeNothing:
1629
1630 finishUndo(LastChangeWriteMacro);
1631 }
1632
getMacroOperands(pp_int32 slot,pp_uint8 & eff,pp_uint8 & op)1633 void PatternEditor::getMacroOperands(pp_int32 slot, pp_uint8& eff, pp_uint8& op)
1634 {
1635 if (slot < 0 || slot >= 20)
1636 return;
1637
1638 eff = effectMacros[slot].effect;
1639 op = effectMacros[slot].operand;
1640 }
1641
setMacroOperands(pp_int32 slot,pp_uint8 eff,pp_uint8 op)1642 void PatternEditor::setMacroOperands(pp_int32 slot, pp_uint8 eff, pp_uint8 op)
1643 {
1644 if (slot < 0 || slot >= 20)
1645 return;
1646
1647 effectMacros[slot].effect = eff;
1648 effectMacros[slot].operand = op;
1649 }
1650
deleteCursorSlotData(PatternAdvanceInterface * advanceImpl)1651 void PatternEditor::deleteCursorSlotData(PatternAdvanceInterface* advanceImpl/* = NULL*/)
1652 {
1653 prepareUndo();
1654 PatternTools patternTools;
1655 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1656 if (cursor.inner == 3 || cursor.inner == 4)
1657 {
1658 patternTools.setFirstEffect(0,0);
1659 }
1660 else if (cursor.inner == 5 || cursor.inner == 6 || cursor.inner == 7)
1661 {
1662 // What have I been thinking?
1663 //pp_int32 eff, op;
1664 //patternTools.getEffect(1, eff, op);
1665 // actually I think delete should really delete
1666 patternTools.setEffect(1, 0, 0);
1667 }
1668 else
1669 {
1670 patternTools.setNote(0);
1671 patternTools.setInstrument(0);
1672 }
1673
1674 if (advanceImpl)
1675 advanceImpl->advance();
1676
1677 finishUndo(LastChangeDeleteNote);
1678 }
1679
deleteCursorSlotDataEntire(PatternAdvanceInterface * advanceImpl)1680 void PatternEditor::deleteCursorSlotDataEntire(PatternAdvanceInterface* advanceImpl/* = NULL*/)
1681 {
1682 prepareUndo();
1683 PatternTools patternTools;
1684 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1685 patternTools.setNote(0);
1686 patternTools.setInstrument(0);
1687 patternTools.setFirstEffect(0,0);
1688 patternTools.setNextEffect(0,0);
1689
1690 if (advanceImpl)
1691 advanceImpl->advance();
1692
1693 finishUndo(LastChangeDeleteNoteVolumeAndEffect);
1694 }
1695
deleteCursorSlotDataVolumeAndEffect(PatternAdvanceInterface * advanceImpl)1696 void PatternEditor::deleteCursorSlotDataVolumeAndEffect(PatternAdvanceInterface* advanceImpl/* = NULL*/)
1697 {
1698 prepareUndo();
1699 PatternTools patternTools;
1700 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1701 patternTools.setFirstEffect(0,0);
1702 patternTools.setNextEffect(0,0);
1703
1704 if (advanceImpl)
1705 advanceImpl->advance();
1706
1707 finishUndo(LastChangeDeleteVolumeAndEffect);
1708 }
1709
deleteCursorSlotDataEffect(PatternAdvanceInterface * advanceImpl)1710 void PatternEditor::deleteCursorSlotDataEffect(PatternAdvanceInterface* advanceImpl/* = NULL*/)
1711 {
1712 prepareUndo();
1713 PatternTools patternTools;
1714 patternTools.setPosition(pattern, cursor.channel, cursor.row);
1715 pp_int32 eff, op;
1716 patternTools.getFirstEffect(eff, op);
1717 patternTools.setFirstEffect(eff,op);
1718 patternTools.setNextEffect(0,0);
1719
1720 if (advanceImpl)
1721 advanceImpl->advance();
1722
1723 finishUndo(LastChangeDeleteEffect);
1724 }
1725
insertNote(pp_int32 channel,pp_int32 row)1726 void PatternEditor::insertNote(pp_int32 channel, pp_int32 row)
1727 {
1728 if (pattern == NULL || pattern->patternData == NULL)
1729 return;
1730
1731 if (channel < 0 || channel >= pattern->channum)
1732 return;
1733
1734 prepareUndo();
1735
1736 mp_sint32 slotSize = pattern->effnum * 2 + 2;
1737 mp_sint32 rowSize = slotSize*pattern->channum;
1738
1739 for (mp_sint32 i = pattern->rows - 1; i > row; i--)
1740 {
1741 mp_ubyte* src = (i-1)*rowSize + channel*slotSize + pattern->patternData;
1742 mp_ubyte* dst = i*rowSize + channel*slotSize + pattern->patternData;
1743
1744 memcpy(dst, src, slotSize);
1745 }
1746
1747 memset(row*rowSize + channel*slotSize + pattern->patternData, 0, slotSize);
1748
1749 finishUndo(LastChangeInsertNote);
1750 }
1751
insertLine(pp_int32 row)1752 void PatternEditor::insertLine(pp_int32 row)
1753 {
1754 if (pattern == NULL || pattern->patternData == NULL)
1755 return;
1756
1757 if (row < 0 || row >= pattern->rows)
1758 return;
1759
1760 prepareUndo();
1761
1762 mp_sint32 slotSize = pattern->effnum * 2 + 2;
1763
1764 mp_sint32 rowSize = slotSize*pattern->channum;
1765
1766 for (mp_sint32 i = pattern->rows - 1; i > row; i--)
1767 {
1768 mp_ubyte* src = (i-1)*rowSize + pattern->patternData;
1769 mp_ubyte* dst = i*rowSize + pattern->patternData;
1770
1771 memcpy(dst, src, rowSize);
1772 }
1773
1774 memset(row*rowSize + pattern->patternData, 0, rowSize);
1775
1776 finishUndo(LastChangeInsertLine);
1777 }
1778
deleteNote(pp_int32 channel,pp_int32 row)1779 void PatternEditor::deleteNote(pp_int32 channel, pp_int32 row)
1780 {
1781 if (pattern == NULL || pattern->patternData == NULL)
1782 return;
1783
1784 if (row < 0 || row >= pattern->rows)
1785 return;
1786
1787 if (channel < 0 || channel >= pattern->channum)
1788 return;
1789
1790 prepareUndo();
1791
1792 mp_sint32 slotSize = pattern->effnum * 2 + 2;
1793 mp_sint32 rowSize = slotSize*pattern->channum;
1794
1795 for (mp_sint32 i = row; i < pattern->rows-1; i++)
1796 {
1797 mp_ubyte* src = (i+1)*rowSize + channel*slotSize + pattern->patternData;
1798 mp_ubyte* dst = i*rowSize + channel*slotSize + pattern->patternData;
1799
1800 memcpy(dst, src, slotSize);
1801 }
1802
1803 memset((pattern->rows-1)*rowSize + channel*slotSize + pattern->patternData, 0, slotSize);
1804
1805 finishUndo(LastChangeDeleteNote);
1806 }
1807
deleteLine(pp_int32 row)1808 void PatternEditor::deleteLine(pp_int32 row)
1809 {
1810 if (pattern == NULL || pattern->patternData == NULL)
1811 return;
1812
1813 if (row < 0 || row >= pattern->rows)
1814 return;
1815
1816 prepareUndo();
1817
1818 mp_sint32 slotSize = pattern->effnum * 2 + 2;
1819
1820 mp_sint32 rowSize = slotSize*pattern->channum;
1821
1822 for (mp_sint32 i = row; i < pattern->rows-1; i++)
1823 {
1824 mp_ubyte* src = (i+1)*rowSize + pattern->patternData;
1825 mp_ubyte* dst = i*rowSize + pattern->patternData;
1826
1827 memcpy(dst, src, rowSize);
1828 }
1829
1830 memset((pattern->rows-1)*rowSize + pattern->patternData, 0, rowSize);
1831
1832 finishUndo(LastChangeDeleteLine);
1833 }
1834
1835
moveSelection(pp_int32 channels,pp_int32 rows)1836 void PatternEditor::moveSelection(pp_int32 channels, pp_int32 rows)
1837 {
1838 PatternEditorTools::Position targetStart = selection.start;
1839 PatternEditorTools::Position targetEnd = selection.end;
1840 targetStart.row += rows;
1841 targetStart.channel += channels;
1842 targetEnd.row += rows;
1843 targetEnd.channel += channels;
1844
1845 if (!PatternEditorTools::hasValidSelection(pattern, selection.start, selection.end))
1846 return;
1847 if (!PatternEditorTools::hasValidSelection(pattern, targetStart, targetEnd))
1848 return;
1849
1850 prepareUndo();
1851
1852 PatternEditorTools tools(pattern);
1853 tools.moveSelection(selection.start, selection.end, channels, rows, true);
1854
1855 selection.start = targetStart;
1856 selection.end = targetEnd;
1857
1858 finishUndo(LastChangeMoveSelection);
1859 }
1860
1861
cloneSelection(pp_int32 channels,pp_int32 rows)1862 void PatternEditor::cloneSelection(pp_int32 channels, pp_int32 rows)
1863 {
1864 PatternEditorTools::Position targetStart = selection.start;
1865 PatternEditorTools::Position targetEnd = selection.end;
1866 targetStart.row += rows;
1867 targetStart.channel += channels;
1868 targetEnd.row += rows;
1869 targetEnd.channel += channels;
1870
1871 if (!PatternEditorTools::hasValidSelection(pattern, selection.start, selection.end))
1872 return;
1873 if (!PatternEditorTools::hasValidSelection(pattern, targetStart, targetEnd))
1874 return;
1875
1876 prepareUndo();
1877
1878 PatternEditorTools tools(pattern);
1879 tools.moveSelection(selection.start, selection.end, channels, rows, false); // don't erase source notes
1880
1881 selection.start = targetStart;
1882 selection.end = targetEnd;
1883
1884 finishUndo(LastChangeCloneSelection);
1885 }