1 /** 2 * This file is part of the Web Enabled Audio and Sound Enhancement Library (aka the Weasel audio library) Copyright 2011 - 2013 Warren Willmey. It is covered by the GNU General Public License version 3 as published by the Free Software Foundation, you should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. 3 */ 4 5 if( undefined == window.weasel ) window.weasel = {}; 6 7 // --------------------------------------------------------------------------- 8 /** Object to contain a single Instrument from the Ultimate Soundtracker module, 9 * the Instrument contains the sample associated with it. 10 * 11 * @constructor 12 * @param {weasel.UltimateSoundTracker121|weasel.UltimateSoundTracker18|weasel.DOCSoundTracker9|weasel.DOCSoundTracker22|weasel.TJCSoundTracker2|weasel.DefJamSoundTracker3|weasel.SpreadpointSoundTracker23|weasel.SpreadpointSoundTracker25|weasel.NoiseTracker11|weasel.NoiseTracker20|weasel.ProTrackerMK|weasel.FSTModule} oModule = The module containing the instruments. 13 * @param {int} iInstrumentNumber = The number of the instrument to construct from the module data. 14 * @param {weasel.Sample.prototype.SampleScannerMode} iSampleScannerMode = Scan for IFF Header corruption residue?. 15 * @param {bool} bNoisetrackerInstrument = True : Instrument is to become a Noisetracker/Protracker instrument where as the Sample Loop Offset/Repeat Offset is stored in words not bytes. False : Repeat Offset is in bytes as used in Ultimate Soundtracker 1.21. 16 * @param {bool} bNoiseTrackerLoopQuirk = True : Instrument is to use Noisetracker/Protracker loop quirk mode which Taketracker/Fasttracker does not support. 17 * @param {bool} bProtrackerFineTuning = True : Instrument is to support the use of Protrackers Fine Tuning. 18 * 19 * @author Warren Willmey 2011. 20 */ 21 weasel.Instrument = function( oModule, iInstrumentNumber, iSampleScannerMode, bNoisetrackerInstrument, bNoiseTrackerLoopQuirk, bProtrackerFineTuning ){ 22 23 this.sName = ''; 24 this.iVolume = 0; 25 this.iLengthInWords = 0; 26 this.iLoopOffsetInBytes = 0; 27 this.iLoopLengthInWords = 0; 28 this.iFineTuning = 0; 29 this.bNoisetrackerInstrument = bNoisetrackerInstrument; 30 this.bNoiseTrackerLoopQuirk = bNoiseTrackerLoopQuirk; 31 this.bProtrackerFineTuning = bProtrackerFineTuning; 32 33 this.oSample = null; 34 35 this.__extractInstrumentFromMod( oModule, iInstrumentNumber ); 36 37 if( bNoisetrackerInstrument ) 38 { 39 this.iLoopOffsetInBytes *= 2; 40 } 41 42 try 43 { 44 this.oSample = new weasel.Sample( this, oModule, iInstrumentNumber, iSampleScannerMode ); 45 }catch( oException ){}; 46 }; 47 48 // --------------------------------------------------------------------------- 49 /** 50 * Extract Instrument details from the Ultimate Soundtracker 1.21 module. 51 * 52 * @param {weasel.UltimateSoundTracker121|weasel.UltimateSoundTracker18|weasel.DOCSoundTracker9|weasel.DOCSoundTracker22|weasel.TJCSoundTracker2|weasel.DefJamSoundTracker3|weasel.SpreadpointSoundTracker23|weasel.SpreadpointSoundTracker25|weasel.NoiseTracker11|weasel.NoiseTracker20|weasel.ProTrackerMK|weasel.FSTModule} oModule = Soundtracker module object. 53 * @param {int} iInstrumentNumber = The Instrument number to extract (0-14 range, which is 15 different instruments). 54 * 55 * @private 56 */ 57 weasel.Instrument.prototype.__extractInstrumentFromMod = function( oModule, iInstrumentNumber ) 58 { 59 var aModuleData = oModule.getModuleData(); 60 if( aModuleData.length < oModule.FormatModuleHeaderSize() ) 61 return; 62 63 // Instrument 0 does not actually exist, its instruments 1 to 15 for Ultimate Soundtracker 1 to 31 for M.K. Soundtrackers. 64 // 65 if( iInstrumentNumber == 0 || iInstrumentNumber > oModule.FormatInstrumentTotal() ) 66 return; 67 68 iInstrumentNumber--; 69 try 70 { 71 // The first 22 bytes of the sample header are the instrument name, which is padded with NULLs. 72 // 73 var iInstrumentOffset = weasel.FormatUltimateSoundTracker121.SampleHeaders + (iInstrumentNumber * weasel.FormatUltimateSoundTracker121.SampleHeader.HeaderSize); 74 this.sName = weasel.Helper.getNullTerminatedString( aModuleData, iInstrumentOffset + weasel.FormatUltimateSoundTracker121.SampleHeader.SampleName, weasel.FormatUltimateSoundTracker121.SampleHeader.MaxNameLength ); 75 76 this.iLengthInWords = weasel.Helper.getWord( aModuleData, iInstrumentOffset + weasel.FormatUltimateSoundTracker121.SampleHeader.LengthInWords ); 77 this.iVolume = weasel.Helper.getWord( aModuleData, iInstrumentOffset + weasel.FormatUltimateSoundTracker121.SampleHeader.Volume ) & 0xff; 78 this.iLoopOffsetInBytes = weasel.Helper.getWord( aModuleData, iInstrumentOffset + weasel.FormatUltimateSoundTracker121.SampleHeader.RepeatOffsetInBytes ); 79 this.iLoopLengthInWords = weasel.Helper.getWord( aModuleData, iInstrumentOffset + weasel.FormatUltimateSoundTracker121.SampleHeader.RepeatLengthInWords ); 80 81 if( this.bProtrackerFineTuning ) 82 { 83 this.iFineTuning = (weasel.Helper.getWord( aModuleData, iInstrumentOffset + weasel.FormatUltimateSoundTracker121.SampleHeader.Volume ) >> 8) & 0xf; 84 } 85 86 }catch( oException ){}; 87 }; 88 89 90 // --------------------------------------------------------------------------- 91 /** Get the name of the instrument. 92 * 93 * @return {String} The name of the instrument as stored in the module. 94 */ 95 weasel.Instrument.prototype.getName = function() 96 { 97 return this.sName; 98 }; 99 100 // --------------------------------------------------------------------------- 101 /** Get the volume of the instrument. 102 * 103 * @return {int} Volume of the instrument (0-64, 0 being silent, 64 being maximum volume). 104 */ 105 weasel.Instrument.prototype.getVolume = function() 106 { 107 return this.iVolume; 108 }; 109 110 // --------------------------------------------------------------------------- 111 /** Get the length, in words (sample pairs), of the sample, you may be looking to use Sample.getLength() instead. 112 * 113 * @return {int} The length of the sample in words (sample pairs). 114 */ 115 weasel.Instrument.prototype.getLengthInWords = function() 116 { 117 return this.iLengthInWords; 118 }; 119 120 // --------------------------------------------------------------------------- 121 /** Get the loop starting offset in bytes/samples, you may be looking to use Sample.getLoopStart() instead. 122 * 123 * @return {int} The loop starting offset in bytes/samples. 124 */ 125 weasel.Instrument.prototype.getLoopOffsetInBytes = function() 126 { 127 return this.iLoopOffsetInBytes; 128 }; 129 130 // --------------------------------------------------------------------------- 131 /** Get the loop length in words (sample pairs), you may be looking to use Sample.getLoopLength() instead. 132 * 133 * @return {int} The loop length in words (sample pairs). 134 */ 135 weasel.Instrument.prototype.getLoopLengthInWords = function() 136 { 137 return this.iLoopLengthInWords; 138 }; 139 140 // --------------------------------------------------------------------------- 141 /** Get the Sample object associated with this instrument. 142 * 143 * @return {weasel.Sample} The Sample belonging to this instrument. 144 */ 145 weasel.Instrument.prototype.getSample = function() 146 { 147 return this.oSample; 148 }; 149 150 // --------------------------------------------------------------------------- 151 /** Is this a Noistracker instrument (looped samples play differently, they do 152 * not start from the loop start, but start from the beginning of the sample and then loop). 153 * 154 * @return {weasel.Sample} The Sample belonging to this instrument. 155 */ 156 weasel.Instrument.prototype.isNoisetrackerInstrument = function() 157 { 158 return this.bNoisetrackerInstrument; 159 }; 160 161 162 //--------------------------------------------------------------------------- 163 /** Noisetracker introduced a loop quirk (also in protracker) which is an additional 164 * loop mode where the entire sample is played first and then the loop is played 165 * but this only happens if the loop start point is set at zero. 166 * Handle this by copying the loop to the end of the sample data if the 167 * loop length is not the whole sample. 168 * However TakeTracker & Fasttracker DO NOT have this feature (as its related to 169 * the Amiga sound hardware). 170 * 171 * @return {weasel.Sample} The Sample belonging to this instrument. 172 */ 173 weasel.Instrument.prototype.useNoisetrackerLoopQuirk = function() 174 { 175 return this.bNoiseTrackerLoopQuirk; 176 }; 177 178 // --------------------------------------------------------------------------- 179 /** Get the fine tuning value of this instrument. 180 * 181 * @return {int} The fine tuning value [ 0-15 in two complement form]. 182 */ 183 weasel.Instrument.prototype.getFineTuning = function() 184 { 185 return this.iFineTuning; 186 };