1 /*
2 * tracker/ModuleEditor.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 #include <new>
24 #include "ModuleEditor.h"
25 #include "PatternEditor.h"
26 #include "SampleEditor.h"
27 #include "EnvelopeEditor.h"
28 #include "ModuleServices.h"
29 #include "PlayerCriticalSection.h"
30 #include "TrackerConfig.h"
31 #include "PPSystem.h"
32
33 static const char validCharacters[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_!.";
34
35 #ifndef TRUE
36 #define TRUE 1
37 #endif
38
39 #ifndef FALSE
40 #define FALSE 0
41 #endif
42
43 // convert string
convertStr(SYSCHAR * buffer,char * src)44 static mp_sint32 convertStr(SYSCHAR* buffer, char* src)
45 {
46 mp_sint32 j = 0;
47 for (mp_sint32 i = 0; i < MP_MAXTEXT; i++)
48 {
49 if (src[i] == '\0')
50 break;
51
52 bool found = false;
53 for (mp_sint32 k = 0; k < (signed)(sizeof(validCharacters)/sizeof(char))-1; k++)
54 if (src[i] == validCharacters[k])
55 {
56 found = true;
57 break;
58 }
59
60 if (found)
61 buffer[j++] = src[i];
62 }
63
64 buffer[j] = '\0';
65 return j;
66 }
67
68 class ChangesListener : public EditorBase::EditorNotificationListener
69 {
70 private:
editorNotification(EditorBase * sender,EditorBase::EditorNotifications notification)71 virtual void editorNotification(EditorBase* sender, EditorBase::EditorNotifications notification)
72 {
73 switch (notification)
74 {
75 case EditorBase::NotificationChanges:
76 {
77 if (sender == moduleEditor.sampleEditor)
78 moduleEditor.finishSamples();
79 moduleEditor.setChanged();
80 break;
81 }
82
83 case EditorBase::NotificationPrepareCritical:
84 moduleEditor.enterCriticalSection();
85 break;
86
87 case EditorBase::NotificationUnprepareCritical:
88 moduleEditor.leaveCriticalSection();
89 break;
90 default:
91 break;
92 }
93 }
94
95 ModuleEditor& moduleEditor;
96
97 public:
ChangesListener(ModuleEditor & moduleEditor)98 ChangesListener(ModuleEditor& moduleEditor) :
99 moduleEditor(moduleEditor)
100 {
101 }
102 };
103
ModuleEditor()104 ModuleEditor::ModuleEditor() :
105 module(NULL),
106 patternEditor(NULL),
107 sampleEditor(NULL),
108 envelopeEditor(NULL),
109 playerCriticalSection(NULL),
110 changed(false),
111 eSaveType(ModSaveTypeXM),
112 lastRequestedPatternIndex(0),
113 currentOrderIndex(0),
114 currentPatternIndex(0),
115 currentInstrumentIndex(0),
116 currentSampleIndex(0),
117 enumerationIndex(-1)
118 {
119 instruments = new TEditorInstrument[MAX_INSTRUMENTS];
120
121 moduleFileName = TrackerConfig::untitledSong;
122
123 // no extension here
124 adjustExtension(false);
125
126 module = new XModule();
127
128 createNewSong();
129
130 changesListener = new ChangesListener(*this);
131
132 // create pattern editor
133 patternEditor = new PatternEditor();
134 patternEditor->addNotificationListener(changesListener);
135 reloadCurrentPattern();
136
137 // create sample editor
138 sampleEditor = new SampleEditor();
139 sampleEditor->addNotificationListener(changesListener);
140 reloadSample(0, 0);
141
142 // create envelope editor
143 envelopeEditor = new EnvelopeEditor();
144 envelopeEditor->addNotificationListener(changesListener);
145 envelopeEditor->attachEnvelope(NULL, module);
146
147 moduleServices = new ModuleServices(*module);
148
149 currentCursorPosition.row = currentCursorPosition.channel = currentCursorPosition.inner = 0;
150 }
151
~ModuleEditor()152 ModuleEditor::~ModuleEditor()
153 {
154 delete moduleServices;
155 delete sampleEditor;
156 delete patternEditor;
157 delete envelopeEditor;
158 // must be deleted AFTER the editors
159 delete changesListener;
160 delete module;
161
162 delete[] instruments;
163 }
164
getModuleFileNameFull(ModSaveTypes extension)165 PPSystemString ModuleEditor::getModuleFileNameFull(ModSaveTypes extension/* = ModSaveTypeDefault*/)
166 {
167 PPSystemString s = moduleFileName;
168
169 PPSystemString s2;
170 if (extension != ModSaveTypeDefault)
171 {
172 ModSaveTypes eOldType = eSaveType;
173 eSaveType = extension;
174 adjustExtension();
175 eSaveType = eOldType;
176 }
177 s2 = moduleFileName;
178 moduleFileName = s;
179 return s2;
180 }
181
getModuleFileName(ModSaveTypes extension)182 PPSystemString ModuleEditor::getModuleFileName(ModSaveTypes extension/* = ModSaveTypeDefault*/)
183 {
184 PPSystemString s = getModuleFileNameFull(extension);
185
186 return s.stripPath();
187 }
188
reloadCurrentPattern()189 void ModuleEditor::reloadCurrentPattern()
190 {
191 TXMPattern* pattern = patternEditor->getPattern();
192
193 if (pattern &&
194 pattern->patternData &&
195 pattern->channum == TrackerConfig::numPlayerChannels &&
196 module &&
197 pattern == &module->phead[getCurrentPatternIndex()])
198 return;
199
200 patternEditor->attachPattern(getPattern(getCurrentPatternIndex()), module);
201 }
202
reloadSample(mp_sint32 insIndex,mp_sint32 smpIndex)203 void ModuleEditor::reloadSample(mp_sint32 insIndex, mp_sint32 smpIndex)
204 {
205 sampleEditor->attachSample(getSampleInfo(insIndex, smpIndex), module);
206 }
207
reloadEnvelope(mp_sint32 insIndex,mp_sint32 smpIndex,mp_sint32 type)208 void ModuleEditor::reloadEnvelope(mp_sint32 insIndex, mp_sint32 smpIndex, mp_sint32 type)
209 {
210 envelopeEditor->attachEnvelope(getEnvelope(insIndex, smpIndex, type), module);
211 }
212
enterCriticalSection()213 void ModuleEditor::enterCriticalSection()
214 {
215 if (playerCriticalSection)
216 playerCriticalSection->enter();
217 }
218
leaveCriticalSection()219 void ModuleEditor::leaveCriticalSection()
220 {
221 if (playerCriticalSection)
222 playerCriticalSection->leave();
223 }
224
adjustExtension(bool hasExtension)225 void ModuleEditor::adjustExtension(bool hasExtension/* = true*/)
226 {
227 if (hasExtension)
228 moduleFileName = moduleFileName.stripExtension();
229
230 switch (eSaveType)
231 {
232 case ModSaveTypeXM:
233 moduleFileName.append(".xm");
234 break;
235
236 case ModSaveTypeMOD:
237 moduleFileName.append(".mod");
238 break;
239
240 default:
241 ASSERT(false);
242 }
243 }
244
convertInstrument(mp_sint32 i)245 void ModuleEditor::convertInstrument(mp_sint32 i)
246 {
247 mp_sint32 j,k;
248
249 TXMInstrument* ins = &module->instr[i];
250 instruments[i].instrument = ins;
251 instruments[i].numUsedSamples = 16;
252
253 for (j = 0; j < 16; j++)
254 instruments[i].usedSamples[j] = i*16+j;
255
256 // build FT2 compatible note->sample LUT
257 for (j = 0; j < MAX_NOTE; j++)
258 {
259 mp_sword s = ins->snum[j];
260
261 // empty entry
262 if (s == -1)
263 {
264 instruments[i].nbu[j] = /*255*/0;
265 ins->snum[j] = i*16;
266 continue;
267 }
268
269 bool found = false;
270 for (k = 0; k < 16; k++)
271 if (i*16+k == s)
272 {
273 instruments[i].nbu[j] = k;
274 found = true;
275 break;
276 }
277
278 if (!found)
279 {
280 instruments[i].nbu[j] = /*255*/0;
281 ins->snum[j] = i*16;
282 //exit(1);
283 }
284 }
285
286 if (ins->samp)
287 {
288 // take default envelope from first sample in instrument
289 mp_sint32 venvIndex = module->smp[i*16].venvnum - 1;
290 if (venvIndex == -1)
291 {
292 for (mp_sint32 e = 0; e < module->header.volenvnum; e++)
293 {
294 bool used = false;
295 for (mp_sint32 s = 0; s < module->header.smpnum; s++)
296 {
297 if (module->smp[s].venvnum - 1 == e)
298 {
299 used = true;
300 break;
301 }
302 }
303
304 if (!used)
305 {
306 venvIndex = e;
307 break;
308 }
309 }
310 }
311
312 if (venvIndex == -1)
313 {
314 TEnvelope venv;
315 memset(&venv, 0, sizeof(venv));
316 venv.type = 0;
317 venv.num = 2;
318 venv.loops = 0;
319 venv.loope = 1;
320 venv.sustain = 0;
321 venv.env[0][0] = 0;
322 venv.env[0][1] = 256;
323 venv.env[1][0] = 32;
324 venv.env[1][1] = 256;
325 module->addVolumeEnvelope(venv);
326 venvIndex = module->numVEnvs - 1;
327 module->header.volenvnum = module->numVEnvs;
328 }
329
330 instruments[i].volumeEnvelope = venvIndex;
331
332 // same for panning envelope index
333 mp_sint32 penvIndex = module->smp[i*16].penvnum - 1;
334 if (penvIndex == -1)
335 {
336 for (mp_sint32 e = 0; e < module->header.panenvnum; e++)
337 {
338 bool used = false;
339 for (mp_sint32 s = 0; s < module->header.smpnum; s++)
340 {
341 if (module->smp[s].penvnum - 1 == e)
342 {
343 used = true;
344 break;
345 }
346 }
347
348 if (!used)
349 {
350 penvIndex = e;
351 break;
352 }
353 }
354 }
355
356 if (penvIndex == -1)
357 {
358 TEnvelope penv;
359 memset(&penv, 0, sizeof(penv));
360 penv.type=0;
361 penv.num=2;
362 penv.loops=0;
363 penv.loope=1;
364 penv.sustain = 0;
365 penv.env[0][0]=0;
366 penv.env[0][1]=128;
367 penv.env[1][0]=32;
368 penv.env[1][1]=128;
369 module->addPanningEnvelope(penv);
370 penvIndex = module->numPEnvs - 1;
371 module->header.panenvnum = module->numPEnvs;
372 }
373
374 instruments[i].panningEnvelope = penvIndex;
375
376 mp_sint32 s = instruments[i].usedSamples[0];
377
378 // take all fadeout/autovibrato settings from first sample in instrument
379 instruments[i].volfade = module->smp[s].volfade >> 1;
380 instruments[i].vibtype = module->smp[s].vibtype;
381 instruments[i].vibrate = module->smp[s].vibrate;
382 instruments[i].vibdepth = module->smp[s].vibdepth >> 1;
383 instruments[i].vibsweep = module->smp[s].vibsweep;
384 }
385 else
386 {
387
388 for (j = 0; j < MAX_NOTE; j++)
389 ins->snum[j] = i*16;
390
391 mp_sint32 e;
392 mp_sint32 venvIndex = - 1;
393
394 for (e = 0; e < module->header.volenvnum; e++)
395 {
396 bool used = false;
397 for (mp_sint32 s = 0; s < module->header.smpnum; s++)
398 {
399 if (module->smp[s].venvnum - 1 == e)
400 {
401 used = true;
402 break;
403 }
404 }
405
406 if (!used)
407 {
408 venvIndex = e;
409 break;
410 }
411 }
412
413 if (venvIndex == -1)
414 {
415 TEnvelope venv;
416 memset(&venv, 0, sizeof(venv));
417 venv.type=0;
418 venv.num=2;
419 venv.loops=0;
420 venv.loope=1;
421 venv.sustain = 0;
422 venv.env[0][0]=0;
423 venv.env[0][1]=256;
424 venv.env[1][0]=32;
425 venv.env[1][1]=256;
426 module->addVolumeEnvelope(venv);
427 venvIndex = module->numVEnvs - 1;
428 module->header.volenvnum = module->numVEnvs;
429 }
430
431 instruments[i].volumeEnvelope = venvIndex;
432
433 mp_sint32 penvIndex = - 1;
434
435 for (e = 0; e < module->header.panenvnum; e++)
436 {
437 bool used = false;
438 for (mp_sint32 s = 0; s < module->header.smpnum; s++)
439 {
440 if (module->smp[s].penvnum - 1 == e)
441 {
442 used = true;
443 break;
444 }
445 }
446
447 if (!used)
448 {
449 penvIndex = e;
450 break;
451 }
452 }
453
454 if (penvIndex == -1)
455 {
456 TEnvelope penv;
457 memset(&penv, 0, sizeof(penv));
458 penv.type=0;
459 penv.num=2;
460 penv.loops=0;
461 penv.loope=1;
462 penv.sustain = 0;
463 penv.env[0][0]=0;
464 penv.env[0][1]=128;
465 penv.env[1][0]=32;
466 penv.env[1][1]=128;
467 module->addPanningEnvelope(penv);
468 penvIndex = module->numPEnvs - 1;
469 module->header.panenvnum = module->numPEnvs;
470 }
471
472 instruments[i].panningEnvelope = penvIndex;
473
474 //-----------------------------------------------------------
475 // this will only work if there are 16 sample per instrument
476 //-----------------------------------------------------------
477 for (j = 0; j < 16; j++)
478 {
479 module->smp[i*16+j].venvnum = venvIndex + 1;
480 module->smp[i*16+j].penvnum = penvIndex + 1;
481 // default fade out to cut
482 module->smp[i*16+j].volfade = 0xFFFF;
483 }
484
485 instruments[i].volfade = 0xFFFF >> 1;
486 instruments[i].vibtype = 0;
487 instruments[i].vibrate = 0;
488 instruments[i].vibdepth = 0;
489 instruments[i].vibsweep = 0;
490 }
491
492
493 for (j = 0; j < 16; j++)
494 {
495 if (!module->smp[i*16+j].sample)
496 {
497 module->smp[i*16+j].vol = 0xFF;
498 module->smp[i*16+j].pan = 0x80;
499 }
500 }
501 }
502
buildInstrumentTable()503 void ModuleEditor::buildInstrumentTable()
504 {
505 mp_sint32 i,j;
506
507 for (i = 0; i < MAX_INSTRUMENTS; i++)
508 {
509 instruments[i].instrument = NULL;
510 instruments[i].numUsedSamples = 0;
511 for (j = 0; j < 16; j++)
512 instruments[i].usedSamples[j] = -1;
513 instruments[i].volumeEnvelope = instruments[i].panningEnvelope = -1;
514
515 memset(instruments[i].nbu, 0, MAX_NOTE);
516 }
517
518 for (i = 0; i < module->header.insnum; i++)
519 {
520 convertInstrument(i);
521 }
522
523 validateInstruments();
524 }
525
validateInstruments()526 void ModuleEditor::validateInstruments()
527 {
528 for (mp_sint32 i = 0; i < module->header.insnum; i++)
529 {
530 mp_sint32 lastUsedInstrument = -1;
531 for (mp_sint32 j = 15; j >= 0; j--)
532 {
533 mp_sint32 s = instruments[i].usedSamples[j];
534 if (module->smp[s].sample)
535 {
536 lastUsedInstrument = j;
537 }
538
539 module->smp[s].flags = 3;
540 }
541
542 instruments[i].instrument->samp = 16;
543 }
544 }
545
allocatePattern(TXMPattern * pattern)546 bool ModuleEditor::allocatePattern(TXMPattern* pattern)
547 {
548 // create empty pattern
549 pattern->channum = (mp_ubyte)/*numChannels*/TrackerConfig::numPlayerChannels;
550 pattern->rows = 64;
551 // create XM style pattern, two effects
552 pattern->effnum = 2;
553
554 mp_sint32 slotSize = pattern->effnum * 2 + 2;
555
556 mp_sint32 patternSize = slotSize * pattern->channum * pattern->rows;
557
558 pattern->patternData = new mp_ubyte[patternSize];
559
560 if (pattern->patternData == NULL)
561 return false;
562
563 memset(pattern->patternData, 0, patternSize);
564 return true;
565 }
566
createEmptySong(bool clearPatterns,bool clearInstruments,mp_sint32 numChannels)567 void ModuleEditor::createEmptySong(bool clearPatterns/* = true*/, bool clearInstruments/* = true*/, mp_sint32 numChannels/* = 8*/)
568 {
569 if (module)
570 {
571 enterCriticalSection();
572
573 setCurrentOrderIndex(0);
574 setCurrentPatternIndex(0);
575
576 module->createEmptySong(clearPatterns, clearInstruments, numChannels);
577
578 if (clearPatterns && clearInstruments)
579 {
580 changed = false;
581
582 eSaveType = ModSaveTypeXM;
583
584 moduleFileName = TrackerConfig::untitledSong;
585
586 // no extension
587 adjustExtension(false);
588 }
589 else
590 {
591 changed = true;
592 }
593
594 buildInstrumentTable();
595
596 lastRequestedPatternIndex = 0;
597
598 leaveCriticalSection();
599 }
600 }
601
createNewSong(mp_uword numChannels)602 bool ModuleEditor::createNewSong(mp_uword numChannels/*= 8*/)
603 {
604 module->createEmptySong(true, true, numChannels);
605
606 changed = false;
607
608 eSaveType = ModSaveTypeXM;
609
610 moduleFileName = TrackerConfig::untitledSong;
611
612 // no extension
613 adjustExtension(false);
614
615 buildInstrumentTable();
616
617 lastRequestedPatternIndex = 0;
618
619 return true;
620 }
621
isEmpty() const622 bool ModuleEditor::isEmpty() const
623 {
624 mp_sint32 patNum = module->header.patnum;
625 if (patNum != 1)
626 return false;
627
628 TXMPattern* pattern = &module->phead[0];
629
630 if (pattern->patternData != NULL)
631 {
632 mp_sint32 slotSize = pattern->effnum * 2 + 2;
633
634 mp_sint32 patternSize = slotSize * pattern->channum * pattern->rows;
635
636 bool empty = true;
637 for (mp_sint32 j = 0; j < patternSize; j++)
638 if (pattern->patternData[j])
639 {
640 empty = false;
641 break;
642 }
643
644 if (!empty)
645 return false;
646 }
647
648 // step two, find last used instrument
649 mp_sint32 insNum = module->getNumUsedInstruments();
650 if (insNum)
651 return false;
652
653 char temp[MAX_TITLETEXT+1];
654 memset(temp, 0, sizeof(temp));
655 getTitle(temp, MAX_TITLETEXT);
656
657 if (strlen(temp))
658 return true;
659
660 return true;
661 }
662
openSong(const SYSCHAR * fileName,const SYSCHAR * preferredFileName)663 bool ModuleEditor::openSong(const SYSCHAR* fileName, const SYSCHAR* preferredFileName/* = NULL*/)
664 {
665 if (!XMFile::exists(fileName))
666 return false;
667
668 mp_sint32 nRes = module->loadModule(fileName);
669
670 // unknown format
671 if (nRes == MP_UNKNOWN_FORMAT)
672 {
673 return false;
674 }
675
676 bool res = (nRes == MP_OK);
677
678 XModule::ModuleTypes type = XModule::ModuleType_NONE;
679
680 if (module->getType() != XModule::ModuleType_XM)
681 {
682 type = module->getType();
683
684 mp_ubyte oneShotFlags[MAX_INSTRUMENTS];
685 // save flags for one shot PT style looping, it will be stripped out
686 // when exporting to XM
687 if (type == XModule::ModuleType_MOD)
688 {
689 memset(oneShotFlags, 0, sizeof(oneShotFlags));
690 for (mp_sint32 i = 0; i < module->header.insnum; i++)
691 {
692 mp_sint32 snum = module->instr[i].snum[0];
693 if (snum >= 0)
694 {
695 oneShotFlags[i] = module->smp[snum].type & 32;
696 }
697 }
698 }
699
700 PPSystemString tempFile(getTempFilename());
701
702 try
703 {
704 res = module->saveExtendedModule(tempFile) == MP_OK;
705 if(!res)
706 return res;
707
708 res = module->loadModule(tempFile) == MP_OK;
709 } catch (const std::bad_alloc &) {
710 return false;
711 }
712
713 // restore one shot looping flag
714 if (type == XModule::ModuleType_MOD)
715 {
716 for (mp_sint32 i = 0; i < module->header.insnum; i++)
717 {
718 mp_sint32 snum = module->instr[i].snum[0];
719 if (snum >= 0)
720 {
721 if (oneShotFlags[i])
722 module->smp[snum].type |= 32;
723 }
724 }
725 }
726
727 XMFile::remove(tempFile);
728 }
729
730 if (module->header.channum > TrackerConfig::numPlayerChannels)
731 res = false;
732
733 lastRequestedPatternIndex = 0;
734
735 if (res)
736 {
737 changed = false;
738
739 buildInstrumentTable();
740
741 // expand patterns to 32 channels width
742 for (mp_sint32 i = 0; i < module->header.patnum; i++)
743 getPattern(i);
744
745 PPSystemString strFileName = preferredFileName ? preferredFileName : fileName;
746
747 moduleFileName = strFileName.stripExtension();
748
749 if (type == XModule::ModuleType_MOD)
750 eSaveType = ModSaveTypeMOD;
751 else
752 eSaveType = ModSaveTypeXM;
753
754 // no extension
755 adjustExtension(false);
756 }
757 else
758 {
759 createNewSong();
760 }
761
762 cleanUnusedPatterns();
763
764 return res;
765 }
766
saveSong(const SYSCHAR * fileName,ModSaveTypes saveType)767 bool ModuleEditor::saveSong(const SYSCHAR* fileName, ModSaveTypes saveType/* = eXM*/)
768 {
769 // too risky
770 //cleanUnusedPatterns();
771
772 bool res = false;
773
774 switch (saveType)
775 {
776 case ModSaveTypeDefault:
777 case ModSaveTypeXM:
778 res = module->saveExtendedModule(fileName) == 0;
779 break;
780
781 case ModSaveTypeMOD:
782 res = module->saveProtrackerModule(fileName) == 0;
783 break;
784 }
785
786 eSaveType = saveType;
787
788 moduleFileName = fileName;
789
790 // has extension
791 adjustExtension();
792
793 changed = false;
794
795 return res;
796 }
797
saveBackup(const SYSCHAR * fileName)798 mp_sint32 ModuleEditor::saveBackup(const SYSCHAR* fileName)
799 {
800 return module->saveExtendedModule(fileName);
801 }
802
803
increaseSongLength()804 void ModuleEditor::increaseSongLength()
805 {
806 if (module->header.ordnum < 255)
807 {
808 module->header.ordnum++;
809 changed = true;
810 }
811 }
812
decreaseSongLength()813 void ModuleEditor::decreaseSongLength()
814 {
815 if (module->header.ordnum > 1)
816 {
817 module->header.ordnum--;
818 changed = true;
819 }
820 }
821
increaseRepeatPos()822 void ModuleEditor::increaseRepeatPos()
823 {
824 mp_uword old = module->header.restart;
825
826 if (module->header.restart < 255)
827 module->header.restart++;
828
829 if (module->header.restart >= module->header.ordnum)
830 module->header.restart = module->header.ordnum - 1;
831
832 if (old != module->header.restart)
833 changed = true;
834 }
835
decreaseRepeatPos()836 void ModuleEditor::decreaseRepeatPos()
837 {
838 if (module->header.restart > 0)
839 {
840 module->header.restart--;
841 changed = true;
842 }
843 }
844
insertNewOrderPosition(mp_sint32 index)845 bool ModuleEditor::insertNewOrderPosition(mp_sint32 index)
846 {
847
848 if (module->header.ordnum >= 255)
849 return false;
850
851 mp_ubyte temp[256];
852
853 mp_sint32 i;
854
855 for (i = 0; i <= index; i++)
856 temp[i] = module->header.ord[i];
857
858 temp[index+1] = module->header.ord[index];
859
860 for (i = index+2; i <= module->header.ordnum; i++)
861 temp[i] = module->header.ord[i-1];
862
863 module->header.ordnum++;
864
865 memcpy(module->header.ord, temp, module->header.ordnum);
866
867 changed = true;
868
869 return true;
870 }
871
deleteOrderPosition(mp_sint32 index)872 void ModuleEditor::deleteOrderPosition(mp_sint32 index)
873 {
874 if (index < module->header.ordnum && module->header.ordnum > 1)
875 {
876 for (mp_sint32 i = index; i < module->header.ordnum - 1; i++)
877 module->header.ord[i] = module->header.ord[i+1];
878
879 module->header.ordnum--;
880
881 changed = true;
882 }
883 }
884
seqCurrentOrderPosition(mp_sint32 index,bool clone)885 bool ModuleEditor::seqCurrentOrderPosition(mp_sint32 index, bool clone/* = false*/)
886 {
887 mp_sint32 i;
888
889 if (module->header.ordnum >= 255)
890 return false;
891
892 pp_int32 srcPatternIndex = module->header.ord[index];
893
894 mp_sint32 highestPattern = module->header.ord[0];
895 for (i = 1; i < module->header.ordnum; i++)
896 if (module->header.ord[i] > highestPattern)
897 highestPattern = module->header.ord[i];
898
899 mp_ubyte temp[256];
900
901 for (i = 0; i <= index; i++)
902 temp[i] = module->header.ord[i];
903
904 temp[index+1] = /*module->header.ord[index] + 1*/highestPattern+1;
905
906 pp_int32 dstPatternIndex = highestPattern+1;
907
908 for (i = index+2; i <= module->header.ordnum; i++)
909 temp[i] = module->header.ord[i-1];
910
911 module->header.ordnum++;
912
913 memcpy(module->header.ord, temp, module->header.ordnum);
914
915 if (clone)
916 {
917 // now clone pattern
918 module->phead[dstPatternIndex] = module->phead[srcPatternIndex];
919 }
920
921 changed = true;
922
923 return true;
924 }
925
getOrderPosition(mp_sint32 index) const926 mp_sint32 ModuleEditor::getOrderPosition(mp_sint32 index) const
927 {
928 return module->header.ord[index];
929 }
930
increaseOrderPosition(mp_sint32 index)931 void ModuleEditor::increaseOrderPosition(mp_sint32 index)
932 {
933 if (module->header.ord[index] < 255)
934 {
935 module->header.ord[index]++;
936
937 changed = true;
938 }
939 }
940
decreaseOrderPosition(mp_sint32 index)941 void ModuleEditor::decreaseOrderPosition(mp_sint32 index)
942 {
943 if (module->header.ord[index] > 0)
944 {
945 module->header.ord[index]--;
946
947 changed = true;
948 }
949 }
950
isEditingOrderPosition(mp_sint32 index) const951 bool ModuleEditor::isEditingOrderPosition(mp_sint32 index) const
952 {
953 if (index < 0 || index >= module->header.ordnum)
954 return false;
955
956 return patternEditor->getPattern() == &module->phead[module->header.ord[index]];
957 }
958
cleanUnusedPatterns()959 void ModuleEditor::cleanUnusedPatterns()
960 {
961 if (!module)
962 return;
963
964 for (mp_sint32 i = module->header.patnum - 1; i > lastRequestedPatternIndex; i--)
965 {
966 TXMPattern* pattern = &module->phead[i];
967
968 if (pattern->patternData == NULL)
969 continue;
970
971 mp_sint32 slotSize = pattern->effnum * 2 + 2;
972
973 mp_sint32 patternSize = slotSize * pattern->channum * pattern->rows;
974
975 bool empty = true;
976 for (mp_sint32 j = 0; j < patternSize; j++)
977 if (pattern->patternData[j])
978 {
979 empty = false;
980 break;
981 }
982
983 if (empty)
984 {
985 bool found = false;
986 for (mp_sint32 j = 0; j < module->header.ordnum; j++)
987 if (module->header.ord[j] == i)
988 {
989 found = true;
990 break;
991 }
992
993 if (found)
994 break;
995
996 delete[] pattern->patternData;
997 memset(pattern, 0, sizeof(TXMPattern));
998 module->header.patnum = i;
999 }
1000 else
1001 {
1002 break;
1003 }
1004 }
1005 }
1006
1007 ///////////////////////////////////////////////////////////////////////////
1008 // Whenever a pattern is requested we will return a pattern that is
1009 // 32 channels wide, this makes adding/subtracting channels easier
1010 // without losing data in that channel
1011 // When another pattern pattern is selected we will discard unused channels
1012 ///////////////////////////////////////////////////////////////////////////
getPattern(mp_sint32 index,bool cleanUnusedPatterns)1013 TXMPattern* ModuleEditor::getPattern(mp_sint32 index, bool cleanUnusedPatterns/* = true*/)
1014 {
1015 lastRequestedPatternIndex = index;
1016
1017 // handle with care, this might throw away patterns while the player
1018 // is using them
1019 if (cleanUnusedPatterns)
1020 this->cleanUnusedPatterns();
1021
1022 // get requested pattern, allocate one if it's empty
1023 TXMPattern* pattern = &module->phead[index];
1024
1025 if (pattern->patternData == NULL)
1026 {
1027 bool res = allocatePattern(pattern);
1028
1029 if (!res)
1030 return NULL;
1031 }
1032
1033 // if the number of channels in this pattern is
1034 // smaller then 32 we resize to 32 channels
1035 if (pattern->channum < TrackerConfig::numPlayerChannels)
1036 {
1037 mp_sint32 slotSize = pattern->effnum * 2 + 2;
1038
1039 mp_sint32 patternSize = slotSize * TrackerConfig::numPlayerChannels * pattern->rows;
1040
1041 mp_ubyte* newPatternData = new mp_ubyte[patternSize];
1042
1043 memset(newPatternData, 0, patternSize);
1044
1045 for (mp_sint32 i = 0; i < pattern->rows; i++)
1046 {
1047 mp_sint32 srcOffset = i * slotSize * pattern->channum;
1048 mp_sint32 dstOffset = i * slotSize * TrackerConfig::numPlayerChannels;
1049 for (mp_sint32 j = 0; j < slotSize * pattern->channum; j++)
1050 newPatternData[dstOffset++] = pattern->patternData[srcOffset++];
1051 }
1052
1053 delete[] pattern->patternData;
1054
1055 pattern->patternData = newPatternData;
1056
1057 pattern->channum = (mp_ubyte)TrackerConfig::numPlayerChannels;
1058 }
1059
1060 // update number of patterns in module header if necessary
1061 if (module->header.patnum < index + 1)
1062 module->header.patnum = index + 1;
1063
1064 return pattern;
1065
1066 }
1067
1068 #if 0
1069 mp_sint32 ModuleEditor::allocateSample(mp_sint32 index)
1070 {
1071 if (index < 0)
1072 return -1;
1073
1074 if (index >= module->header.insnum)
1075 return -1;
1076
1077 // sorry, XM can only handle 16 samples per instrument
1078 if (instruments[index].numUsedSamples >= 16)
1079 return -1;
1080
1081
1082 // look if we can find an unused sample
1083 mp_sint32 s = -1;
1084
1085 for (mp_sint32 i = 0; i < module->header.smpnum; i++)
1086 {
1087
1088 bool used = false;
1089 //if (module->smp[i].sample == NULL && module->smp[i].samplen == 0)
1090 //{
1091
1092 for (mp_sint32 j = 0; j < module->header.insnum; j++)
1093 {
1094 for (mp_sint32 k = 0; k < instruments[j].numUsedSamples; k++)
1095 {
1096 if (instruments[j].usedSamples[k] == i)
1097 {
1098 used = true;
1099 break;
1100 }
1101 }
1102
1103 if (used)
1104 break;
1105
1106 }
1107
1108 //}
1109 //else
1110 // used = true;
1111
1112 if (!used)
1113 {
1114 s = i;
1115 break;
1116 }
1117
1118 }
1119
1120 if (s == -1)
1121 {
1122 if (module->header.smpnum >= 254)
1123 return -2;
1124
1125 s = module->header.smpnum++;
1126 }
1127
1128 if (module->smp[s].sample)
1129 {
1130 module->freeSampleMem((mp_ubyte*)module->smp[s].sample);
1131 module->smp[s].sample = NULL;
1132 }
1133
1134 if (!instruments[index].numUsedSamples)
1135 {
1136 for (mp_sint32 i = 0; i < MAX_NOTE; i++)
1137 {
1138 module->instr[index].snum[i] = s;
1139 instruments[index].nbu[i] = 0;
1140 }
1141 }
1142
1143 strcpy((char*)module->smp[s].name,"<new sample>");
1144 module->smp[s].venvnum = instruments[index].volumeEnvelope + 1;
1145 module->smp[s].penvnum = instruments[index].panningEnvelope + 1;
1146
1147 instruments[index].usedSamples[instruments[index].numUsedSamples++] = s;
1148
1149 return 0;
1150
1151 }
1152 #endif
1153
finishSamples()1154 void ModuleEditor::finishSamples()
1155 {
1156 module->postProcessSamples();
1157 }
1158
allocateInstrument()1159 mp_sint32 ModuleEditor::allocateInstrument()
1160 {
1161 if (module->header.insnum >= 255)
1162 return -1;
1163
1164 enterCriticalSection();
1165
1166 mp_sint32 i = module->header.insnum++;
1167
1168 module->header.smpnum+=16;
1169
1170 convertInstrument(i);
1171
1172 validateInstruments();
1173
1174 leaveCriticalSection();
1175
1176 changed = true;
1177
1178 return 0;
1179 }
1180
1181 // free sample
freeSample(mp_sint32 index)1182 void ModuleEditor::freeSample(mp_sint32 index)
1183 {
1184 return;
1185
1186 if (index < 0)
1187 return;
1188
1189 if (index >= module->header.insnum)
1190 return;
1191
1192 if (instruments[index].numUsedSamples)
1193 {
1194 instruments[index].usedSamples[--instruments[index].numUsedSamples] = -1;
1195
1196 mp_sint32 i;
1197
1198 mp_ubyte* nbu = instruments[index].nbu;
1199
1200 for (i = 0; i < MAX_NOTE; i++)
1201 if (nbu[i] == instruments[index].numUsedSamples)
1202 nbu[i] = 255;
1203
1204 for (i = 0; i < MAX_NOTE; i++)
1205 {
1206 if (nbu[i] != 255)
1207 module->instr[index].snum[i] = instruments[index].usedSamples[nbu[i]];
1208 else
1209 module->instr[index].snum[i] = 255;
1210 }
1211
1212 }
1213
1214 }
1215
clearSample(mp_sint32 smpIndex)1216 void ModuleEditor::clearSample(mp_sint32 smpIndex)
1217 {
1218 if (smpIndex >= 0 && smpIndex < MP_MAXSAMPLES)
1219 {
1220 TXMSample* dst = &module->smp[smpIndex];
1221
1222 module->freeSampleMem((mp_ubyte*)dst->sample);
1223 dst->sample = NULL;
1224 dst->samplen = 0;
1225 dst->loopstart = 0;
1226 dst->looplen = 0;
1227
1228 changed = true;
1229 }
1230 }
1231
clearSample(mp_sint32 insIndex,mp_sint32 smpIndex)1232 void ModuleEditor::clearSample(mp_sint32 insIndex, mp_sint32 smpIndex)
1233 {
1234 if (insIndex < module->header.insnum && smpIndex < 16)
1235 {
1236 mp_sint32 s = instruments[insIndex].usedSamples[smpIndex];
1237
1238 clearSample(s);
1239 }
1240 }
1241
loadSample(const SYSCHAR * fileName,mp_sint32 insIndex,mp_sint32 smpIndex,mp_sint32 channelIndex,const SYSCHAR * preferredFileName)1242 bool ModuleEditor::loadSample(const SYSCHAR* fileName,
1243 mp_sint32 insIndex,
1244 mp_sint32 smpIndex,
1245 mp_sint32 channelIndex,
1246 const SYSCHAR* preferredFileName/* = NULL*/)
1247 {
1248 PPSystemString sysPreferredName(preferredFileName ? preferredFileName : fileName);
1249 sysPreferredName = sysPreferredName.stripPath();
1250 char* preferredNameASCIIZ = sysPreferredName.toASCIIZ();
1251 PPString preferredName(preferredNameASCIIZ);
1252 delete[] preferredNameASCIIZ;
1253
1254 SampleLoaderGeneric sampleLoader(fileName, *module);
1255 sampleLoader.setPreferredDefaultName(preferredName);
1256
1257 if (insIndex < module->header.insnum && smpIndex < 16)
1258 {
1259 enterCriticalSection();
1260
1261 bool res = sampleLoader.loadSample(instruments[insIndex].usedSamples[smpIndex], channelIndex) == 0;
1262
1263 if (res)
1264 {
1265 TXMSample* dst = &module->smp[instruments[insIndex].usedSamples[smpIndex]];
1266
1267 ASSERT(dst);
1268
1269 // default values first
1270 dst->flags = 3;
1271 dst->venvnum = instruments[insIndex].volumeEnvelope+1;
1272 dst->penvnum = instruments[insIndex].panningEnvelope+1;
1273 dst->fenvnum = dst->vibenvnum = 0;
1274
1275 dst->vibtype = instruments[insIndex].vibtype;
1276 dst->vibsweep = instruments[insIndex].vibsweep;
1277 dst->vibdepth = instruments[insIndex].vibdepth << 1;
1278 dst->vibrate = instruments[insIndex].vibrate;
1279 dst->volfade = instruments[insIndex].volfade << 1;
1280
1281 finishSamples();
1282
1283 validateInstruments();
1284
1285 changed = true;
1286 }
1287
1288 leaveCriticalSection();
1289
1290 return res;
1291 }
1292
1293 return false;
1294 }
1295
getNumSampleChannels(const SYSCHAR * fileName)1296 mp_sint32 ModuleEditor::getNumSampleChannels(const SYSCHAR* fileName)
1297 {
1298 SampleLoaderGeneric sampleLoader(fileName, *module);
1299 return sampleLoader.getNumChannels();
1300 }
1301
1302 // get name of channel in sample as returned by sample loader
getNameOfSampleChannel(const SYSCHAR * fileName,mp_sint32 index)1303 const char* ModuleEditor::getNameOfSampleChannel(const SYSCHAR* fileName, mp_sint32 index)
1304 {
1305 SampleLoaderGeneric sampleLoader(fileName, *module);
1306 return sampleLoader.getChannelName(index);
1307 }
1308
saveSample(const SYSCHAR * fileName,mp_sint32 insIndex,mp_sint32 smpIndex,SampleFormatTypes format)1309 bool ModuleEditor::saveSample(const SYSCHAR* fileName, mp_sint32 insIndex, mp_sint32 smpIndex, SampleFormatTypes format)
1310 {
1311 SampleLoaderGeneric sampleLoader(fileName, *module);
1312
1313 if (insIndex < module->header.insnum && smpIndex < 16)
1314 {
1315 bool res = false;
1316
1317 switch (format)
1318 {
1319 case SampleFormatTypeWAV:
1320 res = sampleLoader.saveSample(fileName, instruments[insIndex].usedSamples[smpIndex], SampleLoaderGeneric::OutputFiletypeWAV) == 0;
1321 break;
1322 case SampleFormatTypeIFF:
1323 res = sampleLoader.saveSample(fileName, instruments[insIndex].usedSamples[smpIndex], SampleLoaderGeneric::OutputFiletypeIFF) == 0;
1324 break;
1325 }
1326
1327 return res;
1328 }
1329
1330 return false;
1331 }
1332
getSampleFileName(mp_sint32 insIndex,mp_sint32 smpIndex)1333 const PPSystemString& ModuleEditor::getSampleFileName(mp_sint32 insIndex, mp_sint32 smpIndex)
1334 {
1335 SYSCHAR buffer[MP_MAXTEXT+1];
1336 memset(buffer, 0, sizeof(buffer));
1337
1338 TXMSample* smp = getSampleInfo(insIndex,smpIndex);
1339
1340 mp_sint32 len = convertStr(buffer, smp->name);
1341
1342 if (!len)
1343 sampleFileName = getInstrumentFileName(insIndex);
1344 else
1345 {
1346 sampleFileName = buffer;
1347 sampleFileName = sampleFileName.stripExtension();
1348 }
1349
1350 return sampleFileName;
1351 }
1352
1353 // free last instrument
freeInstrument()1354 void ModuleEditor::freeInstrument()
1355 {
1356 if (module->header.insnum <= 1)
1357 return;
1358
1359 enterCriticalSection();
1360
1361 for (mp_sint32 j = 0; j < 16; j++)
1362 instruments[module->header.insnum].usedSamples[j] = -1;
1363
1364 instruments[module->header.insnum].volumeEnvelope = -1;
1365 instruments[module->header.insnum].panningEnvelope = -1;
1366
1367 memset(instruments[module->header.insnum].nbu, 0, MAX_NOTE);
1368
1369 module->header.insnum--;
1370
1371 module->header.smpnum-=16;
1372
1373 leaveCriticalSection();
1374
1375 changed = true;
1376 }
1377
insertXIInstrument(mp_sint32 index,const XIInstrument * ins)1378 bool ModuleEditor::insertXIInstrument(mp_sint32 index, const XIInstrument* ins)
1379 {
1380 ASSERT(index < module->header.insnum);
1381
1382 mp_sint32 j;
1383
1384 ASSERT(instruments[index].numUsedSamples == 16);
1385
1386 memcpy(instruments[index].nbu, ins->nbu, MAX_NOTE);
1387
1388 for (j = 0; j < MAX_NOTE; j++)
1389 instruments[index].instrument->snum[j] = index*16 + ins->nbu[j];
1390
1391 memcpy(instruments[index].instrument->name, ins->name, MAX_INSTEXT);
1392
1393 instruments[index].instrument->samp = ins->numsamples;
1394
1395 memcpy(&module->venvs[instruments[index].volumeEnvelope], &ins->venv, sizeof(ins->venv));
1396 memcpy(&module->penvs[instruments[index].panningEnvelope], &ins->penv, sizeof(ins->penv));
1397
1398 instruments[index].volfade = ins->volfade>>1;
1399 instruments[index].vibtype = ins->vibtype;
1400 instruments[index].vibrate = ins->vibrate;
1401 instruments[index].vibdepth = ins->vibdepth>>1;
1402 instruments[index].vibsweep = ins->vibsweep;
1403
1404 // Wipe samples first
1405 for (j = 0; j < 16; j++)
1406 {
1407 mp_sint32 s = instruments[index].usedSamples[j];
1408
1409 TXMSample* smp = &module->smp[s];
1410
1411 if (smp->sample)
1412 {
1413 module->freeSampleMem((mp_ubyte*)smp->sample);
1414 smp->sample = NULL;
1415 }
1416
1417 smp->vol = 255;
1418 smp->pan = 0x80;
1419 smp->finetune = 0;
1420 smp->relnote = 0;
1421 smp->looplen = smp->loopstart = smp->samplen = 0;
1422 smp->flags = smp->type = 0;
1423 memset(smp->name, 0, sizeof(smp->name));
1424 }
1425
1426
1427 for (j = 0; j < ins->numsamples; j++)
1428 {
1429 mp_sint32 s = instruments[index].usedSamples[j];
1430
1431 // 16 bit samples
1432 if (ins->samples[j].samplen && ins->samples[j].sample)
1433 {
1434 if (ins->samples[j].type & 16)
1435 {
1436 module->smp[s].sample = (mp_sbyte*)module->allocSampleMem(ins->samples[j].samplen*2);
1437 if (module->smp[s].sample == NULL)
1438 return false;
1439
1440 TXMSample::copyPaddedMem(module->smp[s].sample, ins->samples[j].sample, ins->samples[j].samplen*2);
1441 }
1442 else
1443 {
1444 module->smp[s].sample = (mp_sbyte*)module->allocSampleMem(ins->samples[j].samplen);
1445 if (module->smp[s].sample == NULL)
1446 return false;
1447
1448 TXMSample::copyPaddedMem(module->smp[s].sample, ins->samples[j].sample, ins->samples[j].samplen);
1449 }
1450 }
1451
1452 const TXMSample* src = &ins->samples[j];
1453 TXMSample* dst = &module->smp[s];
1454
1455 // default values first
1456 dst->flags = 3;
1457 dst->venvnum = instruments[index].volumeEnvelope+1;
1458 dst->penvnum = instruments[index].panningEnvelope+1;
1459 dst->fenvnum = dst->vibenvnum = 0;
1460
1461 // copy from original instrument
1462 dst->samplen = src->samplen;
1463 dst->loopstart = src->loopstart;
1464 dst->looplen = src->looplen;
1465 dst->vol = src->vol;
1466 dst->finetune = src->finetune;
1467 dst->type = src->type;
1468 dst->pan = src->pan;
1469 dst->relnote = src->relnote;
1470
1471 dst->vibtype = src->vibtype;
1472 dst->vibsweep = src->vibsweep;
1473 dst->vibdepth = src->vibdepth;
1474 dst->vibrate = src->vibrate;
1475 dst->volfade = src->volfade;
1476
1477 memcpy(dst->name, src->name, sizeof(dst->name));
1478 }
1479
1480 changed = true;
1481
1482 return true;
1483 }
1484
extractXIInstrument(mp_sint32 index)1485 XIInstrument* ModuleEditor::extractXIInstrument(mp_sint32 index)
1486 {
1487 ASSERT(index < module->header.insnum);
1488
1489 XIInstrument* ins = new XIInstrument();
1490
1491 if (ins == NULL)
1492 return NULL;
1493
1494 mp_sint32 j;
1495
1496 ASSERT(instruments[index].numUsedSamples == 16);
1497
1498 memcpy(ins->nbu, instruments[index].nbu, MAX_NOTE);
1499
1500 memcpy(ins->name, instruments[index].instrument->name, MAX_INSTEXT);
1501
1502 ins->numsamples = 16;
1503
1504 memcpy(&ins->venv, &module->venvs[instruments[index].volumeEnvelope], sizeof(ins->venv));
1505 memcpy(&ins->penv, &module->penvs[instruments[index].panningEnvelope], sizeof(ins->penv));
1506
1507 ins->volfade = instruments[index].volfade<<1;
1508 ins->vibtype = instruments[index].vibtype;
1509 ins->vibrate = instruments[index].vibrate;
1510 ins->vibdepth = instruments[index].vibdepth<<1;
1511 ins->vibsweep = instruments[index].vibsweep;
1512
1513 for (j = 0; j < ins->numsamples; j++)
1514 {
1515 mp_sint32 s = instruments[index].usedSamples[j];
1516
1517 TXMSample* dst = &ins->samples[j];
1518 TXMSample* src = &module->smp[s];
1519
1520 // default values first
1521 dst->flags = 3;
1522 dst->venvnum = instruments[index].volumeEnvelope+1;
1523 dst->penvnum = instruments[index].panningEnvelope+1;
1524 dst->fenvnum = dst->vibenvnum = 0;
1525
1526 // copy from original instrument
1527 dst->samplen = src->samplen;
1528 dst->loopstart = src->loopstart;
1529 dst->looplen = src->looplen;
1530 dst->vol = src->vol;
1531 dst->finetune = src->finetune;
1532 dst->type = src->type;
1533 dst->pan = src->pan;
1534 dst->relnote = src->relnote;
1535 dst->sample = src->sample;
1536
1537 dst->vibtype = src->vibtype;
1538 dst->vibsweep = src->vibsweep;
1539 dst->vibdepth = src->vibdepth;
1540 dst->vibrate = src->vibrate;
1541 dst->volfade = src->volfade;
1542
1543 memcpy(dst->name, src->name, sizeof(dst->name));
1544 }
1545
1546 return ins;
1547 }
1548
loadInstrument(const SYSCHAR * fileName,mp_sint32 index)1549 bool ModuleEditor::loadInstrument(const SYSCHAR* fileName, mp_sint32 index)
1550 {
1551 ASSERT(index < module->header.insnum);
1552
1553 XIInstrument* ins = new XIInstrument();
1554
1555 bool res = ins->load(fileName) == 0;
1556
1557 if (res)
1558 {
1559 res = insertXIInstrument(index, ins);
1560
1561 finishSamples();
1562
1563 validateInstruments();
1564 }
1565
1566 delete ins;
1567
1568 return res;
1569 }
1570
saveInstrument(const SYSCHAR * fileName,mp_sint32 index)1571 bool ModuleEditor::saveInstrument(const SYSCHAR* fileName, mp_sint32 index)
1572 {
1573 ASSERT(index < module->header.insnum);
1574
1575 XIInstrument* ins = extractXIInstrument(index);
1576
1577 bool res = true;
1578
1579 if (ins)
1580 {
1581 ins->save(fileName);
1582 }
1583
1584 return res;
1585 }
1586
zapInstrument(mp_sint32 index)1587 bool ModuleEditor::zapInstrument(mp_sint32 index)
1588 {
1589 ASSERT(index < module->header.insnum);
1590
1591 enterCriticalSection();
1592
1593 XIInstrument ins;
1594
1595 bool res = insertXIInstrument(index, &ins);
1596
1597 finishSamples();
1598
1599 validateInstruments();
1600
1601 leaveCriticalSection();
1602
1603 changed = true;
1604
1605 return res;
1606 }
1607
getInstrumentFileName(mp_sint32 index)1608 const PPSystemString& ModuleEditor::getInstrumentFileName(mp_sint32 index)
1609 {
1610 SYSCHAR buffer[MP_MAXTEXT+1];
1611 memset(buffer, 0, sizeof(buffer));
1612
1613 TEditorInstrument* ins = getInstrumentInfo(index);
1614
1615 mp_sint32 len = convertStr(buffer, ins->instrument->name);
1616
1617 if (!len)
1618 instrumentFileName = "Untitled";
1619 else
1620 {
1621 instrumentFileName = buffer;
1622 instrumentFileName = instrumentFileName.stripExtension();
1623 }
1624
1625 return instrumentFileName;
1626 }
1627
copyInstrument(ModuleEditor & dstModule,mp_sint32 dstIndex,ModuleEditor & srcModule,mp_sint32 srcIndex)1628 bool ModuleEditor::copyInstrument(ModuleEditor& dstModule, mp_sint32 dstIndex,
1629 ModuleEditor& srcModule, mp_sint32 srcIndex)
1630 {
1631 ASSERT(srcIndex < srcModule.module->header.insnum);
1632 ASSERT(dstIndex < dstModule.module->header.insnum);
1633
1634 XIInstrument* srcIns = srcModule.extractXIInstrument(srcIndex);
1635
1636 if (!srcIns)
1637 return false;
1638
1639 XIInstrument* dstIns = new XIInstrument(*srcIns);
1640
1641 if (!dstIns)
1642 {
1643 delete srcIns;
1644 return false;
1645 }
1646
1647 dstModule.enterCriticalSection();
1648
1649 bool res = dstModule.insertXIInstrument(dstIndex, dstIns);
1650
1651 if (res)
1652 {
1653 dstModule.finishSamples();
1654 dstModule.validateInstruments();
1655 }
1656
1657 delete dstIns;
1658 delete srcIns;
1659
1660 dstModule.leaveCriticalSection();
1661
1662 return res;
1663 }
1664
swapInstruments(ModuleEditor & dstModule,mp_sint32 dstIndex,ModuleEditor & srcModule,mp_sint32 srcIndex)1665 bool ModuleEditor::swapInstruments(ModuleEditor& dstModule, mp_sint32 dstIndex,
1666 ModuleEditor& srcModule, mp_sint32 srcIndex)
1667 {
1668 ASSERT(srcIndex < srcModule.module->header.insnum);
1669 ASSERT(dstIndex < dstModule.module->header.insnum);
1670
1671 XIInstrument* srcIns = srcModule.extractXIInstrument(srcIndex);
1672
1673 if (!srcIns)
1674 return false;
1675
1676 XIInstrument* dstIns = dstModule.extractXIInstrument(dstIndex);
1677
1678 if (!dstIns)
1679 {
1680 delete srcIns;
1681 return false;
1682 }
1683
1684 XIInstrument* swapSrc = new XIInstrument(*srcIns);
1685
1686 if (!swapSrc)
1687 {
1688 delete dstIns;
1689 delete srcIns;
1690 return false;
1691 }
1692
1693 XIInstrument* swapDst = new XIInstrument(*dstIns);
1694
1695 if (!swapDst)
1696 {
1697 delete swapSrc;
1698 delete dstIns;
1699 delete srcIns;
1700 return false;
1701 }
1702
1703 delete dstIns;
1704 delete srcIns;
1705
1706 if (&dstModule == &srcModule)
1707 {
1708 dstModule.enterCriticalSection();
1709 }
1710 else
1711 {
1712 srcModule.enterCriticalSection();
1713 dstModule.enterCriticalSection();
1714 }
1715
1716 bool res = dstModule.insertXIInstrument(dstIndex, swapSrc);
1717 res = srcModule.insertXIInstrument(srcIndex, swapDst) && res;
1718
1719 if (res)
1720 {
1721 srcModule.finishSamples();
1722 srcModule.validateInstruments();
1723
1724 dstModule.finishSamples();
1725 dstModule.validateInstruments();
1726 }
1727
1728 delete swapDst;
1729 delete swapSrc;
1730
1731 if (&dstModule == &srcModule)
1732 {
1733 dstModule.leaveCriticalSection();
1734 }
1735 else
1736 {
1737 dstModule.leaveCriticalSection();
1738 srcModule.leaveCriticalSection();
1739 }
1740
1741 return res;
1742 }
1743
copySample(ModuleEditor & dstModule,mp_sint32 dstInsIndex,mp_sint32 dstIndex,ModuleEditor & srcModule,mp_sint32 srcInsIndex,mp_sint32 srcIndex)1744 bool ModuleEditor::copySample(ModuleEditor& dstModule, mp_sint32 dstInsIndex, mp_sint32 dstIndex,
1745 ModuleEditor& srcModule, mp_sint32 srcInsIndex, mp_sint32 srcIndex)
1746 {
1747 ASSERT(srcInsIndex < srcModule.module->header.insnum);
1748 ASSERT(dstInsIndex < dstModule.module->header.insnum);
1749
1750 ASSERT(srcIndex < 16);
1751 ASSERT(dstIndex < 16);
1752
1753 bool res = true;
1754
1755 TXMSample* dstSmp = dstModule.getSampleInfo(dstInsIndex, dstIndex);
1756 TXMSample* srcSmp = srcModule.getSampleInfo(srcInsIndex, srcIndex);
1757
1758 dstModule.enterCriticalSection();
1759
1760 if (dstSmp->sample && dstSmp->samplen)
1761 dstModule.module->freeSampleMem((mp_ubyte*)dstSmp->sample);
1762
1763 // assign attributes
1764 *dstSmp = *srcSmp;
1765
1766 mp_sint32 sampleSize = (srcSmp->samplen * ((srcSmp->type & 16) ? 16:8)) >> 3;
1767 if (sampleSize && srcSmp->sample)
1768 {
1769 dstSmp->sample = (mp_sbyte*)dstModule.module->allocSampleMem(sampleSize);
1770 if (dstSmp->sample)
1771 {
1772 TXMSample::copyPaddedMem(dstSmp->sample, srcSmp->sample, sampleSize);
1773 dstModule.finishSamples();
1774 dstModule.validateInstruments();
1775 }
1776 else res = false;
1777 }
1778
1779 dstModule.leaveCriticalSection();
1780
1781 return res;
1782 }
1783
swapSamples(ModuleEditor & dstModule,mp_sint32 dstInsIndex,mp_sint32 dstIndex,ModuleEditor & srcModule,mp_sint32 srcInsIndex,mp_sint32 srcIndex)1784 bool ModuleEditor::swapSamples(ModuleEditor& dstModule, mp_sint32 dstInsIndex, mp_sint32 dstIndex,
1785 ModuleEditor& srcModule, mp_sint32 srcInsIndex, mp_sint32 srcIndex)
1786 {
1787 ASSERT(srcInsIndex < srcModule.module->header.insnum);
1788 ASSERT(dstInsIndex < dstModule.module->header.insnum);
1789
1790 ASSERT(srcIndex < 16);
1791 ASSERT(dstIndex < 16);
1792
1793 bool res = true;
1794
1795 if (&dstModule == &srcModule)
1796 {
1797 dstModule.enterCriticalSection();
1798 }
1799 else
1800 {
1801 srcModule.enterCriticalSection();
1802 dstModule.enterCriticalSection();
1803 }
1804
1805 TXMSample* dstSmp = dstModule.getSampleInfo(dstInsIndex, dstIndex);
1806 TXMSample* srcSmp = srcModule.getSampleInfo(srcInsIndex, srcIndex);
1807
1808 TXMSample tmpSmp;
1809
1810 srcModule.module->removeSamplePtr((mp_ubyte*)srcSmp->sample);
1811 dstModule.module->removeSamplePtr((mp_ubyte*)dstSmp->sample);
1812
1813 tmpSmp = *dstSmp;
1814 *dstSmp = *srcSmp;
1815 *srcSmp = tmpSmp;
1816
1817 srcModule.module->insertSamplePtr((mp_ubyte*)srcSmp->sample);
1818 dstModule.module->insertSamplePtr((mp_ubyte*)dstSmp->sample);
1819
1820 if (&dstModule == &srcModule)
1821 {
1822 dstModule.leaveCriticalSection();
1823 }
1824 else
1825 {
1826 dstModule.leaveCriticalSection();
1827 srcModule.leaveCriticalSection();
1828 }
1829
1830 return res;
1831 }
1832
setNumChannels(mp_uint32 channels)1833 void ModuleEditor::setNumChannels(mp_uint32 channels)
1834 {
1835 if (module->header.channum != channels)
1836 changed = true;
1837 module->header.channum = channels;
1838 }
1839
setTitle(const char * name,mp_uint32 length)1840 void ModuleEditor::setTitle(const char* name, mp_uint32 length)
1841 {
1842 insertText(module->header.name, name, length);
1843 changed = true;
1844 }
1845
getTitle(char * name,mp_uint32 length) const1846 void ModuleEditor::getTitle(char* name, mp_uint32 length) const
1847 {
1848 if (length > MAX_TITLETEXT)
1849 length = MAX_TITLETEXT;
1850 XModule::convertStr(name, (char*)module->header.name, length, false);
1851 }
1852
setNumOrders(mp_sint32 numOrders)1853 void ModuleEditor::setNumOrders(mp_sint32 numOrders)
1854 {
1855 if (numOrders > 255)
1856 numOrders = 255;
1857 if (numOrders < 1)
1858 numOrders = 1;
1859
1860 if (module->header.ordnum != numOrders)
1861 changed = true;
1862
1863 module->header.ordnum = numOrders;
1864 }
1865
setFrequency(Frequencies frequency)1866 void ModuleEditor::setFrequency(Frequencies frequency)
1867 {
1868 // changes are made using the settings panel
1869 // do not flag changes here
1870 //mp_sint32 old = module->header.freqtab;
1871 module->header.freqtab &= ~1;
1872 module->header.freqtab |= frequency;
1873 //if (old != module->header.freqtab)
1874 // changed = true;
1875 }
1876
setSampleName(mp_sint32 insIndex,mp_sint32 smpIndex,const char * name,mp_uint32 length)1877 void ModuleEditor::setSampleName(mp_sint32 insIndex, mp_sint32 smpIndex, const char* name, mp_uint32 length)
1878 {
1879 insertText((char*)getSampleInfo(insIndex, smpIndex)->name, name, length);
1880 changed = true;
1881 }
1882
getSampleName(mp_sint32 insIndex,mp_sint32 smpIndex,char * name,mp_uint32 length) const1883 void ModuleEditor::getSampleName(mp_sint32 insIndex, mp_sint32 smpIndex, char* name, mp_uint32 length) const
1884 {
1885 if (length > MAX_SMPTEXT)
1886 length = MAX_SMPTEXT;
1887 XModule::convertStr(name, (char*)getSampleInfoInternal(insIndex, smpIndex)->name, length, false);
1888 }
1889
setCurrentSampleName(const char * name,mp_uint32 length)1890 void ModuleEditor::setCurrentSampleName(const char* name, mp_uint32 length)
1891 {
1892 if (sampleEditor->getSample() == NULL)
1893 return;
1894
1895 insertText((char*)sampleEditor->getSample()->name, name, length);
1896 changed = true;
1897 }
1898
getFirstSampleInfo()1899 TXMSample* ModuleEditor::getFirstSampleInfo()
1900 {
1901 enumerationIndex = 0;
1902 if (enumerationIndex < module->header.smpnum)
1903 return &module->smp[enumerationIndex];
1904 else
1905 return NULL;
1906 }
1907
getNextSampleInfo()1908 TXMSample* ModuleEditor::getNextSampleInfo()
1909 {
1910 enumerationIndex++;
1911 if (enumerationIndex >= module->header.smpnum)
1912 {
1913 enumerationIndex = -1;
1914 return NULL;
1915 }
1916
1917 return &module->smp[enumerationIndex];
1918 }
1919
setInstrumentName(mp_sint32 insIndex,const char * name,mp_uint32 length)1920 void ModuleEditor::setInstrumentName(mp_sint32 insIndex, const char* name, mp_uint32 length)
1921 {
1922 insertText(module->instr[insIndex].name, name, length);
1923 changed = true;
1924 }
1925
getInstrumentName(mp_sint32 insIndex,char * name,mp_uint32 length) const1926 void ModuleEditor::getInstrumentName(mp_sint32 insIndex, char* name, mp_uint32 length) const
1927 {
1928 if (length > MAX_INSTEXT)
1929 length = MAX_INSTEXT;
1930
1931 XModule::convertStr(name, module->instr[insIndex].name, length, false);
1932 }
1933
getEnvelope(mp_sint32 insIndex,mp_sint32 smpIndex,mp_sint32 type)1934 TEnvelope* ModuleEditor::getEnvelope(mp_sint32 insIndex, mp_sint32 smpIndex, mp_sint32 type)
1935 {
1936 if (insIndex < 0 || insIndex >= module->header.insnum)
1937 return NULL;
1938
1939 if (smpIndex < 0 || smpIndex >= instruments[insIndex].numUsedSamples)
1940 return NULL;
1941
1942 TXMSample* smp = getSampleInfo(insIndex,smpIndex);
1943
1944 // no envelopes available, assign some
1945 if (smp->venvnum == 0)
1946 smp->venvnum = instruments[insIndex].volumeEnvelope+1;
1947 // no envelope available, assign one
1948 if (smp->penvnum == 0)
1949 smp->penvnum = instruments[insIndex].panningEnvelope+1;
1950
1951 if (type == 0 && smp->venvnum)
1952 {
1953 return &module->venvs[smp->venvnum-1];
1954 }
1955 else if (type == 1 && smp->penvnum)
1956 {
1957 return &module->penvs[smp->penvnum-1];
1958 }
1959
1960 return NULL;
1961 }
1962
getSampleTable(mp_sint32 insIndex)1963 const mp_ubyte* ModuleEditor::getSampleTable(mp_sint32 insIndex)
1964 {
1965 if (insIndex < 0 || insIndex >= module->header.insnum)
1966 return NULL;
1967
1968 return instruments[insIndex].nbu;
1969 }
1970
updateSampleTable(mp_sint32 index,const mp_ubyte * nbu)1971 void ModuleEditor::updateSampleTable(mp_sint32 index, const mp_ubyte* nbu)
1972 {
1973 if (nbu == NULL)
1974 return;
1975
1976 if (index < 0 || index >= module->header.insnum)
1977 return;
1978
1979 // cope with FT2 noterange (= 96)
1980 memcpy(instruments[index].nbu, nbu, MAX_NOTE);
1981
1982 // update module data
1983 for (mp_sint32 i = 0; i < MAX_NOTE; i++)
1984 {
1985 if (nbu[i] != 255)
1986 module->instr[index].snum[i] = instruments[index].usedSamples[nbu[i]];
1987 else
1988 module->instr[index].snum[i] = 255;
1989
1990 }
1991
1992 changed = true;
1993 }
1994
updateInstrumentData(mp_sint32 index)1995 void ModuleEditor::updateInstrumentData(mp_sint32 index)
1996 {
1997
1998 if (index < 0)
1999 return;
2000
2001 if (index >= module->header.insnum)
2002 return;
2003
2004 for (mp_sint32 i = 0; i < instruments[index].numUsedSamples; i++)
2005 {
2006 mp_sint32 s = instruments[index].usedSamples[i];
2007
2008 TXMSample* smp = &module->smp[s];
2009
2010 smp->volfade = instruments[index].volfade << 1;
2011 if (smp->volfade == 65534) smp->volfade++;
2012 smp->vibtype = instruments[index].vibtype;
2013 smp->vibrate = instruments[index].vibrate;
2014 smp->vibdepth = instruments[index].vibdepth << 1;
2015 smp->vibsweep = instruments[index].vibsweep;
2016 }
2017
2018 changed = true;
2019
2020 }
2021
insRemapSong(pp_int32 oldIns,pp_int32 newIns)2022 pp_int32 ModuleEditor::insRemapSong(pp_int32 oldIns, pp_int32 newIns)
2023 {
2024 mp_sint32 resCnt = 0;
2025
2026 PatternEditorTools patternEditorTools;
2027
2028 for (mp_sint32 k = 0; k < module->header.patnum; k++)
2029 {
2030 patternEditorTools.attachPattern(&module->phead[k]);
2031 resCnt+=patternEditorTools.insRemap(oldIns, newIns);
2032 }
2033
2034 if (resCnt)
2035 changed = true;
2036
2037 return resCnt;
2038 }
2039
noteTransposeSong(const PatternEditorTools::TransposeParameters & transposeParameters,bool evaluate)2040 pp_int32 ModuleEditor::noteTransposeSong(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate/* = false*/)
2041 {
2042 mp_sint32 resCnt = 0;
2043 pp_int32 fuckupCnt = 0;
2044
2045 PatternEditorTools patternEditorTools;
2046
2047 for (mp_sint32 k = 0; k < module->header.patnum; k++)
2048 {
2049 patternEditorTools.attachPattern(&module->phead[k]);
2050
2051 if (evaluate)
2052 fuckupCnt+=patternEditorTools.noteTranspose(transposeParameters, evaluate);
2053 else
2054 resCnt+=patternEditorTools.noteTranspose(transposeParameters, evaluate);
2055 }
2056
2057 if (!evaluate)
2058 {
2059 if (resCnt)
2060 changed = true;
2061
2062 return resCnt;
2063 }
2064 else
2065 return fuckupCnt;
2066 }
2067
panConvertSong(PanConversionTypes type)2068 pp_int32 ModuleEditor::panConvertSong(PanConversionTypes type)
2069 {
2070 mp_sint32 resCnt = 0;
2071
2072 for (mp_sint32 k = 0; k < module->header.patnum; k++)
2073 {
2074 TXMPattern* pattern = &module->phead[k];
2075
2076 if (pattern->patternData == NULL)
2077 continue;
2078
2079 mp_sint32 slotSize = pattern->effnum * 2 + 2;
2080 mp_sint32 rowSizeSrc = slotSize*pattern->channum;
2081
2082 for (pp_int32 i = 0; i < pattern->rows; i++)
2083 for (pp_int32 j = 0; j < pattern->channum; j++)
2084 {
2085 mp_ubyte* src = pattern->patternData + i*rowSizeSrc+j*slotSize;
2086
2087 switch (type)
2088 {
2089 case PanConversionTypeConvert_E8x:
2090 if (src[4] == 0x38)
2091 {
2092 src[4] = 0x08;
2093 src[5] = (mp_ubyte)XModule::pan15to255(src[5]);
2094 resCnt++;
2095 }
2096 break;
2097 case PanConversionTypeConvert_80x:
2098 if (src[4] == 0x08)
2099 {
2100 src[5] = (mp_ubyte)XModule::pan15to255(src[5]);
2101 resCnt++;
2102 }
2103 break;
2104 case PanConversionTypeRemove_E8x:
2105 if (src[4] == 0x38)
2106 {
2107 src[4] = src[5] = 0x0;
2108 resCnt++;
2109 }
2110 break;
2111 case PanConversionTypeRemove_8xx:
2112 if (src[4] == 0x08)
2113 {
2114 src[4] = src[5] = 0x0;
2115 resCnt++;
2116 }
2117 break;
2118 }
2119 }
2120
2121 }
2122
2123 if (resCnt)
2124 changed = true;
2125
2126 return resCnt;
2127 }
2128
removeUnusedPatterns(bool evaluate)2129 pp_int32 ModuleEditor::removeUnusedPatterns(bool evaluate)
2130 {
2131 mp_sint32 result = module->removeUnusedPatterns(evaluate);
2132
2133 if (!evaluate && result)
2134 {
2135 changed = true;
2136 if (currentPatternIndex > module->header.patnum - 1)
2137 currentPatternIndex = module->header.patnum - 1;
2138 }
2139 return result;
2140 }
2141
removeUnusedInstruments(bool evaluate,bool remap)2142 pp_int32 ModuleEditor::removeUnusedInstruments(bool evaluate, bool remap)
2143 {
2144 mp_sint32 i,j,k;
2145
2146 mp_ubyte* bitMap = new mp_ubyte[MAX_INSTRUMENTS];
2147
2148 memset(bitMap, 0, sizeof(mp_ubyte)*MAX_INSTRUMENTS);
2149
2150 for (k = 0; k < module->header.patnum; k++)
2151 {
2152 TXMPattern* pattern = &module->phead[k];
2153
2154 if (pattern->patternData == NULL)
2155 continue;
2156
2157 mp_sint32 slotSize = pattern->effnum * 2 + 2;
2158 mp_sint32 rowSizeSrc = slotSize*pattern->channum;
2159
2160 for (i = 0; i < pattern->rows; i++)
2161 for (j = 0; j < pattern->channum; j++)
2162 {
2163 mp_ubyte* src = pattern->patternData + i*rowSizeSrc+j*slotSize;
2164
2165 if (src[1])
2166 {
2167 bitMap[src[1]-1] = TRUE;
2168 }
2169 }
2170
2171 }
2172
2173 mp_sint32 result = 0;
2174 for (i = 0; i < module->header.insnum; i++)
2175 {
2176 if (!bitMap[i])
2177 {
2178 result++;
2179 if (!evaluate)
2180 zapInstrument(i);
2181 }
2182 }
2183
2184 if (!evaluate)
2185 {
2186 mp_sint32* insRelocTable = new mp_sint32[MAX_INSTRUMENTS];
2187
2188 for (i = 0, j = 0; i < module->header.insnum; i++)
2189 {
2190 if (bitMap[i])
2191 {
2192 insRelocTable[i] = j++;
2193 }
2194 }
2195
2196 for (i = 0, k = 0; i < module->header.insnum; i++)
2197 {
2198 if (bitMap[i])
2199 {
2200 j = insRelocTable[i];
2201
2202 if (j < i)
2203 {
2204 XIInstrument* ins = extractXIInstrument(i);
2205
2206 insertXIInstrument(j, ins);
2207
2208 delete ins;
2209
2210 insRemapSong(i+1, j+1);
2211
2212 zapInstrument(i);
2213
2214 }
2215 k++;
2216 }
2217 }
2218 delete[] insRelocTable;
2219
2220 // zero number of instruments is not allowed
2221 if (k == 0)
2222 {
2223 result--;
2224 k++;
2225 }
2226
2227 module->header.insnum = k;
2228 module->header.smpnum = k*16;
2229 }
2230 else
2231 {
2232 if (module->header.insnum - result <= 0)
2233 result--;
2234 }
2235
2236 if (!evaluate && result)
2237 changed = true;
2238
2239 delete[] bitMap;
2240
2241 return result;
2242 }
2243
removeUnusedSamples(bool evaluate)2244 pp_int32 ModuleEditor::removeUnusedSamples(bool evaluate)
2245 {
2246 mp_sint32 i,j,k;
2247
2248 mp_ubyte* bitMap = new mp_ubyte[MP_MAXSAMPLES];
2249
2250 memset(bitMap, 0, sizeof(mp_ubyte)*MP_MAXSAMPLES);
2251
2252 mp_ubyte* lastIns = new mp_ubyte[module->header.channum];
2253 memset(lastIns, 0, module->header.channum);
2254
2255 for (mp_sint32 l = 0; l < module->header.ordnum; l++)
2256 {
2257 k = module->header.ord[l];
2258
2259 TXMPattern* pattern = &module->phead[k];
2260
2261 if (pattern->patternData == NULL)
2262 continue;
2263
2264 mp_sint32 slotSize = pattern->effnum * 2 + 2;
2265 mp_sint32 rowSizeSrc = slotSize*pattern->channum;
2266
2267 for (i = 0; i < pattern->rows; i++)
2268 for (j = 0; j < pattern->channum; j++)
2269 {
2270 mp_ubyte* src = pattern->patternData + i*rowSizeSrc+j*slotSize;
2271
2272 if (src[1])
2273 {
2274 lastIns[j] = src[1];
2275 #if 0
2276 // just assume, that if an instrument is used
2277 // in the pattern, that the first sample of this instrument
2278 // is kept even if there isn't any note played with that instrument
2279 mp_sint32 insIndex = lastIns[j] - 1;
2280 mp_sint32 smpIndex = module->instr[insIndex].snum[0];
2281 if (smpIndex >= 0 && smpIndex < MP_MAXSAMPLES)
2282 bitMap[smpIndex] = TRUE;
2283 #endif
2284 }
2285
2286 if (src[0] && src[0] < 120)
2287 {
2288 if (lastIns[j])
2289 {
2290 mp_sint32 insIndex = lastIns[j] - 1;
2291
2292 mp_sint32 smpIndex = module->instr[insIndex].snum[src[0]-1];
2293
2294 if (smpIndex >= 0 && smpIndex < MP_MAXSAMPLES)
2295 bitMap[smpIndex] = TRUE;
2296 }
2297 }
2298 }
2299
2300 }
2301
2302 delete[] lastIns;
2303
2304 mp_sint32 result = 0;
2305 for (i = 0; i < module->header.smpnum; i++)
2306 {
2307 if (!bitMap[i] && module->smp[i].sample)
2308 {
2309 result++;
2310 if (!evaluate)
2311 {
2312 clearSample(i);
2313 // wipe out sample slot
2314 memset(module->smp + i, 0, sizeof(TXMSample));
2315 }
2316 }
2317 }
2318
2319 // relocate samples
2320 if (!evaluate)
2321 {
2322 for (i = 0; i < module->header.insnum; i++)
2323 {
2324 mp_sint32 smpRelocTable[16];
2325 for (j = 0; j < 16; j++)
2326 smpRelocTable[j] = -1;
2327
2328 mp_sint32 s = 0;
2329 TXMSample* src = module->smp + 16*i;
2330 TXMSample* dst = src;
2331 for (j = 0; j < 16; j++, src++)
2332 {
2333 k = i*16+j;
2334 if (bitMap[k])
2335 {
2336 if (src != dst)
2337 {
2338 *dst = *src;
2339 // wipe out source sample
2340 memset(src, 0, sizeof(TXMSample));
2341 }
2342 smpRelocTable[j] = s++;
2343 dst++;
2344 }
2345 }
2346
2347 // adjust the FT2 style sample->note mapping table
2348 TEditorInstrument* ins = instruments + i;
2349
2350 for (j = 0; j < MAX_NOTE; j++)
2351 if (ins->nbu[j] < 16 && smpRelocTable[ins->nbu[j]] != -1)
2352 ins->nbu[j] = smpRelocTable[ins->nbu[j]];
2353 else
2354 ins->nbu[j] = 0;
2355
2356 // convert back to milkytracker module style mapping
2357 for (j = 0; j < MAX_NOTE; j++)
2358 module->instr[i].snum[j] = i * 16 + ins->nbu[j];
2359
2360 }
2361 }
2362
2363 if (!evaluate && result)
2364 changed = true;
2365
2366 delete[] bitMap;
2367
2368 return result;
2369 }
2370
relocateCommands(const PatternEditorTools::RelocateParameters & relocateParameters,bool evaluate)2371 pp_int32 ModuleEditor::relocateCommands(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate)
2372 {
2373 mp_sint32 result = 0;
2374
2375 PatternEditorTools patternEditorTools;
2376
2377 for (mp_sint32 k = 0; k < module->header.patnum; k++)
2378 {
2379 patternEditorTools.attachPattern(&module->phead[k]);
2380 result+=patternEditorTools.relocateCommands(relocateParameters, evaluate);
2381 }
2382
2383 if (!evaluate && result)
2384 changed = true;
2385
2386 return result;
2387 }
2388
zeroOperands(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)2389 pp_int32 ModuleEditor::zeroOperands(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
2390 {
2391 mp_sint32 result = 0;
2392
2393 PatternEditorTools patternEditorTools;
2394
2395 for (mp_sint32 k = 0; k < module->header.patnum; k++)
2396 {
2397 patternEditorTools.attachPattern(&module->phead[k]);
2398 result+=patternEditorTools.zeroOperands(optimizeParameters, evaluate);
2399 }
2400
2401 if (!evaluate && result)
2402 changed = true;
2403
2404 return result;
2405 }
2406
fillOperands(const PatternEditorTools::OperandOptimizeParameters & optimizeParameters,bool evaluate)2407 pp_int32 ModuleEditor::fillOperands(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate)
2408 {
2409 mp_sint32 result = 0;
2410
2411 PatternEditorTools patternEditorTools;
2412
2413 for (mp_sint32 k = 0; k < module->header.patnum; k++)
2414 {
2415 patternEditorTools.attachPattern(&module->phead[k]);
2416 result+=patternEditorTools.fillOperands(optimizeParameters, evaluate);
2417 }
2418
2419 if (!evaluate && result)
2420 changed = true;
2421
2422 return result;
2423 }
2424
optimizeSamples(bool convertTo8Bit,bool minimize,mp_sint32 & numConvertedSamples,mp_sint32 & numMinimizedSamples,bool evaluate)2425 void ModuleEditor::optimizeSamples(bool convertTo8Bit, bool minimize,
2426 mp_sint32& numConvertedSamples, mp_sint32& numMinimizedSamples,
2427 bool evaluate)
2428 {
2429 TXMSample* oldSmp = sampleEditor->getSample();
2430
2431 TXMSample* smp = getFirstSampleInfo();
2432
2433 sampleEditor->activateUndoStack(false);
2434
2435 numConvertedSamples = numMinimizedSamples = 0;
2436
2437 while (smp)
2438 {
2439 sampleEditor->attachSample(smp, module);
2440
2441 // check for 16 bit sample
2442 if ((smp->type & 16) && smp->sample && smp->samplen && convertTo8Bit)
2443 {
2444 if (!evaluate)
2445 sampleEditor->convertSampleResolution(true);
2446 numConvertedSamples++;
2447 }
2448 if (smp->sample && smp->samplen && smp->isMinimizable() && minimize)
2449 {
2450 if (!evaluate)
2451 sampleEditor->minimizeSample();
2452 numMinimizedSamples++;
2453 }
2454
2455 smp = getNextSampleInfo();
2456 }
2457
2458 sampleEditor->activateUndoStack(true);
2459
2460 sampleEditor->attachSample(oldSmp, module);
2461
2462 if (!evaluate && (numMinimizedSamples || numConvertedSamples))
2463 changed = true;
2464 }
2465
insertText(char * dst,const char * src,mp_sint32 max)2466 void ModuleEditor::insertText(char* dst, const char* src, mp_sint32 max)
2467 {
2468 char name[MP_MAXTEXT+1];
2469
2470 ASSERT((signed)sizeof(name) >= max && strlen(src) <= sizeof(name));
2471
2472 memset(name, 0, sizeof(name));
2473 memcpy(name, src, (signed)strlen(src) <= max ? strlen(src) : max);
2474 memcpy(dst, name, max);
2475 }
2476
getTempFilename()2477 PPSystemString ModuleEditor::getTempFilename()
2478 {
2479 return PPSystemString(System::getTempFileName());
2480 }
2481
2482