1 /* 2 * tracker/ModuleEditor.h 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 #ifndef MODULEDITOR__H 24 #define MODULEDITOR__H 25 26 #include "MilkyPlay.h" 27 #include "BasicTypes.h" 28 #include "PatternEditorTools.h" 29 #include "SongLengthEstimator.h" 30 31 class XIInstrument; 32 class PatternEditor; 33 class SampleEditor; 34 class EnvelopeEditor; 35 class ModuleServices; 36 class PlayerCriticalSection; 37 38 class ModuleEditor 39 { 40 public: 41 enum 42 { 43 // FT2 noterange 44 MAX_NOTE = 96, 45 // FT2 maximum of instruments 46 MAX_INSTRUMENTS = 255, 47 // FT2 maximum of patterns 48 MAX_PATTERNS = 256, 49 // FT2 length of module title 50 MAX_TITLETEXT = 20, 51 // FT2 length of instrument text 52 MAX_INSTEXT = 22, 53 // FT2 length of sample text 54 MAX_SMPTEXT = 22, 55 }; 56 57 // "proxy" instrument type 58 struct TEditorInstrument 59 { 60 TXMInstrument* instrument; 61 62 // since TXMInstruments holds only references to the *used* samples 63 // we need another list of samples here in case the user wants to 64 // add a new sample that isn't used yet 65 66 // fasttracker 2 can only handle 16 samples 67 mp_sint32 numUsedSamples; 68 mp_sint32 usedSamples[16]; 69 70 // FT2 can only handle 96 notes 71 mp_ubyte nbu[MAX_NOTE]; 72 73 // fasttracker can only handle envelopes per instrument, 74 // no envelopes per sample 75 // store default envelope here 76 mp_sint32 volumeEnvelope; 77 mp_sint32 panningEnvelope; 78 79 // default volume fadeout 80 mp_uword volfade; 81 // default autovibrato stuff 82 mp_ubyte vibtype, vibsweep, vibdepth, vibrate; 83 }; 84 85 enum ModSaveTypes 86 { 87 ModSaveTypeDefault = -1, 88 ModSaveTypeXM, 89 ModSaveTypeMOD 90 }; 91 92 private: 93 XModule* module; 94 PatternEditor* patternEditor; 95 SampleEditor* sampleEditor; 96 EnvelopeEditor* envelopeEditor; 97 class ChangesListener* changesListener; 98 ModuleServices* moduleServices; 99 PlayerCriticalSection* playerCriticalSection; 100 101 bool changed; 102 103 PPSystemString moduleFileName; 104 PPSystemString sampleFileName; 105 PPSystemString instrumentFileName; 106 ModSaveTypes eSaveType; 107 108 void enterCriticalSection(); 109 void leaveCriticalSection(); 110 111 void adjustExtension(bool hasExtension = true); 112 113 TEditorInstrument* instruments; 114 115 // convert MilkyPlay instrument at index i to our more XM-style instrument 116 void convertInstrument(mp_sint32 i); 117 118 // create a mapping which helps to treat MilkyPlay style instruments like XM ones 119 void buildInstrumentTable(); 120 121 // make sure everything is fine 122 void validateInstruments(); 123 124 // insert an XIInstrument at position index 125 bool insertXIInstrument(mp_sint32 index, const XIInstrument* ins); 126 127 XIInstrument* extractXIInstrument(mp_sint32 index); 128 129 bool allocatePattern(TXMPattern* pattern); 130 131 mp_sint32 lastRequestedPatternIndex; 132 133 mp_sint32 currentOrderIndex; 134 mp_sint32 currentPatternIndex; 135 mp_sint32 currentInstrumentIndex; 136 mp_sint32 currentSampleIndex; 137 PatternEditorTools::Position currentCursorPosition; 138 139 pp_int32 enumerationIndex; 140 141 public: 142 ModuleEditor(); 143 ~ModuleEditor(); 144 getModule()145 XModule* getModule() { return module; } getPatternEditor()146 PatternEditor* getPatternEditor() { return patternEditor; } getSampleEditor()147 SampleEditor* getSampleEditor() { return sampleEditor; } getEnvelopeEditor()148 EnvelopeEditor* getEnvelopeEditor() { return envelopeEditor; } getModuleServices()149 ModuleServices* getModuleServices() { return moduleServices; } 150 attachPlayerCriticalSection(PlayerCriticalSection * playerCriticalSection)151 void attachPlayerCriticalSection(PlayerCriticalSection* playerCriticalSection) { this->playerCriticalSection = playerCriticalSection; } 152 153 PPSystemString getModuleFileNameFull(ModSaveTypes extension = ModSaveTypeDefault); 154 PPSystemString getModuleFileName(ModSaveTypes extension = ModSaveTypeDefault); 155 getSaveType()156 ModSaveTypes getSaveType() const { return eSaveType; } 157 setCurrentOrderIndex(mp_sint32 index)158 void setCurrentOrderIndex(mp_sint32 index) { currentOrderIndex = index; } getCurrentOrderIndex()159 mp_sint32 getCurrentOrderIndex() const { return currentOrderIndex; } 160 setCurrentPatternIndex(mp_sint32 index)161 void setCurrentPatternIndex(mp_sint32 index) { currentPatternIndex = index; } getCurrentPatternIndex()162 mp_sint32 getCurrentPatternIndex() const { return currentPatternIndex; } 163 setCurrentInstrumentIndex(mp_sint32 index)164 void setCurrentInstrumentIndex(mp_sint32 index) { currentInstrumentIndex = index; } getCurrentInstrumentIndex()165 mp_sint32 getCurrentInstrumentIndex() const { return currentInstrumentIndex; } 166 setCurrentSampleIndex(mp_sint32 index)167 void setCurrentSampleIndex(mp_sint32 index) { currentSampleIndex = index; } getCurrentSampleIndex()168 mp_sint32 getCurrentSampleIndex() const { return currentSampleIndex; } 169 setCurrentCursorPosition(const PatternEditorTools::Position & currentCursorPosition)170 void setCurrentCursorPosition(const PatternEditorTools::Position& currentCursorPosition) { this->currentCursorPosition = currentCursorPosition; } getCurrentCursorPosition()171 const PatternEditorTools::Position& getCurrentCursorPosition() { return currentCursorPosition; } 172 setChanged()173 void setChanged() { changed = true; } hasChanged()174 bool hasChanged() const { return changed; } 175 176 void reloadCurrentPattern(); 177 void reloadSample(mp_sint32 insIndex, mp_sint32 smpIndex); 178 void reloadEnvelope(mp_sint32 insIndex, mp_sint32 smpIndex, mp_sint32 type); 179 180 // --------- Access to module information/module data --------------------------- 181 void setNumChannels(mp_uint32 channels); getNumChannels()182 mp_uint32 getNumChannels() const { return module->header.channum; } 183 184 void setTitle(const char* name, mp_uint32 length); 185 void getTitle(char* name, mp_uint32 length) const; 186 187 void setNumOrders(mp_sint32 numOrders); getNumOrders()188 mp_sint32 getNumOrders() const { return module->header.ordnum; } 189 getNumInstruments()190 mp_sint32 getNumInstruments() const { return module->header.insnum; } getNumSamples(mp_sint32 insIndex)191 mp_sint32 getNumSamples(mp_sint32 insIndex) const { return instruments[insIndex].numUsedSamples; } 192 193 enum Frequencies 194 { 195 FrequencyAmiga = 0, 196 FrequencyLinear = 1 197 }; 198 void setFrequency(Frequencies frequency); getFrequency()199 Frequencies getFrequency() const { return (Frequencies)(module->header.freqtab & 1); } 200 getSongBPM()201 mp_sint32 getSongBPM() const { return module->header.speed; } getSongTickSpeed()202 mp_sint32 getSongTickSpeed() const { return module->header.tempo; } 203 204 // Check if song is protracker incompatible 205 // 0 = PTK compatible 206 // 1 = Song contains more than 31 instruments 207 // 2 = Song uses linear frequencies 208 // 3 = Song contains incompatible samples 209 // 4 = Song contains FT2-style instruments 210 // 5 = Incompatible pattern data getPTIncompatibilityCode()211 mp_uint32 getPTIncompatibilityCode() const { return module->isPTCompatible(); } 212 213 private: getSampleInfoInternal(mp_sint32 insIndex,mp_sint32 smpIndex)214 TXMSample* getSampleInfoInternal(mp_sint32 insIndex, mp_sint32 smpIndex) const { return &module->smp[instruments[insIndex].usedSamples[smpIndex]]; } 215 216 public: getSampleInfo(mp_sint32 insIndex,mp_sint32 smpIndex)217 TXMSample* getSampleInfo(mp_sint32 insIndex, mp_sint32 smpIndex) { return &module->smp[instruments[insIndex].usedSamples[smpIndex]]; } 218 219 void setSampleName(mp_sint32 insIndex, mp_sint32 smpIndex, const char* name, mp_uint32 length); 220 void getSampleName(mp_sint32 insIndex, mp_sint32 smpIndex, char* name, mp_uint32 length) const; 221 void setCurrentSampleName(const char* name, mp_uint32 length); 222 223 private: 224 TXMSample* getFirstSampleInfo(); 225 TXMSample* getNextSampleInfo(); 226 227 public: getInstrumentInfo(mp_sint32 insIndex)228 TEditorInstrument* getInstrumentInfo(mp_sint32 insIndex) { return &instruments[insIndex]; } 229 230 void setInstrumentName(mp_sint32 insIndex, const char* name, mp_uint32 length); 231 void getInstrumentName(mp_sint32 insIndex, char* name, mp_uint32 length) const; 232 233 TEnvelope* getEnvelope(mp_sint32 insIndex, mp_sint32 smpIndex, mp_sint32 type); 234 235 bool createNewSong(mp_uword numChannels = 8); 236 void createEmptySong(bool clearPatterns = true, bool clearInstruments = true, mp_sint32 numChannels = 8); 237 bool isEmpty() const; 238 239 bool openSong(const SYSCHAR* fileName, const SYSCHAR* preferredFileName = NULL); 240 bool saveSong(const SYSCHAR* fileName, ModSaveTypes saveType = ModSaveTypeXM); 241 mp_sint32 saveBackup(const SYSCHAR* fileName); 242 243 void increaseSongLength(); 244 void decreaseSongLength(); 245 getRepeatPos()246 mp_sint32 getRepeatPos() const { return module->header.restart; } 247 248 void increaseRepeatPos(); 249 void decreaseRepeatPos(); 250 251 // insert new position into orderlist 252 bool insertNewOrderPosition(mp_sint32 index); 253 // delete position from orderlist 254 void deleteOrderPosition(mp_sint32 index); 255 // duplicate current position and add one 256 bool seqCurrentOrderPosition(mp_sint32 index, bool clone = false); 257 258 // get pattern index at order position 259 mp_sint32 getOrderPosition(mp_sint32 index) const; 260 261 // inrease pattern number in the orderlist 262 void increaseOrderPosition(mp_sint32 index); 263 // decrease pattern number in the orderlist 264 void decreaseOrderPosition(mp_sint32 index); 265 266 bool isEditingOrderPosition(mp_sint32 index) const; 267 268 // throw away trailing empty patterns 269 // handle with care, they might be currently playing 270 void cleanUnusedPatterns(); 271 272 // get pattern, if not allocated yet, allocate one 273 TXMPattern* getPattern(mp_sint32 index, bool cleanUnusedPatterns = false); 274 275 // allocate new sample within given instrument (obsolete) 276 //mp_sint32 allocateSample(mp_sint32 index); 277 278 // free last sample within given instrument (obsolete) 279 void freeSample(mp_sint32 index); 280 281 // deallocate memory used by sample 282 void clearSample(mp_sint32 smpIndex); 283 void clearSample(mp_sint32 insIndex, mp_sint32 smpIndex); 284 285 // load sample 286 bool loadSample(const SYSCHAR* fileName, 287 mp_sint32 insIndex, 288 mp_sint32 smpIndex, 289 mp_sint32 channelIndex, 290 const SYSCHAR* preferredFileName = NULL); 291 292 // retrieve number of channels contained in a sample on disk 293 mp_sint32 getNumSampleChannels(const SYSCHAR* fileName); 294 295 // get name of channel 296 const char* getNameOfSampleChannel(const SYSCHAR* fileName, mp_sint32 index); 297 298 // save sample 299 enum SampleFormatTypes 300 { 301 SampleFormatTypeWAV, 302 SampleFormatTypeIFF 303 }; 304 305 bool saveSample(const SYSCHAR* fileName, mp_sint32 insIndex, mp_sint32 smpIndex, SampleFormatTypes format); 306 307 // create sample filename from sample name information 308 const PPSystemString& getSampleFileName(mp_sint32 insIndex, mp_sint32 smpIndex); 309 310 // postprocessing of samples, when changes are made 311 void finishSamples(); 312 313 // allocate one more instrument 314 mp_sint32 allocateInstrument(); 315 // free last instrument 316 void freeInstrument(); 317 318 // load instrument 319 bool loadInstrument(const SYSCHAR* fileName, mp_sint32 index); 320 // save instrument 321 bool saveInstrument(const SYSCHAR* fileName, mp_sint32 index); 322 323 // zap (clear) instrument 324 bool zapInstrument(mp_sint32 index); 325 326 // create instrument filename from instrument name information 327 const PPSystemString& getInstrumentFileName(mp_sint32 index); 328 329 bool copyInstrument(ModuleEditor& dstModule, mp_sint32 dstIndex, 330 ModuleEditor& srcModule, mp_sint32 srcIndex); 331 bool swapInstruments(ModuleEditor& dstModule, mp_sint32 dstIndex, 332 ModuleEditor& srcModule, mp_sint32 srcIndex); 333 334 bool copySample(ModuleEditor& dstModule, mp_sint32 dstInsIndex, mp_sint32 dstIndex, 335 ModuleEditor& srcModule, mp_sint32 srcInsIndex, mp_sint32 srcIndex); 336 bool swapSamples(ModuleEditor& dstModule, mp_sint32 dstInsIndex, mp_sint32 dstIndex, 337 ModuleEditor& srcModule, mp_sint32 srcInsIndex, mp_sint32 srcIndex); 338 339 // get note->sample LUT 340 const mp_ubyte* getSampleTable(mp_sint32 index); 341 342 // update note->sample LUT 343 void updateSampleTable(mp_sint32 index, const mp_ubyte* nbu); 344 345 // update instrument autovibrato / volume fadeout stuff 346 void updateInstrumentData(mp_sint32 index); 347 348 // remap instruments in entire song 349 pp_int32 insRemapSong(pp_int32 oldIns, pp_int32 newIns); 350 351 // transpose notes in entire song 352 pp_int32 noteTransposeSong(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate = false); 353 354 // panning effect conversion 355 enum PanConversionTypes 356 { 357 PanConversionTypeConvert_E8x, 358 PanConversionTypeConvert_80x, 359 PanConversionTypeRemove_E8x, 360 PanConversionTypeRemove_8xx 361 }; 362 363 pp_int32 panConvertSong(PanConversionTypes type); 364 365 // Optimizing features operating on the entire song 366 // -------------------------------------------------------- 367 // remove unused patterns, remapping is always done 368 pp_int32 removeUnusedPatterns(bool evaluate); 369 // remove unused instruments, remapping is optional 370 pp_int32 removeUnusedInstruments(bool evaluate, bool remap); 371 // remove unused samples, no remapping is performed 372 pp_int32 removeUnusedSamples(bool evaluate); 373 374 pp_int32 relocateCommands(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate); 375 pp_int32 zeroOperands(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 376 pp_int32 fillOperands(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 377 378 void optimizeSamples(bool convertTo8Bit, bool minimize, 379 mp_sint32& numConvertedSamples, mp_sint32& numMinimizedSamples, 380 bool evaluate); 381 382 public: 383 static void insertText(char* dst, const char* src, mp_sint32 max); 384 385 static PPSystemString getTempFilename(); 386 387 friend class ChangesListener; 388 }; 389 390 #endif 391