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 };