Mercurial > audlegacy
annotate Plugins/Input/adplug/core/s3m.cpp @ 919:c19c3ea7d29d trunk
[svn] - fading fix
| author | nenolod |
|---|---|
| date | Thu, 06 Apr 2006 11:03:26 -0700 |
| parents | 1cd8716972df |
| children | c71e2ef2dcf4 |
| rev | line source |
|---|---|
| 359 | 1 /* |
| 2 * Adplug - Replayer for many OPL2/OPL3 audio file formats. | |
|
843
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
3 * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al. |
| 359 | 4 * |
| 5 * This library is free software; you can redistribute it and/or | |
| 6 * modify it under the terms of the GNU Lesser General Public | |
| 7 * License as published by the Free Software Foundation; either | |
| 8 * version 2.1 of the License, or (at your option) any later version. | |
| 9 * | |
| 10 * This library is distributed in the hope that it will be useful, | |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 * Lesser General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU Lesser General Public | |
| 16 * License along with this library; if not, write to the Free Software | |
| 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 18 * | |
| 19 * s3m.c - S3M Player by Simon Peter <dn.tlp@gmx.net> | |
| 20 * | |
| 21 * BUGS: | |
| 22 * Extra Fine Slides (EEx, FEx) & Fine Vibrato (Uxy) are inaccurate | |
| 23 */ | |
| 24 | |
| 25 #include "s3m.h" | |
| 26 | |
| 27 const char Cs3mPlayer::chnresolv[] = // S3M -> adlib channel conversion | |
| 28 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,-1,-1,-1,-1,-1,-1,-1}; | |
| 29 | |
| 30 const unsigned short Cs3mPlayer::notetable[12] = // S3M adlib note table | |
| 31 {340,363,385,408,432,458,485,514,544,577,611,647}; | |
| 32 | |
| 33 const unsigned char Cs3mPlayer::vibratotab[32] = // vibrato rate table | |
| 34 {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; | |
| 35 | |
| 36 /*** public methods *************************************/ | |
| 37 | |
| 38 CPlayer *Cs3mPlayer::factory(Copl *newopl) | |
| 39 { | |
| 40 return new Cs3mPlayer(newopl); | |
| 41 } | |
| 42 | |
| 43 Cs3mPlayer::Cs3mPlayer(Copl *newopl): CPlayer(newopl) | |
| 44 { | |
| 45 int i,j,k; | |
| 46 | |
| 47 memset(pattern,255,sizeof(pattern)); | |
| 48 memset(orders,255,sizeof(orders)); | |
| 49 | |
| 50 for(i=0;i<99;i++) // setup pattern | |
| 51 for(j=0;j<64;j++) | |
| 52 for(k=0;k<32;k++) { | |
| 53 pattern[i][j][k].instrument = 0; | |
| 54 pattern[i][j][k].info = 0; | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 bool Cs3mPlayer::load(const std::string &filename, const CFileProvider &fp) | |
| 59 { | |
| 60 binistream *f = fp.open(filename); if(!f) return false; | |
| 61 unsigned short insptr[99],pattptr[99]; | |
| 62 int i,row; | |
| 63 unsigned char bufval,bufval2; | |
| 64 unsigned short ppatlen; | |
| 65 s3mheader *checkhead; | |
| 66 bool adlibins=false; | |
| 67 | |
| 68 // file validation section | |
| 69 checkhead = new s3mheader; | |
| 70 load_header(f, checkhead); | |
| 71 if((checkhead->kennung != 0x1a) || (checkhead->typ != 16)) { | |
| 72 delete checkhead; fp.close(f); return false; | |
| 73 } else | |
| 74 if(strncmp(checkhead->scrm,"SCRM",4)) { | |
| 75 delete checkhead; fp.close(f); return false; | |
| 76 } else { // is an adlib module? | |
| 77 f->seek(checkhead->ordnum, binio::Add); | |
| 78 for(i = 0; i < checkhead->insnum; i++) | |
| 79 insptr[i] = f->readInt(2); | |
| 80 for(i=0;i<checkhead->insnum;i++) { | |
| 81 f->seek(insptr[i]*16); | |
| 82 if(f->readInt(1) >= 2) { | |
| 83 adlibins = true; | |
| 84 break; | |
| 85 } | |
| 86 } | |
| 87 delete checkhead; | |
| 88 if(!adlibins) { fp.close(f); return false; } | |
| 89 } | |
| 90 | |
| 91 // load section | |
| 92 f->seek(0); // rewind for load | |
| 93 load_header(f, &header); // read header | |
| 94 for(i = 0; i < header.ordnum; i++) orders[i] = f->readInt(1); // read orders | |
| 95 for(i = 0; i < header.insnum; i++) insptr[i] = f->readInt(2); // instrument parapointers | |
| 96 for(i = 0; i < header.patnum; i++) pattptr[i] = f->readInt(2); // pattern parapointers | |
| 97 | |
| 98 for(i=0;i<header.insnum;i++) { // load instruments | |
| 99 f->seek(insptr[i]*16); | |
| 100 inst[i].type = f->readInt(1); | |
| 101 f->readString(inst[i].filename, 15); | |
| 102 inst[i].d00 = f->readInt(1); inst[i].d01 = f->readInt(1); | |
| 103 inst[i].d02 = f->readInt(1); inst[i].d03 = f->readInt(1); | |
| 104 inst[i].d04 = f->readInt(1); inst[i].d05 = f->readInt(1); | |
| 105 inst[i].d06 = f->readInt(1); inst[i].d07 = f->readInt(1); | |
| 106 inst[i].d08 = f->readInt(1); inst[i].d09 = f->readInt(1); | |
| 107 inst[i].d0a = f->readInt(1); inst[i].d0b = f->readInt(1); | |
| 108 inst[i].volume = f->readInt(1); inst[i].dsk = f->readInt(1); | |
| 109 f->ignore(2); | |
| 110 inst[i].c2spd = f->readInt(4); | |
| 111 f->ignore(12); | |
| 112 f->readString(inst[i].name, 28); | |
| 113 f->readString(inst[i].scri, 4); | |
| 114 } | |
| 115 | |
| 116 for(i=0;i<header.patnum;i++) { // depack patterns | |
| 117 f->seek(pattptr[i]*16); | |
| 118 ppatlen = f->readInt(2); | |
| 119 unsigned long pattpos = f->pos(); | |
| 120 for(row=0;(row<64) && (pattpos-pattptr[i]*16<=ppatlen);row++) | |
| 121 do { | |
| 122 bufval = f->readInt(1); | |
| 123 if(bufval & 32) { | |
| 124 bufval2 = f->readInt(1); | |
| 125 pattern[i][row][bufval & 31].note = bufval2 & 15; | |
| 126 pattern[i][row][bufval & 31].oct = (bufval2 & 240) >> 4; | |
| 127 pattern[i][row][bufval & 31].instrument = f->readInt(1); | |
| 128 } | |
| 129 if(bufval & 64) | |
| 130 pattern[i][row][bufval & 31].volume = f->readInt(1); | |
| 131 if(bufval & 128) { | |
| 132 pattern[i][row][bufval & 31].command = f->readInt(1); | |
| 133 pattern[i][row][bufval & 31].info = f->readInt(1); | |
| 134 } | |
| 135 } while(bufval); | |
| 136 } | |
| 137 | |
| 138 fp.close(f); | |
| 139 rewind(0); | |
| 140 return true; // done | |
| 141 } | |
| 142 | |
| 143 bool Cs3mPlayer::update() | |
| 144 { | |
| 145 unsigned char pattbreak=0,donote; // remember vars | |
| 146 unsigned char pattnr,chan,row,info; // cache vars | |
| 147 signed char realchan; | |
| 148 | |
| 149 // effect handling (timer dependant) | |
| 150 for(realchan=0; realchan<9; realchan++) { | |
| 151 info = channel[realchan].info; // fill infobyte cache | |
| 152 switch(channel[realchan].fx) { | |
| 153 case 11: | |
| 154 case 12: if(channel[realchan].fx == 11) // dual command: H00 and Dxy | |
| 155 vibrato(realchan,channel[realchan].dualinfo); | |
| 156 else // dual command: G00 and Dxy | |
| 157 tone_portamento(realchan,channel[realchan].dualinfo); | |
| 158 case 4: if(info <= 0x0f) // volume slide down | |
| 159 if(channel[realchan].vol - info >= 0) | |
| 160 channel[realchan].vol -= info; | |
| 161 else | |
| 162 channel[realchan].vol = 0; | |
| 163 if((info & 0x0f) == 0) // volume slide up | |
| 164 if(channel[realchan].vol + (info >> 4) <= 63) | |
| 165 channel[realchan].vol += info >> 4; | |
| 166 else | |
| 167 channel[realchan].vol = 63; | |
| 168 setvolume(realchan); | |
| 169 break; | |
| 170 case 5: if(info == 0xf0 || info <= 0xe0) { // slide down | |
| 171 slide_down(realchan,info); | |
| 172 setfreq(realchan); | |
| 173 } | |
| 174 break; | |
| 175 case 6: if(info == 0xf0 || info <= 0xe0) { // slide up | |
| 176 slide_up(realchan,info); | |
| 177 setfreq(realchan); | |
| 178 } | |
| 179 break; | |
| 180 case 7: tone_portamento(realchan,channel[realchan].dualinfo); break; // tone portamento | |
| 181 case 8: vibrato(realchan,channel[realchan].dualinfo); break; // vibrato | |
| 182 case 10: channel[realchan].nextfreq = channel[realchan].freq; // arpeggio | |
| 183 channel[realchan].nextoct = channel[realchan].oct; | |
| 184 switch(channel[realchan].trigger) { | |
| 185 case 0: channel[realchan].freq = notetable[channel[realchan].note]; break; | |
| 186 case 1: if(channel[realchan].note + ((info & 0xf0) >> 4) < 12) | |
| 187 channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4)]; | |
| 188 else { | |
| 189 channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4) - 12]; | |
| 190 channel[realchan].oct++; | |
| 191 } | |
| 192 break; | |
| 193 case 2: if(channel[realchan].note + (info & 0x0f) < 12) | |
| 194 channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f)]; | |
| 195 else { | |
| 196 channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f) - 12]; | |
| 197 channel[realchan].oct++; | |
| 198 } | |
| 199 break; | |
| 200 } | |
| 201 if(channel[realchan].trigger < 2) | |
| 202 channel[realchan].trigger++; | |
| 203 else | |
| 204 channel[realchan].trigger = 0; | |
| 205 setfreq(realchan); | |
| 206 channel[realchan].freq = channel[realchan].nextfreq; | |
| 207 channel[realchan].oct = channel[realchan].nextoct; | |
| 208 break; | |
| 209 case 21: vibrato(realchan,(unsigned char) (info / 4)); break; // fine vibrato | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 if(del) { // speed compensation | |
| 214 del--; | |
| 215 return !songend; | |
| 216 } | |
| 217 | |
| 218 // arrangement handling | |
| 219 pattnr = orders[ord]; | |
| 220 if(pattnr == 0xff || ord > header.ordnum) { // "--" end of song | |
| 221 songend = 1; // set end-flag | |
| 222 ord = 0; | |
| 223 pattnr = orders[ord]; | |
| 224 if(pattnr == 0xff) | |
| 225 return !songend; | |
| 226 } | |
| 227 if(pattnr == 0xfe) { // "++" skip marker | |
| 228 ord++; pattnr = orders[ord]; | |
| 229 } | |
| 230 | |
| 231 // play row | |
| 232 row = crow; // fill row cache | |
| 233 for(chan=0;chan<32;chan++) { | |
| 234 if(!(header.chanset[chan] & 128)) // resolve S3M -> AdLib channels | |
| 235 realchan = chnresolv[header.chanset[chan] & 127]; | |
| 236 else | |
| 237 realchan = -1; // channel disabled | |
| 238 if(realchan != -1) { // channel playable? | |
| 239 // set channel values | |
| 240 donote = 0; | |
| 241 if(pattern[pattnr][row][chan].note < 14) | |
| 242 // tone portamento | |
| 243 if(pattern[pattnr][row][chan].command == 7 || pattern[pattnr][row][chan].command == 12) { | |
| 244 channel[realchan].nextfreq = notetable[pattern[pattnr][row][chan].note]; | |
| 245 channel[realchan].nextoct = pattern[pattnr][row][chan].oct; | |
| 246 } else { // normal note | |
| 247 channel[realchan].note = pattern[pattnr][row][chan].note; | |
| 248 channel[realchan].freq = notetable[pattern[pattnr][row][chan].note]; | |
| 249 channel[realchan].oct = pattern[pattnr][row][chan].oct; | |
| 250 channel[realchan].key = 1; | |
| 251 donote = 1; | |
| 252 } | |
| 253 if(pattern[pattnr][row][chan].note == 14) { // key off (is 14 here, cause note is only first 4 bits) | |
| 254 channel[realchan].key = 0; | |
| 255 setfreq(realchan); | |
| 256 } | |
| 257 if((channel[realchan].fx != 8 && channel[realchan].fx != 11) && // vibrato begins | |
| 258 (pattern[pattnr][row][chan].command == 8 || pattern[pattnr][row][chan].command == 11)) { | |
| 259 channel[realchan].nextfreq = channel[realchan].freq; | |
| 260 channel[realchan].nextoct = channel[realchan].oct; | |
| 261 } | |
| 262 if(pattern[pattnr][row][chan].note >= 14) | |
| 263 if((channel[realchan].fx == 8 || channel[realchan].fx == 11) && // vibrato ends | |
| 264 (pattern[pattnr][row][chan].command != 8 && pattern[pattnr][row][chan].command != 11)) { | |
| 265 channel[realchan].freq = channel[realchan].nextfreq; | |
| 266 channel[realchan].oct = channel[realchan].nextoct; | |
| 267 setfreq(realchan); | |
| 268 } | |
| 269 if(pattern[pattnr][row][chan].instrument) { // set instrument | |
| 270 channel[realchan].inst = pattern[pattnr][row][chan].instrument - 1; | |
| 271 if(inst[channel[realchan].inst].volume < 64) | |
| 272 channel[realchan].vol = inst[channel[realchan].inst].volume; | |
| 273 else | |
| 274 channel[realchan].vol = 63; | |
| 275 if(pattern[pattnr][row][chan].command != 7) | |
| 276 donote = 1; | |
| 277 } | |
| 278 if(pattern[pattnr][row][chan].volume != 255) | |
| 279 if(pattern[pattnr][row][chan].volume < 64) // set volume | |
| 280 channel[realchan].vol = pattern[pattnr][row][chan].volume; | |
| 281 else | |
| 282 channel[realchan].vol = 63; | |
| 283 channel[realchan].fx = pattern[pattnr][row][chan].command; // set command | |
| 284 if(pattern[pattnr][row][chan].info) // set infobyte | |
| 285 channel[realchan].info = pattern[pattnr][row][chan].info; | |
| 286 | |
|
843
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
287 // some commands reset the infobyte memory |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
288 switch(channel[realchan].fx) { |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
289 case 1: |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
290 case 2: |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
291 case 3: |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
292 case 20: |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
293 channel[realchan].info = pattern[pattnr][row][chan].info; |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
294 break; |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
295 } |
|
1cd8716972df
[svn] Sync core with upstream. Also, rename plugin from AdPlug to AdLib synthesizer, by request of Giacomo.
chainsaw
parents:
359
diff
changeset
|
296 |
| 359 | 297 // play note |
| 298 if(donote) | |
| 299 playnote(realchan); | |
| 300 if(pattern[pattnr][row][chan].volume != 255) // set volume | |
| 301 setvolume(realchan); | |
| 302 | |
| 303 // command handling (row dependant) | |
| 304 info = channel[realchan].info; // fill infobyte cache | |
| 305 switch(channel[realchan].fx) { | |
| 306 case 1: speed = info; break; // set speed | |
| 307 case 2: if(info <= ord) songend = 1; ord = info; crow = 0; pattbreak = 1; break; // jump to order | |
| 308 case 3: if(!pattbreak) { crow = info; ord++; pattbreak = 1; } break; // pattern break | |
| 309 case 4: if(info > 0xf0) // fine volume down | |
| 310 if(channel[realchan].vol - (info & 0x0f) >= 0) | |
| 311 channel[realchan].vol -= info & 0x0f; | |
| 312 else | |
| 313 channel[realchan].vol = 0; | |
| 314 if((info & 0x0f) == 0x0f && info >= 0x1f) // fine volume up | |
| 315 if(channel[realchan].vol + ((info & 0xf0) >> 4) <= 63) | |
| 316 channel[realchan].vol += (info & 0xf0) >> 4; | |
| 317 else | |
| 318 channel[realchan].vol = 63; | |
| 319 setvolume(realchan); | |
| 320 break; | |
| 321 case 5: if(info > 0xf0) { // fine slide down | |
| 322 slide_down(realchan,(unsigned char) (info & 0x0f)); | |
| 323 setfreq(realchan); | |
| 324 } | |
| 325 if(info > 0xe0 && info < 0xf0) { // extra fine slide down | |
| 326 slide_down(realchan,(unsigned char) ((info & 0x0f) / 4)); | |
| 327 setfreq(realchan); | |
| 328 } | |
| 329 break; | |
| 330 case 6: if(info > 0xf0) { // fine slide up | |
| 331 slide_up(realchan,(unsigned char) (info & 0x0f)); | |
| 332 setfreq(realchan); | |
| 333 } | |
| 334 if(info > 0xe0 && info < 0xf0) { // extra fine slide up | |
| 335 slide_up(realchan,(unsigned char) ((info & 0x0f) / 4)); | |
| 336 setfreq(realchan); | |
| 337 } | |
| 338 break; | |
| 339 case 7: // tone portamento | |
| 340 case 8: if((channel[realchan].fx == 7 || // vibrato (remember info for dual commands) | |
| 341 channel[realchan].fx == 8) && pattern[pattnr][row][chan].info) | |
| 342 channel[realchan].dualinfo = info; | |
| 343 break; | |
| 344 case 10: channel[realchan].trigger = 0; break; // arpeggio (set trigger) | |
| 345 case 19: if(info == 0xb0) // set loop start | |
| 346 loopstart = row; | |
| 347 if(info > 0xb0 && info <= 0xbf) // pattern loop | |
| 348 if(!loopcnt) { | |
| 349 loopcnt = info & 0x0f; | |
| 350 crow = loopstart; | |
| 351 pattbreak = 1; | |
| 352 } else | |
| 353 if(--loopcnt > 0) { | |
| 354 crow = loopstart; | |
| 355 pattbreak = 1; | |
| 356 } | |
| 357 if((info & 0xf0) == 0xe0) // patterndelay | |
| 358 del = speed * (info & 0x0f) - 1; | |
| 359 break; | |
| 360 case 20: tempo = info; break; // set tempo | |
| 361 } | |
| 362 } | |
| 363 } | |
| 364 | |
| 365 if(!del) | |
| 366 del = speed - 1;// speed compensation | |
| 367 if(!pattbreak) { // next row (only if no manual advance) | |
| 368 crow++; | |
| 369 if(crow > 63) { | |
| 370 crow = 0; | |
| 371 ord++; | |
| 372 loopstart = 0; | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 return !songend; // still playing | |
| 377 } | |
| 378 | |
| 379 void Cs3mPlayer::rewind(int subsong) | |
| 380 { | |
| 381 // set basic variables | |
| 382 songend = 0; ord = 0; crow = 0; tempo = header.it; | |
| 383 speed = header.is; del = 0; loopstart = 0; loopcnt = 0; | |
| 384 | |
| 385 memset(channel,0,sizeof(channel)); | |
| 386 | |
| 387 opl->init(); // reset OPL chip | |
| 388 opl->write(1,32); // Go to ym3812 mode | |
| 389 } | |
| 390 | |
| 391 std::string Cs3mPlayer::gettype() | |
| 392 { | |
| 393 char filever[5]; | |
| 394 | |
| 395 switch(header.cwtv) { // determine version number | |
| 396 case 0x1300: strcpy(filever,"3.00"); break; | |
| 397 case 0x1301: strcpy(filever,"3.01"); break; | |
| 398 case 0x1303: strcpy(filever,"3.03"); break; | |
| 399 case 0x1320: strcpy(filever,"3.20"); break; | |
| 400 default: strcpy(filever,"3.??"); | |
| 401 } | |
| 402 | |
| 403 return (std::string("Scream Tracker ") + filever); | |
| 404 } | |
| 405 | |
| 406 float Cs3mPlayer::getrefresh() | |
| 407 { | |
| 408 return (float) (tempo / 2.5); | |
| 409 } | |
| 410 | |
| 411 /*** private methods *************************************/ | |
| 412 | |
| 413 void Cs3mPlayer::load_header(binistream *f, s3mheader *h) | |
| 414 { | |
| 415 int i; | |
| 416 | |
| 417 f->readString(h->name, 28); | |
| 418 h->kennung = f->readInt(1); h->typ = f->readInt(1); | |
| 419 f->ignore(2); | |
| 420 h->ordnum = f->readInt(2); h->insnum = f->readInt(2); | |
| 421 h->patnum = f->readInt(2); h->flags = f->readInt(2); | |
| 422 h->cwtv = f->readInt(2); h->ffi = f->readInt(2); | |
| 423 f->readString(h->scrm, 4); | |
| 424 h->gv = f->readInt(1); h->is = f->readInt(1); h->it = f->readInt(1); | |
| 425 h->mv = f->readInt(1); h->uc = f->readInt(1); h->dp = f->readInt(1); | |
| 426 f->ignore(8); | |
| 427 h->special = f->readInt(2); | |
| 428 for(i = 0; i < 32; i++) h->chanset[i] = f->readInt(1); | |
| 429 } | |
| 430 | |
| 431 void Cs3mPlayer::setvolume(unsigned char chan) | |
| 432 { | |
| 433 unsigned char op = op_table[chan], insnr = channel[chan].inst; | |
| 434 | |
| 435 opl->write(0x43 + op,(int)(63-((63-(inst[insnr].d03 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d03 & 192)); | |
| 436 if(inst[insnr].d0a & 1) | |
| 437 opl->write(0x40 + op,(int)(63-((63-(inst[insnr].d02 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d02 & 192)); | |
| 438 } | |
| 439 | |
| 440 void Cs3mPlayer::setfreq(unsigned char chan) | |
| 441 { | |
| 442 opl->write(0xa0 + chan, channel[chan].freq & 255); | |
| 443 if(channel[chan].key) | |
| 444 opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); | |
| 445 else | |
| 446 opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); | |
| 447 } | |
| 448 | |
| 449 void Cs3mPlayer::playnote(unsigned char chan) | |
| 450 { | |
| 451 unsigned char op = op_table[chan], insnr = channel[chan].inst; | |
| 452 | |
| 453 opl->write(0xb0 + chan, 0); // stop old note | |
| 454 | |
| 455 // set instrument data | |
| 456 opl->write(0x20 + op, inst[insnr].d00); | |
| 457 opl->write(0x23 + op, inst[insnr].d01); | |
| 458 opl->write(0x40 + op, inst[insnr].d02); | |
| 459 opl->write(0x43 + op, inst[insnr].d03); | |
| 460 opl->write(0x60 + op, inst[insnr].d04); | |
| 461 opl->write(0x63 + op, inst[insnr].d05); | |
| 462 opl->write(0x80 + op, inst[insnr].d06); | |
| 463 opl->write(0x83 + op, inst[insnr].d07); | |
| 464 opl->write(0xe0 + op, inst[insnr].d08); | |
| 465 opl->write(0xe3 + op, inst[insnr].d09); | |
| 466 opl->write(0xc0 + chan, inst[insnr].d0a); | |
| 467 | |
| 468 // set frequency & play | |
| 469 channel[chan].key = 1; | |
| 470 setfreq(chan); | |
| 471 } | |
| 472 | |
| 473 void Cs3mPlayer::slide_down(unsigned char chan, unsigned char amount) | |
| 474 { | |
| 475 if(channel[chan].freq - amount > 340) | |
| 476 channel[chan].freq -= amount; | |
| 477 else | |
| 478 if(channel[chan].oct > 0) { | |
| 479 channel[chan].oct--; | |
| 480 channel[chan].freq = 684; | |
| 481 } else | |
| 482 channel[chan].freq = 340; | |
| 483 } | |
| 484 | |
| 485 void Cs3mPlayer::slide_up(unsigned char chan, unsigned char amount) | |
| 486 { | |
| 487 if(channel[chan].freq + amount < 686) | |
| 488 channel[chan].freq += amount; | |
| 489 else | |
| 490 if(channel[chan].oct < 7) { | |
| 491 channel[chan].oct++; | |
| 492 channel[chan].freq = 341; | |
| 493 } else | |
| 494 channel[chan].freq = 686; | |
| 495 } | |
| 496 | |
| 497 void Cs3mPlayer::vibrato(unsigned char chan, unsigned char info) | |
| 498 { | |
| 499 unsigned char i,speed,depth; | |
| 500 | |
| 501 speed = info >> 4; | |
| 502 depth = (info & 0x0f) / 2; | |
| 503 | |
| 504 for(i=0;i<speed;i++) { | |
| 505 channel[chan].trigger++; | |
| 506 while(channel[chan].trigger >= 64) | |
| 507 channel[chan].trigger -= 64; | |
| 508 if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) | |
| 509 slide_down(chan,(unsigned char) (vibratotab[channel[chan].trigger - 16] / (16-depth))); | |
| 510 if(channel[chan].trigger < 16) | |
| 511 slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger + 16] / (16-depth))); | |
| 512 if(channel[chan].trigger >= 48) | |
| 513 slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger - 48] / (16-depth))); | |
| 514 } | |
| 515 setfreq(chan); | |
| 516 } | |
| 517 | |
| 518 void Cs3mPlayer::tone_portamento(unsigned char chan, unsigned char info) | |
| 519 { | |
| 520 if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + | |
| 521 (channel[chan].nextoct << 10)) | |
| 522 slide_up(chan,info); | |
| 523 if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + | |
| 524 (channel[chan].nextoct << 10)) | |
| 525 slide_down(chan,info); | |
| 526 setfreq(chan); | |
| 527 } |
