1 /* 2 * Copyright (c) 2009, The MilkyTracker Team. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * - Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * - Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * - Neither the name of the <ORGANIZATION> nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * PlayerBase.h 32 * MilkyPlay 33 * 34 * Created by Peter Barth on Thu Jan 20 2005. 35 * 36 */ 37 38 #ifndef __PLAYERBASE_H__ 39 #define __PLAYERBASE_H__ 40 41 #include "ChannelMixer.h" 42 43 class XModule; 44 45 struct TPlayerChannelInfo 46 { 47 mp_ubyte note; 48 mp_ubyte instrument; 49 mp_ubyte volume; 50 mp_ubyte panning; 51 mp_ubyte numeffects; 52 mp_ubyte effects[MP_NUMEFFECTS]; 53 mp_ubyte operands[MP_NUMEFFECTS]; 54 clearTPlayerChannelInfo55 void clear() 56 { 57 memset(this, 0, sizeof(TPlayerChannelInfo)); 58 } 59 }; 60 61 class PlayModeSettings 62 { 63 public: 64 enum PlayModes 65 { 66 PlayMode_Auto, 67 PlayMode_ProTracker2, 68 PlayMode_ProTracker3, 69 PlayMode_ScreamTracker3, 70 PlayMode_FastTracker2, 71 PlayMode_ImpulseTracker 72 }; 73 74 enum PlayModeOptions 75 { 76 PlayModeOptionFirst = 0, 77 PlayModeOptionPanning8xx = 0, 78 PlayModeOptionPanningE8x = 1, 79 // Only affects PTK playback mode 80 PlayModeOptionForcePTPitchLimit = 2, 81 PlayModeOptionLast 82 }; 83 84 protected: 85 bool options[PlayModeOptionLast]; 86 87 PlayModes playMode; 88 }; 89 90 class PlayerBase : public ChannelMixer, public PlayModeSettings 91 { 92 private: 93 struct TimeRecord 94 { 95 enum BITPOSITIONS 96 { 97 BITPOS_POS = 0, 98 BITPOS_ROW = 8, 99 BITPOS_TEMPO = 16, 100 BITPOS_SPEED = 24, 101 102 BITPOS_MAINVOL = 0, 103 BITPOS_TICKER = 8 104 }; 105 106 mp_uint32 posRowTempoSpeed; 107 mp_sint32 mainVolumeTicker; 108 TimeRecordTimeRecord109 TimeRecord() 110 { 111 } 112 TimeRecordTimeRecord113 TimeRecord(mp_uint32 pos, mp_uint32 row, mp_uint32 tempo, mp_uint32 speed, mp_sint32 mainVol, mp_sint32 ticker) : 114 posRowTempoSpeed((pos << BITPOS_POS) + 115 (row << BITPOS_ROW) + 116 (tempo << BITPOS_TEMPO) + 117 (speed << BITPOS_SPEED)), 118 mainVolumeTicker((mainVol << BITPOS_MAINVOL) + 119 (ticker << BITPOS_TICKER)) 120 { 121 } 122 }; 123 124 TimeRecord* timeRecord; 125 reallocTimeRecord()126 void reallocTimeRecord() 127 { 128 delete[] timeRecord; 129 timeRecord = new TimeRecord[getNumBeatPackets()+1]; 130 131 updateTimeRecord(); 132 } 133 updateTimeRecord()134 void updateTimeRecord() 135 { 136 for (mp_uint32 i = 0; i < getNumBeatPackets()+1; i++) 137 { 138 timeRecord[i] = TimeRecord(poscnt, 139 rowcnt, 140 bpm, 141 tickSpeed, 142 mainVolume, 143 ticker); 144 } 145 } 146 147 public: 148 enum PlayerTypes 149 { 150 PlayerType_Generic, // generic module player, can play most of the Protracker style formats 151 PlayerType_FAR, // Farandole composer player 152 PlayerType_IT, // Supposed to be a compatible IT replayer 153 PlayerType_INVALID = -1 // NULL player :D 154 }; 155 156 protected: 157 XModule* module; 158 159 bool paused; // Player is paused 160 bool halted; // Playing has been stopped (song is over) 161 bool repeat; // Player will repeat song 162 bool idle; // Player is mixing, but not processing song 163 bool playOneRowOnly; // Player will only play one row and not advance to the next row (used for milkytracker) 164 bool resetOnStopFlag; 165 bool resetMainVolumeOnStartPlayFlag; 166 167 mp_sint32 initialNumChannels; // Fixed number of channels, can be set manually in StartPlaying 168 // otherwise it will be module->header.channum 169 170 mp_sint32 mainVolume; // current song's main volume 171 172 mp_sint32 tickSpeed; // our tickspeed 173 mp_sint32 baseBpm; // Support digibooster REAL BPM value 174 mp_sint32 bpm; // BPM speed 175 mp_sint32 ticker; // runs from 0 to tickspeed-1 176 177 mp_sint32 rowcnt; // counts through each row in a pattern 178 mp_sint32 poscnt; // counts through each index the pattern index table 179 mp_int64 synccnt; // will increment 250 times per mixed second 180 mp_sint32 lastUnvisitedPos; // the last order we visited before a new order has been set 181 182 mp_uint32 adder, BPMCounter; 183 184 mp_sint32 patternIndexToPlay; // Play special pattern, -1 = Play entire song 185 186 mp_sint32 kick(); 187 allocateStructures()188 virtual mp_sint32 allocateStructures() { return 0; } 189 clearEffectMemory()190 virtual void clearEffectMemory() { } 191 192 public: 193 PlayerBase(mp_uint32 frequency); 194 195 virtual ~PlayerBase(); 196 197 virtual mp_sint32 adjustFrequency(mp_uint32 frequency); 198 virtual mp_sint32 setBufferSize(mp_uint32 bufferSize); 199 setPlayMode(PlayModes mode)200 void setPlayMode(PlayModes mode) { playMode = mode; } 201 getPlayMode()202 PlayModes getPlayMode() const { return playMode; } 203 enable(PlayModeOptions option,bool b)204 void enable(PlayModeOptions option, bool b) 205 { 206 ASSERT(option>=PlayModeOptionFirst && option<PlayModeOptionLast); 207 options[option] = b; 208 } 209 isEnabled(PlayModeOptions option)210 bool isEnabled(PlayModeOptions option) const 211 { 212 ASSERT(option>=PlayModeOptionFirst && option<PlayModeOptionLast); 213 return options[option]; 214 } 215 216 // runtime type identification 217 virtual PlayerTypes getType() const = 0; 218 219 // virtual from mixer class, perform playing here 220 virtual void timerHandler(mp_sint32 currentBeatPacket); 221 222 virtual void restart(mp_uint32 startPosition = 0, 223 mp_uint32 startRow = 0, 224 bool resetMixer = true, 225 const mp_ubyte* customPanningTable = NULL, 226 bool playOneRowOnly = false); 227 reset()228 virtual void reset() {} 229 resetAllSpeed()230 virtual void resetAllSpeed() {} 231 232 virtual mp_sint32 startPlaying(XModule* module, 233 bool repeat = false, 234 mp_uint32 startPosition = 0, 235 mp_uint32 startRow = 0, 236 mp_sint32 numChannels = -1, 237 const mp_ubyte* customPanningTable = NULL, 238 bool idle = false, 239 mp_sint32 patternIndex = -1, 240 bool playOneRowOnly = false); 241 setPatternToPlay(mp_sint32 patternIndex)242 void setPatternToPlay(mp_sint32 patternIndex) { patternIndexToPlay = patternIndex; } getPatternToPlay()243 mp_sint32 getPatternToPlay() const { return patternIndexToPlay; } 244 245 mp_sint32 stopPlaying(); 246 hasSongHalted()247 bool hasSongHalted() const { return halted; } 248 setIdle(bool idle)249 void setIdle(bool idle) { this->idle = idle; } isIdle()250 bool isIdle() const { return idle; } 251 setRepeat(bool repeat)252 virtual void setRepeat(bool repeat) { this->repeat = repeat; } isRepeating()253 bool isRepeating() const { return repeat; } 254 255 mp_sint32 pausePlaying(); 256 mp_sint32 resumePlaying(bool unpause = true); 257 isPaused()258 bool isPaused() const { return paused; } 259 260 // Set song main volume setSongMainVolume(mp_ubyte volume)261 void setSongMainVolume(mp_ubyte volume) { mainVolume = volume; } 262 mp_sint32 getSongMainVolume(mp_uint32 i = 0) const 263 { 264 return (timeRecord[i].mainVolumeTicker >> TimeRecord::BITPOS_MAINVOL) & 255; 265 } 266 267 // Reset sound mixer on song stop resetOnStop(bool b)268 void resetOnStop(bool b) { resetOnStopFlag = b; } 269 // Reset main volume when song is started resetMainVolumeOnStartPlay(bool b)270 void resetMainVolumeOnStartPlay(bool b) { resetMainVolumeOnStartPlayFlag = b; } 271 272 virtual mp_sint32 getOrder(mp_uint32 i = 0) const 273 { 274 return (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_POS) & 255; 275 } 276 277 virtual mp_sint32 getRow(mp_uint32 i = 0) const 278 { 279 return (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_ROW) & 255; 280 } 281 282 virtual void getPosition(mp_sint32& order, mp_sint32& row, mp_uint32 i = 0) const 283 { 284 order = (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_POS) & 255; 285 row = (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_ROW) & 255; 286 } 287 getLastUnvisitedPosition()288 virtual mp_sint32 getLastUnvisitedPosition() const { return lastUnvisitedPos; } 289 290 virtual void getPosition(mp_sint32& order, mp_sint32& row, mp_sint32& ticker, mp_uint32 i = 0) const 291 { 292 order = (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_POS) & 255; 293 row = (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_ROW) & 255; 294 ticker = (timeRecord[i].mainVolumeTicker >> TimeRecord::BITPOS_TICKER) & 255; 295 } 296 getSyncCount()297 virtual mp_int64 getSyncCount() const { return synccnt; } 298 299 virtual void nextPattern(); 300 virtual void lastPattern(); 301 virtual void setPatternPos(mp_uint32 pos, mp_uint32 row = 0, bool resetChannels = true, bool resetFXMemory = true); 302 setTempo(mp_sint32 tempo)303 virtual void setTempo(mp_sint32 tempo) 304 { 305 bpm = tempo; 306 updateTimeRecord(); 307 } 308 setSpeed(mp_sint32 speed)309 virtual void setSpeed(mp_sint32 speed) 310 { 311 if (speed != tickSpeed) 312 { 313 tickSpeed = speed; 314 if (ticker >= speed) 315 ticker = 0; 316 updateTimeRecord(); 317 } 318 } 319 320 virtual mp_sint32 getTempo(mp_uint32 i = 0) const 321 { 322 if (isPlaying() && !isIdle()) 323 { 324 return (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_TEMPO) & 255; 325 } 326 return bpm; 327 } 328 329 virtual mp_sint32 getSpeed(mp_uint32 i = 0) const 330 { 331 if (isPlaying() && !isIdle()) 332 { 333 return (timeRecord[i].posRowTempoSpeed >> TimeRecord::BITPOS_SPEED) & 255;; 334 } 335 return tickSpeed; 336 } 337 grabChannelInfo(mp_sint32 chn,TPlayerChannelInfo & channelInfo)338 virtual bool grabChannelInfo(mp_sint32 chn, TPlayerChannelInfo& channelInfo) const 339 { 340 channelInfo.clear(); 341 return false; 342 } 343 344 // milkytracker 345 virtual void playNote(mp_ubyte chn, 346 mp_sint32 note, mp_sint32 ins, mp_sint32 vol = -1) {} 347 setPanning(mp_ubyte chn,mp_ubyte pan)348 virtual void setPanning(mp_ubyte chn, mp_ubyte pan) {} 349 }; 350 351 #endif 352