1 // for finding memory leaks in debug mode with Visual Studio
2 #if defined _DEBUG && defined _MSC_VER
3 #include <crtdbg.h>
4 #endif
5
6 #include <stdint.h>
7 #include <stdbool.h>
8 #include <fcntl.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #ifdef _WIN32
12 #include <direct.h>
13 #else
14 #include <unistd.h>
15 #endif
16 #include "pt2_header.h"
17 #include "pt2_helpers.h"
18 #include "pt2_textout.h"
19 #include "pt2_tables.h"
20 #include "pt2_audio.h"
21 #include "pt2_diskop.h"
22 #include "pt2_mouse.h"
23 #include "pt2_sampler.h"
24 #include "pt2_visuals.h"
25 #include "pt2_keyboard.h"
26 #include "pt2_scopes.h"
27 #include "pt2_structs.h"
28 #include "pt2_config.h"
29 #include "pt2_audio.h"
30 #include "pt2_sync.h"
31 #include "pt2_chordmaker.h"
32
33 const int8_t scancode2NoteLo[52] = // "USB usage page standard" order
34 {
35 7, 4, 3, 16, -1, 6, 8, 24,
36 10, -1, 13, 11, 9, 26, 28, 12,
37 17, 1, 19, 23, 5, 14, 2, 21,
38 0, -1, 13, 15, -1, 18, 20, 22,
39 -1, 25, 27, -1, -1, -1, -1, -1,
40 -1, 30, 29, 31, 30, -1, 15, -1,
41 -1, 12, 14, 16
42 };
43
44 const int8_t scancode2NoteHi[52] = // "USB usage page standard" order
45 {
46 19, 16, 15, 28, -1, 18, 20, -2,
47 22, -1, 25, 23, 21, -2, -2, 24,
48 29, 13, 31, 35, 17, 26, 14, 33,
49 12, -1, 25, 27, -1, 30, 32, 34,
50 -1, -2, -2, -1, -1, -1, -1, -1,
51 -1, -2, -2, -2, -2, -1, 27, -1,
52 -1, 24, 26, 28
53 };
54
55 void setPattern(int16_t pattern); // pt2_replayer.c
56
57 void jamAndPlaceSample(SDL_Scancode scancode, bool normalMode);
58 uint8_t quantizeCheck(uint8_t row);
59 bool handleSpecialKeys(SDL_Scancode scancode);
60 int8_t keyToNote(SDL_Scancode scancode);
61
62 // used for re-rendering text object while editing it
updateTextObject(int16_t editObject)63 void updateTextObject(int16_t editObject)
64 {
65 switch (editObject)
66 {
67 default: break;
68 case PTB_SONGNAME: ui.updateSongName = true; break;
69 case PTB_SAMPLENAME: ui.updateCurrSampleName = true; break;
70 case PTB_PE_PATT: ui.updatePosEd = true; break;
71 case PTB_EO_QUANTIZE: ui.updateQuantizeText = true; break;
72 case PTB_EO_METRO_1: ui.updateMetro1Text = true; break;
73 case PTB_EO_METRO_2: ui.updateMetro2Text = true; break;
74 case PTB_EO_FROM_NUM: ui.updateFromText = true; break;
75 case PTB_EO_TO_NUM: ui.updateToText = true; break;
76 case PTB_EO_MIX: ui.updateMixText = true; break;
77 case PTB_EO_POS_NUM: ui.updatePosText = true; break;
78 case PTB_EO_MOD_NUM: ui.updateModText = true; break;
79 case PTB_EO_VOL_NUM: ui.updateVolText = true; break;
80 case PTB_DO_DATAPATH: ui.updateDiskOpPathText = true; break;
81 case PTB_POSS: ui.updateSongPos = true; break;
82 case PTB_PATTERNS: ui.updateSongPattern = true; break;
83 case PTB_LENGTHS: ui.updateSongLength = true; break;
84 case PTB_SAMPLES: ui.updateCurrSampleNum = true; break;
85 case PTB_SVOLUMES: ui.updateCurrSampleVolume = true; break;
86 case PTB_SLENGTHS: ui.updateCurrSampleLength = true; break;
87 case PTB_SREPEATS: ui.updateCurrSampleRepeat = true; break;
88 case PTB_SREPLENS: ui.updateCurrSampleReplen = true; break;
89 case PTB_PATTDATA: ui.updateCurrPattText = true; break;
90 case PTB_SA_VOL_FROM_NUM: ui.updateVolFromText = true; break;
91 case PTB_SA_VOL_TO_NUM: ui.updateVolToText = true; break;
92 case PTB_SA_FIL_LP_CUTOFF: ui.updateLPText = true; break;
93 case PTB_SA_FIL_HP_CUTOFF: ui.updateHPText = true; break;
94 }
95 }
96
exitGetTextLine(bool updateValue)97 void exitGetTextLine(bool updateValue)
98 {
99 int8_t tmp8;
100 int16_t posEdPos, tmp16;
101 int32_t tmp32;
102 UNICHAR *pathU;
103 moduleSample_t *s;
104
105 SDL_StopTextInput();
106
107 // if user updated the disk op path text
108 if (ui.diskOpScreenShown && ui.editObject == PTB_DO_DATAPATH)
109 {
110 pathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
111 if (pathU != NULL)
112 {
113 #ifdef _WIN32
114 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, editor.currPath, -1, pathU, PATH_MAX);
115 #else
116 strcpy(pathU, editor.currPath);
117 #endif
118 diskOpSetPath(pathU, DISKOP_CACHE);
119 free(pathU);
120 }
121 }
122
123 if (ui.editTextType != TEXT_EDIT_STRING)
124 {
125 if (ui.dstPos != ui.numLen)
126 removeTextEditMarker();
127
128 updateTextObject(ui.editObject);
129 }
130 else
131 {
132 removeTextEditMarker();
133
134 // yet another kludge...
135 if (ui.editObject == PTB_PE_PATT)
136 ui.updatePosEd = true;
137 }
138
139 ui.editTextFlag = false;
140
141 ui.lineCurX = 0;
142 ui.lineCurY = 0;
143 ui.editPos = NULL;
144 ui.dstPos = 0;
145
146 if (ui.editTextType == TEXT_EDIT_STRING)
147 {
148 if (ui.dstOffset != NULL)
149 *ui.dstOffset = '\0';
150
151 pointerSetPreviousMode();
152
153 if (!editor.mixFlag)
154 updateWindowTitle(MOD_IS_MODIFIED);
155 }
156 else
157 {
158 // set back GUI text pointers and update values (if requested)
159
160 s = &song->samples[editor.currSample];
161 switch (ui.editObject)
162 {
163 case PTB_SA_FIL_LP_CUTOFF:
164 {
165 editor.lpCutOffDisp = &editor.lpCutOff;
166
167 if (updateValue)
168 {
169 editor.lpCutOff = ui.tmpDisp16;
170 if (editor.lpCutOff > (uint16_t)(FILTERS_BASE_FREQ/2))
171 editor.lpCutOff = (uint16_t)(FILTERS_BASE_FREQ/2);
172
173 ui.updateLPText = true;
174 }
175 }
176 break;
177
178 case PTB_SA_FIL_HP_CUTOFF:
179 {
180 editor.hpCutOffDisp = &editor.hpCutOff;
181
182 if (updateValue)
183 {
184 editor.hpCutOff = ui.tmpDisp16;
185 if (editor.hpCutOff > (uint16_t)(FILTERS_BASE_FREQ/2))
186 editor.hpCutOff = (uint16_t)(FILTERS_BASE_FREQ/2);
187
188 ui.updateHPText = true;
189 }
190 }
191 break;
192
193 case PTB_SA_VOL_FROM_NUM:
194 {
195 editor.vol1Disp = &editor.vol1;
196
197 if (updateValue)
198 {
199 editor.vol1 = ui.tmpDisp16;
200 if (editor.vol1 > 200)
201 editor.vol1 = 200;
202
203 ui.updateVolFromText = true;
204 showVolFromSlider();
205 }
206 }
207 break;
208
209 case PTB_SA_VOL_TO_NUM:
210 {
211 editor.vol2Disp = &editor.vol2;
212
213 if (updateValue)
214 {
215 editor.vol2 = ui.tmpDisp16;
216 if (editor.vol2 > 200)
217 editor.vol2 = 200;
218
219 ui.updateVolToText = true;
220 showVolToSlider();
221 }
222 }
223 break;
224
225 case PTB_EO_VOL_NUM:
226 {
227 editor.sampleVolDisp = &editor.sampleVol;
228
229 if (updateValue)
230 {
231 editor.sampleVol = ui.tmpDisp16;
232 ui.updateVolText = true;
233 }
234 }
235 break;
236
237 case PTB_EO_POS_NUM:
238 {
239 editor.samplePosDisp = &editor.samplePos;
240
241 if (updateValue)
242 {
243 editor.samplePos = ui.tmpDisp16;
244 if (editor.samplePos > song->samples[editor.currSample].length)
245 editor.samplePos = song->samples[editor.currSample].length;
246
247 ui.updatePosText = true;
248 }
249 }
250 break;
251
252 case PTB_EO_QUANTIZE:
253 {
254 editor.quantizeValueDisp = &config.quantizeValue;
255
256 if (updateValue)
257 {
258 if (ui.tmpDisp16 > 63)
259 ui.tmpDisp16 = 63;
260
261 config.quantizeValue = ui.tmpDisp16;
262 ui.updateQuantizeText = true;
263 }
264 }
265 break;
266
267 case PTB_EO_METRO_1: // metronome speed
268 {
269 editor.metroSpeedDisp = &editor.metroSpeed;
270
271 if (updateValue)
272 {
273 if (ui.tmpDisp16 > 64)
274 ui.tmpDisp16 = 64;
275
276 editor.metroSpeed = ui.tmpDisp16;
277 ui.updateMetro1Text = true;
278 }
279 }
280 break;
281
282 case PTB_EO_METRO_2: // metronome channel
283 {
284 editor.metroChannelDisp = &editor.metroChannel;
285
286 if (updateValue)
287 {
288 if (ui.tmpDisp16 > 4)
289 ui.tmpDisp16 = 4;
290
291 editor.metroChannel = ui.tmpDisp16;
292 ui.updateMetro2Text = true;
293 }
294 }
295 break;
296
297 case PTB_EO_FROM_NUM:
298 {
299 editor.sampleFromDisp = &editor.sampleFrom;
300
301 if (updateValue)
302 {
303 editor.sampleFrom = ui.tmpDisp8;
304
305 // signed check + normal check
306 if (editor.sampleFrom < 0x00 || editor.sampleFrom > 0x1F)
307 editor.sampleFrom = 0x1F;
308
309 ui.updateFromText = true;
310 }
311 }
312 break;
313
314 case PTB_EO_TO_NUM:
315 {
316 editor.sampleToDisp = &editor.sampleTo;
317
318 if (updateValue)
319 {
320 editor.sampleTo = ui.tmpDisp8;
321
322 // signed check + normal check
323 if (editor.sampleTo < 0x00 || editor.sampleTo > 0x1F)
324 editor.sampleTo = 0x1F;
325
326 ui.updateToText = true;
327 }
328 }
329 break;
330
331 case PTB_PE_PATT:
332 {
333 posEdPos = song->currOrder;
334 if (posEdPos > song->header.numOrders-1)
335 posEdPos = song->header.numOrders-1;
336
337 editor.currPosEdPattDisp = &song->header.order[posEdPos];
338
339 if (updateValue)
340 {
341 if (ui.tmpDisp16 > MAX_PATTERNS-1)
342 ui.tmpDisp16 = MAX_PATTERNS-1;
343
344 song->header.order[posEdPos] = ui.tmpDisp16;
345
346 updateWindowTitle(MOD_IS_MODIFIED);
347
348 if (ui.posEdScreenShown)
349 ui.updatePosEd = true;
350
351 ui.updateSongPattern = true;
352 ui.updateSongSize = true;
353 }
354 }
355 break;
356
357 case PTB_POSS:
358 {
359 editor.currPosDisp = &song->currOrder;
360
361 if (updateValue)
362 {
363 tmp16 = ui.tmpDisp16;
364 if (tmp16 > 126)
365 tmp16 = 126;
366
367 if (song->currOrder != tmp16)
368 {
369 song->currOrder = tmp16;
370 editor.currPatternDisp = &song->header.order[song->currOrder];
371
372 if (ui.posEdScreenShown)
373 ui.updatePosEd = true;
374
375 ui.updateSongPos = true;
376 ui.updatePatternData = true;
377 }
378 }
379 }
380 break;
381
382 case PTB_PATTERNS:
383 {
384 editor.currPatternDisp = &song->header.order[song->currOrder];
385
386 if (updateValue)
387 {
388 tmp16 = ui.tmpDisp16;
389 if (tmp16 > MAX_PATTERNS-1)
390 tmp16 = MAX_PATTERNS-1;
391
392 if (song->header.order[song->currOrder] != tmp16)
393 {
394 song->header.order[song->currOrder] = tmp16;
395
396 updateWindowTitle(MOD_IS_MODIFIED);
397
398 if (ui.posEdScreenShown)
399 ui.updatePosEd = true;
400
401 ui.updateSongPattern = true;
402 ui.updateSongSize = true;
403 }
404 }
405 }
406 break;
407
408 case PTB_LENGTHS:
409 {
410 editor.currLengthDisp = &song->header.numOrders;
411
412 if (updateValue)
413 {
414 tmp16 = CLAMP(ui.tmpDisp16, 1, 127);
415
416 if (song->header.numOrders != tmp16)
417 {
418 song->header.numOrders = tmp16;
419
420 posEdPos = song->currOrder;
421 if (posEdPos > song->header.numOrders-1)
422 posEdPos = song->header.numOrders-1;
423
424 editor.currPosEdPattDisp = &song->header.order[posEdPos];
425
426 if (ui.posEdScreenShown)
427 ui.updatePosEd = true;
428
429 ui.updateSongLength = true;
430 ui.updateSongSize = true;
431 updateWindowTitle(MOD_IS_MODIFIED);
432 }
433 }
434 }
435 break;
436
437 case PTB_PATTDATA:
438 {
439 editor.currEditPatternDisp = &song->currPattern;
440
441 if (updateValue)
442 {
443 if (song->currPattern != ui.tmpDisp16)
444 {
445 setPattern(ui.tmpDisp16);
446 ui.updatePatternData = true;
447 ui.updateCurrPattText = true;
448 }
449 }
450 }
451 break;
452
453 case PTB_SAMPLES:
454 {
455 editor.currSampleDisp = &editor.currSample;
456
457 if (updateValue)
458 {
459 tmp8 = ui.tmpDisp8;
460 if (tmp8 < 0x00) // (signed) if >0x7F was entered, clamp to 0x1F
461 tmp8 = 0x1F;
462
463 tmp8 = CLAMP(tmp8, 0x01, 0x1F) - 1;
464
465 if (tmp8 != editor.currSample)
466 {
467 editor.currSample = tmp8;
468 updateCurrSample();
469 }
470 }
471 }
472 break;
473
474 case PTB_SVOLUMES:
475 {
476 s->volumeDisp = &s->volume;
477
478 if (updateValue)
479 {
480 tmp8 = ui.tmpDisp8;
481
482 // signed check + normal check
483 if (tmp8 < 0x00 || tmp8 > 0x40)
484 tmp8 = 0x40;
485
486 if (s->volume != tmp8)
487 {
488 s->volume = tmp8;
489 ui.updateCurrSampleVolume = true;
490 updateWindowTitle(MOD_IS_MODIFIED);
491 }
492 }
493 }
494 break;
495
496 case PTB_SLENGTHS:
497 {
498 s->lengthDisp = &s->length;
499
500 if (updateValue)
501 {
502 tmp32 = ui.tmpDisp16 & 0xFFFE; // even'ify
503
504 if (s->loopStart+s->loopLength > 2)
505 {
506 if (tmp32 < s->loopStart+s->loopLength)
507 tmp32 = s->loopStart+s->loopLength;
508 }
509
510 tmp32 &= 0xFFFE;
511
512 if (s->length != tmp32)
513 {
514 turnOffVoices();
515 s->length = (uint16_t)tmp32;
516
517 ui.updateCurrSampleLength = true;
518 ui.updateSongSize = true;
519 updateSamplePos();
520
521 if (ui.samplerScreenShown)
522 redrawSample();
523
524 recalcChordLength();
525 updateWindowTitle(MOD_IS_MODIFIED);
526 }
527 }
528 }
529 break;
530
531 case PTB_SREPEATS:
532 {
533 s->loopStartDisp = &s->loopStart;
534
535 if (updateValue)
536 {
537 tmp32 = ui.tmpDisp16 & 0xFFFE; // even'ify
538
539 if (s->length >= s->loopLength)
540 {
541 if (tmp32+s->loopLength > s->length)
542 tmp32 = s->length - s->loopLength;
543 }
544 else
545 {
546 tmp32 = 0;
547 }
548
549 tmp32 &= 0xFFFE;
550
551 if (s->loopStart != tmp32)
552 {
553 turnOffVoices();
554 s->loopStart = (uint16_t)tmp32;
555 mixerUpdateLoops();
556
557 ui.updateCurrSampleRepeat = true;
558
559 if (ui.editOpScreenShown && ui.editOpScreen == 3)
560 ui.updateLengthText = true;
561
562 if (ui.samplerScreenShown)
563 setLoopSprites();
564
565 updateWindowTitle(MOD_IS_MODIFIED);
566 }
567 }
568 }
569 break;
570
571 case PTB_SREPLENS:
572 {
573 s->loopLengthDisp = &s->loopLength;
574
575 if (updateValue)
576 {
577 tmp32 = ui.tmpDisp16 & 0xFFFE; // even'ify
578
579 if (s->length >= s->loopStart)
580 {
581 if (s->loopStart+tmp32 > s->length)
582 tmp32 = s->length - s->loopStart;
583 }
584 else
585 {
586 tmp32 = 2;
587 }
588
589 tmp32 &= 0xFFFE;
590
591 if (tmp32 < 2)
592 tmp32 = 2;
593
594 if (s->loopLength != tmp32)
595 {
596 turnOffVoices();
597 s->loopLength = (uint16_t)tmp32;
598 mixerUpdateLoops();
599
600 ui.updateCurrSampleReplen = true;
601 if (ui.editOpScreenShown && ui.editOpScreen == 3)
602 ui.updateLengthText = true;
603
604 if (ui.samplerScreenShown)
605 setLoopSprites();
606
607 updateWindowTitle(MOD_IS_MODIFIED);
608 }
609 }
610 }
611 break;
612
613 default: break;
614 }
615
616 pointerSetPreviousMode();
617 }
618
619 ui.editTextType = 0;
620 }
621
getTextLine(int16_t editObject)622 void getTextLine(int16_t editObject)
623 {
624 pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
625
626 ui.lineCurY = (ui.editTextPos / 40) + 5;
627 ui.lineCurX = ((ui.editTextPos % 40) * FONT_CHAR_W) + 4;
628 ui.dstPtr = ui.showTextPtr;
629 ui.editPos = ui.showTextPtr;
630 ui.dstPos = 0;
631 ui.editTextFlag = true;
632 ui.editTextType = TEXT_EDIT_STRING;
633 ui.editObject = editObject;
634
635 if (ui.dstOffset != NULL)
636 ui.dstOffset[0] = '\0';
637
638 // kludge
639 if (editor.mixFlag)
640 {
641 textCharNext();
642 textCharNext();
643 textCharNext();
644 textCharNext();
645 }
646
647 renderTextEditMarker();
648 SDL_StartTextInput();
649 }
650
getNumLine(uint8_t type,int16_t editObject)651 void getNumLine(uint8_t type, int16_t editObject)
652 {
653 pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
654
655 ui.lineCurY = (ui.editTextPos / 40) + 5;
656 ui.lineCurX = ((ui.editTextPos % 40) * FONT_CHAR_W) + 4;
657 ui.dstPos = 0;
658 ui.editTextFlag = true;
659 ui.editTextType = type;
660 ui.editObject = editObject;
661
662 renderTextEditMarker();
663 SDL_StartTextInput();
664 }
665
handleEditKeys(SDL_Scancode scancode,bool normalMode)666 void handleEditKeys(SDL_Scancode scancode, bool normalMode)
667 {
668 int8_t key, hexKey, numberKey;
669 note_t *note;
670
671 if (ui.editTextFlag)
672 return;
673
674 if (ui.samplerScreenShown || (editor.currMode == MODE_IDLE || editor.currMode == MODE_PLAY))
675 {
676 // at this point it will only jam, not place it
677 if (!keyb.leftAltPressed && !keyb.leftAmigaPressed && !keyb.leftCtrlPressed && !keyb.shiftPressed)
678 jamAndPlaceSample(scancode, normalMode);
679
680 return;
681 }
682
683 // handle modified (ALT/CTRL/SHIFT etc) keys for editing
684 if (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD)
685 {
686 if (handleSpecialKeys(scancode))
687 {
688 if (editor.currMode != MODE_RECORD)
689 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
690
691 return;
692 }
693 }
694
695 // are we editing a note, or other stuff?
696 if (cursor.mode != CURSOR_NOTE)
697 {
698 // if we held down any key modifier at this point, then do nothing
699 if (keyb.leftAltPressed || keyb.leftAmigaPressed || keyb.leftCtrlPressed || keyb.shiftPressed)
700 return;
701
702 if (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD)
703 {
704 if (scancode == SDL_SCANCODE_0)
705 numberKey = 0;
706 else if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_9)
707 numberKey = (int8_t)scancode - (SDL_SCANCODE_1-1);
708 else
709 numberKey = -1;
710
711 if (scancode >= SDL_SCANCODE_A && scancode <= SDL_SCANCODE_F)
712 hexKey = 10 + ((int8_t)scancode - SDL_SCANCODE_A);
713 else
714 hexKey = -1;
715
716 key = -1;
717 if (numberKey != -1)
718 {
719 if (key == -1)
720 key = 0;
721
722 key += numberKey;
723 }
724
725 if (hexKey != -1)
726 {
727 if (key == -1)
728 key = 0;
729
730 key += hexKey;
731 }
732
733 note = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
734
735 switch (cursor.mode)
736 {
737 case CURSOR_SAMPLE1:
738 {
739 if (key != -1 && key < 2)
740 {
741 note->sample = (uint8_t)((note->sample % 0x10) | (key << 4));
742
743 if (editor.currMode != MODE_RECORD)
744 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
745
746 updateWindowTitle(MOD_IS_MODIFIED);
747 }
748 }
749 break;
750
751 case CURSOR_SAMPLE2:
752 {
753 if (key != -1 && key < 16)
754 {
755 note->sample = (uint8_t)((note->sample & 16) | key);
756
757 if (editor.currMode != MODE_RECORD)
758 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
759
760 updateWindowTitle(MOD_IS_MODIFIED);
761 }
762 }
763 break;
764
765 case CURSOR_CMD:
766 {
767 if (key != -1 && key < 16)
768 {
769 note->command = (uint8_t)key;
770
771 if (editor.currMode != MODE_RECORD)
772 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
773
774 updateWindowTitle(MOD_IS_MODIFIED);
775 }
776 }
777 break;
778
779 case CURSOR_PARAM1:
780 {
781 if (key != -1 && key < 16)
782 {
783 note->param = (uint8_t)((note->param % 0x10) | (key << 4));
784
785 if (editor.currMode != MODE_RECORD)
786 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
787
788 updateWindowTitle(MOD_IS_MODIFIED);
789 }
790 }
791 break;
792
793 case CURSOR_PARAM2:
794 {
795 if (key != -1 && key < 16)
796 {
797 note->param = (uint8_t)((note->param & 0xF0) | key);
798
799 if (editor.currMode != MODE_RECORD)
800 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
801
802 updateWindowTitle(MOD_IS_MODIFIED);
803 }
804 }
805 break;
806
807 default: break;
808 }
809 }
810 }
811 else
812 {
813 if (scancode == SDL_SCANCODE_DELETE)
814 {
815 if (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD)
816 {
817 note = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
818
819 if (!keyb.leftAltPressed)
820 {
821 note->sample = 0;
822 note->period = 0;
823 }
824
825 if (keyb.shiftPressed || keyb.leftAltPressed)
826 {
827 note->command = 0;
828 note->param = 0;
829 }
830
831 if (editor.currMode != MODE_RECORD)
832 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
833
834 updateWindowTitle(MOD_IS_MODIFIED);
835 }
836 }
837 else
838 {
839 // if we held down any key modifier at this point, then do nothing
840 if (keyb.leftAltPressed || keyb.leftAmigaPressed || keyb.leftCtrlPressed || keyb.shiftPressed)
841 return;
842
843 jamAndPlaceSample(scancode, normalMode);
844 }
845 }
846 }
847
handleSpecialKeys(SDL_Scancode scancode)848 bool handleSpecialKeys(SDL_Scancode scancode)
849 {
850 note_t *patt, *note, *prevNote;
851
852 if (!keyb.leftAltPressed)
853 return false;
854
855 patt = song->patterns[song->currPattern];
856 note = &patt[(song->currRow * AMIGA_VOICES) + cursor.channel];
857 prevNote = &patt[(((song->currRow - 1) & 0x3F) * AMIGA_VOICES) + cursor.channel];
858
859 if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)
860 {
861 // insert stored effect (buffer[0..8])
862 note->command = editor.effectMacros[scancode - SDL_SCANCODE_1] >> 8;
863 note->param = editor.effectMacros[scancode - SDL_SCANCODE_1] & 0xFF;
864
865 updateWindowTitle(MOD_IS_MODIFIED);
866 return true;
867 }
868
869 // copy command+effect from above into current command+effect
870 if (scancode == SDL_SCANCODE_BACKSLASH)
871 {
872 note->command = prevNote->command;
873 note->param = prevNote->param;
874
875 updateWindowTitle(MOD_IS_MODIFIED);
876 return true;
877 }
878
879 // copy command+(effect + 1) from above into current command+effect
880 if (scancode == SDL_SCANCODE_EQUALS)
881 {
882 note->command = prevNote->command;
883 note->param = prevNote->param + 1; // wraps 0x00..0xFF
884
885 updateWindowTitle(MOD_IS_MODIFIED);
886 return true;
887 }
888
889 // copy command+(effect - 1) from above into current command+effect
890 if (scancode == SDL_SCANCODE_MINUS)
891 {
892 note->command = prevNote->command;
893 note->param = prevNote->param - 1; // wraps 0x00..0xFF
894
895 updateWindowTitle(MOD_IS_MODIFIED);
896 return true;
897 }
898
899 return false;
900 }
901
handleSampleJamming(SDL_Scancode scancode)902 void handleSampleJamming(SDL_Scancode scancode) // used for the sampling feature (in SAMPLER)
903 {
904 const int32_t ch = cursor.channel;
905
906 if (scancode == SDL_SCANCODE_NONUSBACKSLASH)
907 {
908 turnOffVoices(); // magic "kill all voices" button
909 return;
910 }
911
912 const int8_t noteVal = keyToNote(scancode);
913 if (noteVal < 0 || noteVal > 35)
914 return;
915
916 moduleSample_t *s = &song->samples[editor.currSample];
917 if (s->length <= 1)
918 return;
919
920 lockAudio();
921
922 song->channels[ch].n_samplenum = editor.currSample; // needed for sample playback/sampling line
923
924 const int8_t *n_start = &song->sampleData[s->offset];
925 const int8_t vol = 64;
926 const uint16_t n_length = s->length >> 1;
927 const uint16_t period = periodTable[((s->fineTune & 0xF) * 37) + noteVal];
928
929 paulaSetVolume(ch, vol);
930 paulaSetPeriod(ch, period);
931 paulaSetData(ch, n_start);
932 paulaSetLength(ch, n_length);
933
934 if (!editor.muted[ch])
935 paulaStartDMA(ch);
936 else
937 paulaStopDMA(ch);
938
939 // these take effect after the current DMA cycle is done
940 paulaSetData(ch, NULL);
941 paulaSetLength(ch, 1);
942
943 unlockAudio();
944 }
945
jamAndPlaceSample(SDL_Scancode scancode,bool normalMode)946 void jamAndPlaceSample(SDL_Scancode scancode, bool normalMode)
947 {
948 int8_t noteVal;
949 uint8_t ch;
950 int16_t tempPeriod;
951 uint16_t cleanPeriod;
952 moduleChannel_t *chn;
953 moduleSample_t *s;
954 note_t *note;
955
956 ch = cursor.channel;
957 assert(ch < AMIGA_VOICES);
958
959 chn = &song->channels[ch];
960 note = &song->patterns[song->currPattern][(quantizeCheck(song->currRow) * AMIGA_VOICES) + ch];
961
962 noteVal = normalMode ? keyToNote(scancode) : pNoteTable[editor.currSample];
963 if (noteVal >= 0)
964 {
965 s = &song->samples[editor.currSample];
966
967 tempPeriod = periodTable[((s->fineTune & 0xF) * 37) + noteVal];
968 cleanPeriod = periodTable[noteVal];
969
970 editor.currPlayNote = noteVal;
971
972 // play current sample
973
974 // don't play sample if we quantized to another row (will be played in modplayer instead)
975 if (editor.currMode != MODE_RECORD || !editor.didQuantize)
976 {
977 lockAudio();
978
979 chn->n_samplenum = editor.currSample;
980 chn->n_volume = s->volume;
981 chn->n_period = tempPeriod;
982 chn->n_start = &song->sampleData[s->offset];
983 chn->n_length = (s->loopStart > 0) ? (s->loopStart + s->loopLength) >> 1 : s->length >> 1;
984 chn->n_loopstart = &song->sampleData[s->offset + s->loopStart];
985 chn->n_replen = s->loopLength >> 1;
986
987 if (chn->n_length == 0)
988 chn->n_length = 1;
989
990 paulaSetVolume(ch, chn->n_volume);
991 paulaSetPeriod(ch, chn->n_period);
992 paulaSetData(ch, chn->n_start);
993 paulaSetLength(ch, chn->n_length);
994
995 if (!editor.muted[ch])
996 paulaStartDMA(ch);
997 else
998 paulaStopDMA(ch);
999
1000 // these take effect after the current DMA cycle is done
1001 paulaSetData(ch, chn->n_loopstart);
1002 paulaSetLength(ch, chn->n_replen);
1003
1004 unlockAudio();
1005 }
1006
1007 // normalMode = normal keys, or else keypad keys (in jam mode)
1008 if (normalMode || editor.pNoteFlag != 0)
1009 {
1010 if (normalMode || editor.pNoteFlag == 2)
1011 {
1012 // insert note and sample number
1013 if (!ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
1014 {
1015 note->sample = editor.sampleZero ? 0 : (editor.currSample + 1);
1016 note->period = cleanPeriod;
1017
1018 if (editor.autoInsFlag)
1019 {
1020 note->command = editor.effectMacros[editor.autoInsSlot] >> 8;
1021 note->param = editor.effectMacros[editor.autoInsSlot] & 0xFF;
1022 }
1023
1024 if (editor.currMode != MODE_RECORD)
1025 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
1026
1027 updateWindowTitle(MOD_IS_MODIFIED);
1028 }
1029 }
1030
1031 if (editor.multiFlag)
1032 gotoNextMulti();
1033 }
1034
1035 updateSpectrumAnalyzer(s->volume, tempPeriod);
1036 }
1037 else if (noteVal == -2)
1038 {
1039 // delete note and sample if illegal note (= -2, -1 = ignore) key was entered
1040
1041 if (normalMode || editor.pNoteFlag == 2)
1042 {
1043 if (!ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
1044 {
1045 note->period = 0;
1046 note->sample = 0;
1047
1048 if (editor.currMode != MODE_RECORD)
1049 modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
1050
1051 updateWindowTitle(MOD_IS_MODIFIED);
1052 }
1053 }
1054 }
1055 }
1056
quantizeCheck(uint8_t row)1057 uint8_t quantizeCheck(uint8_t row)
1058 {
1059 assert(song != NULL);
1060 if (song == NULL)
1061 return row;
1062
1063 const uint8_t quantize = (uint8_t)config.quantizeValue;
1064
1065 editor.didQuantize = false;
1066 if (editor.currMode == MODE_RECORD)
1067 {
1068 if (quantize == 0)
1069 {
1070 return row;
1071 }
1072 else if (quantize == 1)
1073 {
1074 if (song->tick > song->speed>>1)
1075 {
1076 row = (row + 1) & 0x3F;
1077 editor.didQuantize = true;
1078 }
1079 }
1080 else
1081 {
1082 uint8_t tempRow = ((((quantize >> 1) + row) & 0x3F) / quantize) * quantize;
1083 if (tempRow > row)
1084 editor.didQuantize = true;
1085
1086 return tempRow;
1087 }
1088 }
1089
1090 return row;
1091 }
1092
saveUndo(void)1093 void saveUndo(void)
1094 {
1095 memcpy(editor.undoBuffer, song->patterns[song->currPattern], sizeof (note_t) * (AMIGA_VOICES * MOD_ROWS));
1096 }
1097
undoLastChange(void)1098 void undoLastChange(void)
1099 {
1100 note_t data;
1101
1102 for (uint16_t i = 0; i < MOD_ROWS*AMIGA_VOICES; i++)
1103 {
1104 data = editor.undoBuffer[i];
1105 editor.undoBuffer[i] = song->patterns[song->currPattern][i];
1106 song->patterns[song->currPattern][i] = data;
1107 }
1108
1109 updateWindowTitle(MOD_IS_MODIFIED);
1110 ui.updatePatternData = true;
1111 }
1112
copySampleTrack(void)1113 void copySampleTrack(void)
1114 {
1115 uint8_t i;
1116 uint32_t tmpOffset;
1117 note_t *noteSrc;
1118 moduleSample_t *smpFrom, *smpTo;
1119
1120 if (editor.trackPattFlag == 2)
1121 {
1122 // copy from one sample slot to another
1123
1124 // never attempt to swap if from and/or to is 0
1125 if (editor.sampleFrom == 0 || editor.sampleTo == 0)
1126 {
1127 displayErrorMsg("FROM/TO = 0 !");
1128 return;
1129 }
1130
1131 smpTo = &song->samples[editor.sampleTo - 1];
1132 smpFrom = &song->samples[editor.sampleFrom - 1];
1133
1134 turnOffVoices();
1135
1136 // copy
1137 tmpOffset = smpTo->offset;
1138 *smpTo = *smpFrom;
1139 smpTo->offset = tmpOffset;
1140
1141 // update the copied sample's GUI text pointers
1142 smpTo->volumeDisp = &smpTo->volume;
1143 smpTo->lengthDisp = &smpTo->length;
1144 smpTo->loopStartDisp = &smpTo->loopStart;
1145 smpTo->loopLengthDisp = &smpTo->loopLength;
1146
1147 // copy sample data
1148 memcpy(&song->sampleData[smpTo->offset], &song->sampleData[smpFrom->offset], MAX_SAMPLE_LEN);
1149
1150 updateCurrSample();
1151 ui.updateSongSize = true;
1152 }
1153 else
1154 {
1155 // copy sample number in track/pattern
1156 if (editor.trackPattFlag == 0)
1157 {
1158 for (i = 0; i < MOD_ROWS; i++)
1159 {
1160 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1161 if (noteSrc->sample == editor.sampleFrom)
1162 noteSrc->sample = editor.sampleTo;
1163 }
1164 }
1165 else
1166 {
1167 for (i = 0; i < AMIGA_VOICES; i++)
1168 {
1169 for (uint8_t j = 0; j < MOD_ROWS; j++)
1170 {
1171 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1172 if (noteSrc->sample == editor.sampleFrom)
1173 noteSrc->sample = editor.sampleTo;
1174 }
1175 }
1176 }
1177
1178 ui.updatePatternData = true;
1179 }
1180
1181 editor.samplePos = 0;
1182 updateSamplePos();
1183
1184 updateWindowTitle(MOD_IS_MODIFIED);
1185 }
1186
exchSampleTrack(void)1187 void exchSampleTrack(void)
1188 {
1189 int8_t smp;
1190 uint32_t i, tmpOffset;
1191 moduleSample_t *smpFrom, *smpTo, smpTmp;
1192 note_t *noteSrc;
1193
1194 if (editor.trackPattFlag == 2)
1195 {
1196 // exchange sample slots
1197
1198 // never attempt to swap if from and/or to is 0
1199 if (editor.sampleFrom == 0 || editor.sampleTo == 0)
1200 {
1201 displayErrorMsg("FROM/TO = 0 !");
1202 return;
1203 }
1204
1205 smpTo = &song->samples[editor.sampleTo-1];
1206 smpFrom = &song->samples[editor.sampleFrom-1];
1207
1208 turnOffVoices();
1209
1210 // swap offsets first so that the next swap will leave offsets intact
1211 tmpOffset = smpFrom->offset;
1212 smpFrom->offset = smpTo->offset;
1213 smpTo->offset = tmpOffset;
1214
1215 // swap sample (now offsets are left as before)
1216 smpTmp = *smpFrom;
1217 *smpFrom = *smpTo;
1218 *smpTo = smpTmp;
1219
1220 // update the swapped sample's GUI text pointers
1221 smpFrom->volumeDisp = &smpFrom->volume;
1222 smpFrom->lengthDisp = &smpFrom->length;
1223 smpFrom->loopStartDisp = &smpFrom->loopStart;
1224 smpFrom->loopLengthDisp = &smpFrom->loopLength;
1225 smpTo->volumeDisp = &smpTo->volume;
1226 smpTo->lengthDisp = &smpTo->length;
1227 smpTo->loopStartDisp = &smpTo->loopStart;
1228 smpTo->loopLengthDisp = &smpTo->loopLength;
1229
1230 // swap sample data
1231 for (i = 0; i < MAX_SAMPLE_LEN; i++)
1232 {
1233 smp = song->sampleData[smpFrom->offset+i];
1234 song->sampleData[smpFrom->offset+i] = song->sampleData[smpTo->offset+i];
1235 song->sampleData[smpTo->offset+i] = smp;
1236 }
1237
1238 editor.sampleZero = false;
1239
1240 updateCurrSample();
1241 }
1242 else
1243 {
1244 // exchange sample number in track/pattern
1245 if (editor.trackPattFlag == 0)
1246 {
1247 for (i = 0; i < MOD_ROWS; i++)
1248 {
1249 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1250
1251 if (noteSrc->sample == editor.sampleFrom) noteSrc->sample = editor.sampleTo;
1252 else if (noteSrc->sample == editor.sampleTo) noteSrc->sample = editor.sampleFrom;
1253 }
1254 }
1255 else
1256 {
1257 for (i = 0; i < AMIGA_VOICES; i++)
1258 {
1259 for (uint8_t j = 0; j < MOD_ROWS; j++)
1260 {
1261 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1262
1263 if (noteSrc->sample == editor.sampleFrom) noteSrc->sample = editor.sampleTo;
1264 else if (noteSrc->sample == editor.sampleTo) noteSrc->sample = editor.sampleFrom;
1265 }
1266 }
1267 }
1268
1269 ui.updatePatternData = true;
1270 }
1271
1272 editor.samplePos = 0;
1273 updateSamplePos();
1274
1275 updateWindowTitle(MOD_IS_MODIFIED);
1276 }
1277
delSampleTrack(void)1278 void delSampleTrack(void)
1279 {
1280 uint8_t i;
1281 note_t *noteSrc;
1282
1283 saveUndo();
1284 if (editor.trackPattFlag == 0)
1285 {
1286 for (i = 0; i < MOD_ROWS; i++)
1287 {
1288 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1289 if (noteSrc->sample == editor.currSample+1)
1290 {
1291 noteSrc->period = 0;
1292 noteSrc->sample = 0;
1293 noteSrc->command = 0;
1294 noteSrc->param = 0;
1295 }
1296 }
1297 }
1298 else
1299 {
1300 for (i = 0; i < AMIGA_VOICES; i++)
1301 {
1302 for (uint8_t j = 0; j < MOD_ROWS; j++)
1303 {
1304 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1305 if (noteSrc->sample == editor.currSample+1)
1306 {
1307 noteSrc->period = 0;
1308 noteSrc->sample = 0;
1309 noteSrc->command = 0;
1310 noteSrc->param = 0;
1311 }
1312 }
1313 }
1314 }
1315
1316 updateWindowTitle(MOD_IS_MODIFIED);
1317 ui.updatePatternData = true;
1318 }
1319
trackNoteUp(bool sampleAllFlag,uint8_t from,uint8_t to)1320 void trackNoteUp(bool sampleAllFlag, uint8_t from, uint8_t to)
1321 {
1322 bool noteDeleted;
1323 uint8_t j;
1324 note_t *noteSrc;
1325
1326 if (from > to)
1327 {
1328 j = from;
1329 from = to;
1330 to = j;
1331 }
1332
1333 saveUndo();
1334 for (uint8_t i = from; i <= to; i++)
1335 {
1336 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1337
1338 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1339 continue;
1340
1341 if (noteSrc->period)
1342 {
1343 // period -> note
1344 for (j = 0; j < 36; j++)
1345 {
1346 if (noteSrc->period >= periodTable[j])
1347 break;
1348 }
1349
1350 noteDeleted = false;
1351 if (++j > 35)
1352 {
1353 j = 35;
1354
1355 if (config.transDel)
1356 {
1357 noteSrc->period = 0;
1358 noteSrc->sample = 0;
1359
1360 noteDeleted = true;
1361 }
1362 }
1363
1364 if (!noteDeleted)
1365 noteSrc->period = periodTable[j];
1366 }
1367 }
1368
1369 updateWindowTitle(MOD_IS_MODIFIED);
1370 ui.updatePatternData = true;
1371 }
1372
trackNoteDown(bool sampleAllFlag,uint8_t from,uint8_t to)1373 void trackNoteDown(bool sampleAllFlag, uint8_t from, uint8_t to)
1374 {
1375 bool noteDeleted;
1376 int8_t j;
1377 note_t *noteSrc;
1378
1379 if (from > to)
1380 {
1381 j = from;
1382 from = to;
1383 to = j;
1384 }
1385
1386 saveUndo();
1387 for (uint8_t i = from; i <= to; i++)
1388 {
1389 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1390
1391 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1392 continue;
1393
1394 if (noteSrc->period)
1395 {
1396 // period -> note
1397 for (j = 0; j < 36; j++)
1398 {
1399 if (noteSrc->period >= periodTable[j])
1400 break;
1401 }
1402
1403 noteDeleted = false;
1404 if (--j < 0)
1405 {
1406 j = 0;
1407
1408 if (config.transDel)
1409 {
1410 noteSrc->period = 0;
1411 noteSrc->sample = 0;
1412
1413 noteDeleted = true;
1414 }
1415 }
1416
1417 if (!noteDeleted)
1418 noteSrc->period = periodTable[j];
1419 }
1420 }
1421
1422 updateWindowTitle(MOD_IS_MODIFIED);
1423 ui.updatePatternData = true;
1424 }
1425
trackOctaUp(bool sampleAllFlag,uint8_t from,uint8_t to)1426 void trackOctaUp(bool sampleAllFlag, uint8_t from, uint8_t to)
1427 {
1428 bool noteDeleted, noteChanged;
1429 uint8_t j;
1430 note_t *noteSrc;
1431
1432 if (from > to)
1433 {
1434 j = from;
1435 from = to;
1436 to = j;
1437 }
1438
1439 noteChanged = false;
1440
1441 saveUndo();
1442 for (uint8_t i = from; i <= to; i++)
1443 {
1444 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1445
1446 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1447 continue;
1448
1449 if (noteSrc->period)
1450 {
1451 uint16_t oldPeriod = noteSrc->period;
1452
1453 // period -> note
1454 for (j = 0; j < 36; j++)
1455 {
1456 if (noteSrc->period >= periodTable[j])
1457 break;
1458 }
1459
1460 noteDeleted = false;
1461 if (j+12 > 35 && config.transDel)
1462 {
1463 noteSrc->period = 0;
1464 noteSrc->sample = 0;
1465
1466 noteDeleted = true;
1467 }
1468
1469 if (j <= 23)
1470 j += 12;
1471
1472 if (!noteDeleted)
1473 noteSrc->period = periodTable[j];
1474
1475 if (noteSrc->period != oldPeriod)
1476 noteChanged = true;
1477 }
1478 }
1479
1480 if (noteChanged)
1481 {
1482 updateWindowTitle(MOD_IS_MODIFIED);
1483 ui.updatePatternData = true;
1484 }
1485 }
1486
trackOctaDown(bool sampleAllFlag,uint8_t from,uint8_t to)1487 void trackOctaDown(bool sampleAllFlag, uint8_t from, uint8_t to)
1488 {
1489 bool noteDeleted;
1490 int8_t j;
1491 note_t *noteSrc;
1492
1493 if (from > to)
1494 {
1495 j = from;
1496 from = to;
1497 to = j;
1498 }
1499
1500 saveUndo();
1501 for (uint8_t i = from; i <= to; i++)
1502 {
1503 noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
1504
1505 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1506 continue;
1507
1508 if (noteSrc->period)
1509 {
1510 // period -> note
1511 for (j = 0; j < 36; j++)
1512 {
1513 if (noteSrc->period >= periodTable[j])
1514 break;
1515 }
1516
1517 noteDeleted = false;
1518 if (j-12 < 0 && config.transDel)
1519 {
1520 noteSrc->period = 0;
1521 noteSrc->sample = 0;
1522
1523 noteDeleted = true;
1524 }
1525
1526 if (j >= 12)
1527 j -= 12;
1528
1529 if (!noteDeleted)
1530 noteSrc->period = periodTable[j];
1531 }
1532 }
1533
1534 updateWindowTitle(MOD_IS_MODIFIED);
1535 ui.updatePatternData = true;
1536 }
1537
pattNoteUp(bool sampleAllFlag)1538 void pattNoteUp(bool sampleAllFlag)
1539 {
1540 bool noteDeleted;
1541 uint8_t k;
1542 note_t *noteSrc;
1543
1544 saveUndo();
1545 for (uint8_t i = 0; i < AMIGA_VOICES; i++)
1546 {
1547 for (uint8_t j = 0; j < MOD_ROWS; j++)
1548 {
1549 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1550
1551 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1552 continue;
1553
1554 if (noteSrc->period)
1555 {
1556 // period -> note
1557 for (k = 0; k < 36; k++)
1558 {
1559 if (noteSrc->period >= periodTable[k])
1560 break;
1561 }
1562
1563 noteDeleted = false;
1564 if (++k > 35)
1565 {
1566 k = 35;
1567
1568 if (config.transDel)
1569 {
1570 noteSrc->period = 0;
1571 noteSrc->sample = 0;
1572
1573 noteDeleted = true;
1574 }
1575 }
1576
1577 if (!noteDeleted)
1578 noteSrc->period = periodTable[k];
1579 }
1580 }
1581 }
1582
1583 updateWindowTitle(MOD_IS_MODIFIED);
1584 ui.updatePatternData = true;
1585 }
1586
pattNoteDown(bool sampleAllFlag)1587 void pattNoteDown(bool sampleAllFlag)
1588 {
1589 bool noteDeleted;
1590 int8_t k;
1591 note_t *noteSrc;
1592
1593 saveUndo();
1594 for (uint8_t i = 0; i < AMIGA_VOICES; i++)
1595 {
1596 for (uint8_t j = 0; j < MOD_ROWS; j++)
1597 {
1598 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1599
1600 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1601 continue;
1602
1603 if (noteSrc->period)
1604 {
1605 // period -> note
1606 for (k = 0; k < 36; k++)
1607 {
1608 if (noteSrc->period >= periodTable[k])
1609 break;
1610 }
1611
1612 noteDeleted = false;
1613 if (--k < 0)
1614 {
1615 k = 0;
1616
1617 if (config.transDel)
1618 {
1619 noteSrc->period = 0;
1620 noteSrc->sample = 0;
1621
1622 noteDeleted = true;
1623 }
1624 }
1625
1626 if (!noteDeleted)
1627 noteSrc->period = periodTable[k];
1628 }
1629 }
1630 }
1631
1632 updateWindowTitle(MOD_IS_MODIFIED);
1633 ui.updatePatternData = true;
1634 }
1635
pattOctaUp(bool sampleAllFlag)1636 void pattOctaUp(bool sampleAllFlag)
1637 {
1638 bool noteDeleted;
1639 uint8_t k;
1640 note_t *noteSrc;
1641
1642 saveUndo();
1643 for (uint8_t i = 0; i < AMIGA_VOICES; i++)
1644 {
1645 for (uint8_t j = 0; j < MOD_ROWS; j++)
1646 {
1647 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1648
1649 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1650 continue;
1651
1652 if (noteSrc->period)
1653 {
1654 // period -> note
1655 for (k = 0; k < 36; k++)
1656 {
1657 if (noteSrc->period >= periodTable[k])
1658 break;
1659 }
1660
1661 noteDeleted = false;
1662 if (k+12 > 35 && config.transDel)
1663 {
1664 noteSrc->period = 0;
1665 noteSrc->sample = 0;
1666
1667 noteDeleted = true;
1668 }
1669
1670 if (k <= 23)
1671 k += 12;
1672
1673 if (!noteDeleted)
1674 noteSrc->period = periodTable[k];
1675 }
1676 }
1677 }
1678
1679 updateWindowTitle(MOD_IS_MODIFIED);
1680 ui.updatePatternData = true;
1681 }
1682
pattOctaDown(bool sampleAllFlag)1683 void pattOctaDown(bool sampleAllFlag)
1684 {
1685 bool noteDeleted;
1686 int8_t k;
1687 note_t *noteSrc;
1688
1689 saveUndo();
1690 for (uint8_t i = 0; i < AMIGA_VOICES; i++)
1691 {
1692 for (uint8_t j = 0; j < MOD_ROWS; j++)
1693 {
1694 noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
1695
1696 if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
1697 continue;
1698
1699 if (noteSrc->period)
1700 {
1701 // period -> note
1702 for (k = 0; k < 36; k++)
1703 {
1704 if (noteSrc->period >= periodTable[k])
1705 break;
1706 }
1707
1708 noteDeleted = false;
1709 if (k-12 < 0 && config.transDel)
1710 {
1711 noteSrc->period = 0;
1712 noteSrc->sample = 0;
1713
1714 noteDeleted = true;
1715 }
1716
1717 if (k >= 12)
1718 k -= 12;
1719
1720 if (!noteDeleted)
1721 noteSrc->period = periodTable[k];
1722 }
1723 }
1724 }
1725
1726 updateWindowTitle(MOD_IS_MODIFIED);
1727 ui.updatePatternData = true;
1728 }
1729
keyToNote(SDL_Scancode scancode)1730 int8_t keyToNote(SDL_Scancode scancode)
1731 {
1732 int8_t note;
1733 int32_t lookUpKey;
1734
1735 if (scancode < SDL_SCANCODE_B || scancode > SDL_SCANCODE_SLASH)
1736 return -1; // not a note key
1737
1738 lookUpKey = (int32_t)scancode - SDL_SCANCODE_B;
1739 if (lookUpKey < 0 || lookUpKey >= 52)
1740 return -1; // just in case
1741
1742 if (editor.keyOctave == OCTAVE_LOW)
1743 note = scancode2NoteLo[lookUpKey];
1744 else
1745 note = scancode2NoteHi[lookUpKey];
1746
1747 return note;
1748 }
1749