00001
00002
00003
00004
00005 #include "samples.h"
00006 #include "6581_.h"
00007 #include "6510_.h"
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 static const ubyte SO_LOWHIGH = 0;
00025 static const ubyte SO_HIGHLOW = 1;
00026
00027 static const sbyte galwayNoiseTab1[16] =
00028 {
00029 0x80u,0x91u,0xa2u,0xb3u,0xc4u,0xd5u,0xe6u,0xf7u,
00030 0x08u,0x19u,0x2au,0x3bu,0x4cu,0x5du,0x6eu,0x7fu
00031 };
00032
00033 static const sbyte sampleConvertTab[16] =
00034 {
00035
00036
00037 0x81u,0x90u,0xa0u,0xb0u,0xc0u,0xd0u,0xe0u,0xf0u,
00038 0x00u,0x10u,0x20u,0x30u,0x40u,0x50u,0x60u,0x70u
00039 };
00040
00041
00042
00043
00044
00045
00046 Sample::Sample(C6510* a6510)
00050 {
00051 CTOR(Sample);
00052
00053 sampleEmuRout = &Sample::sampleEmuSilence;
00054
00055 c64mem1 = a6510->c64mem1;
00056 c64mem2 = a6510->c64mem2;
00057 }
00058
00059
00060 Sample::~Sample()
00064 {
00065 DTOR(Sample);
00066 }
00067
00068
00069 void Sample::channelReset(sampleChannel& ch)
00070 {
00071 ch.Active = false;
00072 ch.Mode = FM_NONE;
00073 ch.Period = 0;
00074 #if defined(DIRECT_FIXPOINT)
00075 ch.Pos_stp.l = 0;
00076 #elif defined(PORTABLE_FIXPOINT)
00077 ch.Pos_stp = (ch.Pos_pnt = 0);
00078 #else
00079 ch.Pos_stp = 0;
00080 #endif
00081 }
00082
00083 inline void Sample::channelFree(sampleChannel& ch, const uword regBase)
00084 {
00085 ch.Active = false;
00086 ch.Mode = FM_NONE;
00087 c64mem2[regBase+0x1d] = 0x00;
00088 }
00089
00090 inline void Sample::channelTryInit(sampleChannel& ch, const uword regBase)
00091 {
00092 if ( ch.Active && ( ch.Mode == FM_GALWAYON ))
00093 return;
00094
00095 ch.VolShift = ( 0 - (sbyte)c64mem2[regBase+0x1d] ) >> 1;
00096 c64mem2[regBase+0x1d] = 0x00;
00097 ch.Address = readLEword(c64mem2+regBase+0x1e);
00098 ch.EndAddr = readLEword(c64mem2+regBase+0x3d);
00099 if (ch.EndAddr <= ch.Address)
00100 {
00101 return;
00102 }
00103 ch.Repeat = c64mem2[regBase+0x3f];
00104 ch.RepAddr = readLEword(c64mem2+regBase+0x7e);
00105 ch.SampleOrder = c64mem2[regBase+0x7d];
00106 uword tempPeriod = readLEword(c64mem2+regBase+0x5d);
00107 if ( (ch.Scale=c64mem2[regBase+0x5f]) != 0 )
00108 {
00109 tempPeriod >>= ch.Scale;
00110 }
00111 if ( tempPeriod == 0 )
00112 {
00113 ch.Period = 0;
00114 #if defined(DIRECT_FIXPOINT)
00115 ch.Pos_stp.l = (ch.PosAdd_stp.l = 0);
00116 #elif defined(PORTABLE_FIXPOINT)
00117 ch.Pos_stp = (ch.Pos_pnt = 0);
00118 ch.PosAdd_stp = (ch.PosAdd_pnt = 0);
00119 #else
00120 ch.Pos_stp = (ch.PosAdd_stp = 0);
00121 #endif
00122 ch.Active = false;
00123 ch.Mode = FM_NONE;
00124 }
00125 else
00126 {
00127 if ( tempPeriod != ch.Period )
00128 {
00129 ch.Period = tempPeriod;
00130 #if defined(DIRECT_FIXPOINT)
00131 ch.Pos_stp.l = sampleClock / ch.Period;
00132 #elif defined(PORTABLE_FIXPOINT)
00133 udword tempDiv = sampleClock / ch.Period;
00134 ch.Pos_stp = tempDiv >> 16;
00135 ch.Pos_pnt = tempDiv & 0xFFFF;
00136 #else
00137 ch.Pos_stp = sampleClock / ch.Period;
00138 #endif
00139 }
00140 #if defined(DIRECT_FIXPOINT)
00141 ch.PosAdd_stp.l = 0;
00142 #elif defined(PORTABLE_FIXPOINT)
00143 ch.PosAdd_stp = (ch.PosAdd_pnt = 0);
00144 #else
00145 ch.PosAdd_stp = 0;
00146 #endif
00147 ch.Active = true;
00148 ch.Mode = FM_HUELSON;
00149 }
00150 }
00151
00152 inline ubyte Sample::channelProcess(sampleChannel& ch, const uword regBase)
00153 {
00154 #if defined(DIRECT_FIXPOINT)
00155 uword sampleIndex = ch.PosAdd_stp.w[HI] + ch.Address;
00156 #elif defined(PORTABLE_FIXPOINT)
00157 uword sampleIndex = ch.PosAdd_stp + ch.Address;
00158 #else
00159 uword sampleIndex = (ch.PosAdd_stp >> 16) + ch.Address;
00160 #endif
00161 if ( sampleIndex >= ch.EndAddr )
00162 {
00163 if ( ch.Repeat != 0xFF )
00164 {
00165 if ( ch.Repeat != 0 )
00166 ch.Repeat--;
00167 else
00168 {
00169 channelFree(ch,regBase);
00170 return 8;
00171 }
00172 }
00173 sampleIndex = ( ch.Address = ch.RepAddr );
00174 #if defined(DIRECT_FIXPOINT)
00175 ch.PosAdd_stp.l = 0;
00176 #elif defined(PORTABLE_FIXPOINT)
00177 ch.PosAdd_stp = (ch.PosAdd_pnt = 0);
00178 #else
00179 ch.PosAdd_stp = 0;
00180 #endif
00181 if ( sampleIndex >= ch.EndAddr )
00182 {
00183 channelFree(ch,regBase);
00184 return 8;
00185 }
00186 }
00187
00188 ubyte tempSample = c64mem1[sampleIndex];
00189 if (ch.SampleOrder == SO_LOWHIGH)
00190 {
00191 if (ch.Scale == 0)
00192 {
00193 #if defined(DIRECT_FIXPOINT)
00194 if (ch.PosAdd_stp.w[LO] >= 0x8000)
00195 #elif defined(PORTABLE_FIXPOINT)
00196 if ( ch.PosAdd_pnt >= 0x8000 )
00197 #else
00198 if ( (ch.PosAdd_stp & 0x8000) != 0 )
00199 #endif
00200 {
00201 tempSample >>= 4;
00202 }
00203 }
00204
00205 }
00206 else
00207 {
00208 if (ch.Scale == 0)
00209 {
00210 #if defined(DIRECT_FIXPOINT)
00211 if ( ch.PosAdd_stp.w[LO] < 0x8000 )
00212 #elif defined(PORTABLE_FIXPOINT)
00213 if ( ch.PosAdd_pnt < 0x8000 )
00214 #else
00215 if ( (ch.PosAdd_stp & 0x8000) == 0 )
00216 #endif
00217 {
00218 tempSample >>= 4;
00219 }
00220
00221 }
00222 else
00223 {
00224 tempSample >>= 4;
00225 }
00226 }
00227
00228 #if defined(DIRECT_FIXPOINT)
00229 ch.PosAdd_stp.l += ch.Pos_stp.l;
00230 #elif defined(PORTABLE_FIXPOINT)
00231 udword temp = (udword)ch.PosAdd_pnt + (udword)ch.Pos_pnt;
00232 ch.PosAdd_pnt = temp & 0xffff;
00233 ch.PosAdd_stp += ( ch.Pos_stp + ( temp > 65535 ));
00234 #else
00235 ch.PosAdd_stp += ch.Pos_stp;
00236 #endif
00237
00238 return (tempSample&0x0F);
00239 }
00240
00241
00242
00243 void Sample::sampleEmuReset(sidEmu* aTheSidEmu)
00247 {
00248 channelReset(ch4);
00249 channelReset(ch5);
00250
00251
00252 sampleClock = (udword) (((aTheSidEmu->C64_clockSpeed / 2) / aTheSidEmu->PCMfreq) * 65536L);
00253 sampleEmuRout = &Sample::sampleEmuSilence;
00254 if ( c64mem2 != 0 )
00255 {
00256 channelFree(ch4,0xd400);
00257 channelFree(ch5,0xd500);
00258 }
00259 }
00260
00261 ;
00262
00263 void Sample::sampleEmuInit(sidEmu* aTheSidEmu)
00267 {
00268 int k = 0;
00269 for ( int i = 0; i < 16; i++ )
00270 {
00271 int l = 0;
00272 for ( int j = 0; j < 64; j++ )
00273 {
00274 galwayNoiseTab2[k++] = galwayNoiseTab1[l];
00275 l = (l+i) & 15;
00276 }
00277 }
00278 sampleEmuReset(aTheSidEmu);
00279 }
00280
00281 sbyte Sample::sampleEmuSilence()
00282 {
00283 return 0;
00284 }
00285
00286 inline void Sample::sampleEmuTryStopAll()
00287 {
00288 if ( !ch4.Active && !ch5.Active )
00289 {
00290 sampleEmuRout = &Sample::sampleEmuSilence;
00291 }
00292 }
00293
00294 void Sample::sampleEmuCheckForInit()
00295 {
00296
00297 switch ( c64mem2[0xd41d] )
00298 {
00299 case 0xFF:
00300 case 0xFE:
00301 channelTryInit(ch4,0xd400);
00302 break;
00303 case 0xFD:
00304 channelFree(ch4,0xd400);
00305 break;
00306 case 0xFC:
00307 channelTryInit(ch4,0xd400);
00308 break;
00309 case 0x00:
00310 break;
00311 default:
00312 GalwayInit();
00313 break;
00314 }
00315
00316 if (ch4.Mode == FM_HUELSON)
00317 {
00318 sampleEmuRout = &Sample::sampleEmu;
00319 }
00320
00321
00322 switch ( c64mem2[0xd51d] )
00323 {
00324 case 0xFF:
00325 case 0xFE:
00326 channelTryInit(ch5,0xd500);
00327 break;
00328 case 0xFD:
00329 channelFree(ch5,0xd500);
00330 break;
00331 case 0xFC:
00332 channelTryInit(ch5,0xd500);
00333 break;
00334 default:
00335 break;
00336 }
00337
00338 if (ch5.Mode == FM_HUELSON)
00339 {
00340 sampleEmuRout = &Sample::sampleEmuTwo;
00341 }
00342 sampleEmuTryStopAll();
00343 }
00344
00345 sbyte Sample::sampleEmu()
00346 {
00347
00348 if ( !ch4.Active )
00349 return 0;
00350 else
00351 return (sampleConvertTab[channelProcess(ch4,0xd400)]>>ch4.VolShift);
00352 }
00353
00354 sbyte Sample::sampleEmuTwo()
00355 {
00356 sbyte sample = 0;
00357 if ( ch4.Active )
00358 sample += (sampleConvertTab[channelProcess(ch4,0xd400)]>>ch4.VolShift);
00359 if ( ch5.Active )
00360 sample += (sampleConvertTab[channelProcess(ch5,0xd500)]>>ch5.VolShift);
00361 return sample;
00362 }
00363
00364
00365
00366 inline void Sample::GetNextFour()
00367 {
00368 uword tempMul = (uword)(c64mem1[ch4.Address+(uword)ch4.Counter])
00369 * ch4.LoopWait + ch4.NullWait;
00370 ch4.Counter--;
00371 #if defined(DIRECT_FIXPOINT)
00372 if ( tempMul != 0 )
00373 ch4.Period_stp.l = sampleClock / tempMul;
00374 else
00375 ch4.Period_stp.l = 0;
00376 #elif defined(PORTABLE_FIXPOINT)
00377 udword tempDiv;
00378 if ( tempMul != 0 )
00379 tempDiv = sampleClock / tempMul;
00380 else
00381 tempDiv = 0;
00382 ch4.Period_stp = tempDiv >> 16;
00383 ch4.Period_pnt = tempDiv & 0xFFFF;
00384 #else
00385 if ( tempMul != 0 )
00386 ch4.Period_stp = sampleClock / tempMul;
00387 else
00388 ch4.Period_stp = 0;
00389 #endif
00390 ch4.Period = tempMul;
00391 }
00392
00393 void Sample::GalwayInit()
00394 {
00395 if (ch4.Active)
00396 return;
00397
00398 sampleEmuRout = &Sample::sampleEmuSilence;
00399
00400 ch4.Counter = c64mem2[0xd41d];
00401 c64mem2[0xd41d] = 0;
00402
00403 if ((ch4.Address=readLEword(c64mem2+0xd41e)) == 0)
00404 return;
00405
00406 if ((ch4.LoopWait=c64mem2[0xd43f]) == 0)
00407 return;
00408
00409 if ((ch4.NullWait=c64mem2[0xd45d]) == 0)
00410 return;
00411
00412 if (c64mem2[0xd43e] == 0)
00413 return;
00414 ch4.SamAddr = ((uword)c64mem2[0xd43e]&15) << 6;
00415
00416 if ( c64mem2[0xd43d] == 0 )
00417 return;
00418 ch4.SamLen = (((uword)c64mem2[0xd43d])+1) & 0xfffe;
00419
00420 ch4.Active = true;
00421 ch4.Mode = FM_GALWAYON;
00422
00423
00424 #if defined(DIRECT_FIXPOINT)
00425 ch4.Pos_stp.l = 0;
00426 #elif defined(PORTABLE_FIXPOINT)
00427 ch4.Pos_stp = 0;
00428 ch4.Pos_pnt = 0;
00429 #else
00430 ch4.Pos_stp = 0;
00431 #endif
00432
00433 GetNextFour();
00434 ch4.Counter++;
00435
00436 sampleEmuRout = &Sample::GalwayReturnSample;
00437 }
00438
00439 sbyte Sample::GalwayReturnSample()
00440 {
00441 #if defined(DIRECT_FIXPOINT)
00442 sbyte tempSample = galwayNoiseTab2[ ch4.SamAddr + (ch4.Pos_stp.w[HI] & 15) ];
00443 #elif defined(PORTABLE_FIXPOINT)
00444 sbyte tempSample = galwayNoiseTab2[ ch4.SamAddr + ( ch4.Pos_stp & 15 )];
00445 #else
00446 sbyte tempSample = galwayNoiseTab2[ ch4.SamAddr + ((ch4.Pos_stp >> 16) & 15) ];
00447 #endif
00448
00449 #if defined(DIRECT_FIXPOINT)
00450 ch4.Pos_stp.l += ch4.Period_stp.l;
00451 #elif defined(PORTABLE_FIXPOINT)
00452 udword temp = (udword)ch4.Pos_pnt;
00453 temp += (udword)ch4.Period_pnt;
00454 ch4.Pos_pnt = temp & 0xffff;
00455 ch4.Pos_stp += ( ch4.Period_stp + ( temp > 65535 ));
00456 #else
00457 ch4.Pos_stp += ch4.Period_stp;
00458 #endif
00459
00460 #if defined(DIRECT_FIXPOINT)
00461 if ( ch4.Pos_stp.w[HI] >= ch4.SamLen )
00462 #elif defined(PORTABLE_FIXPOINT)
00463 if ( ch4.Pos_stp >= ch4.SamLen )
00464 #else
00465 if ( (ch4.Pos_stp >> 16) >= ch4.SamLen )
00466 #endif
00467 {
00468 #if defined(DIRECT_FIXPOINT)
00469 ch4.Pos_stp.w[HI] = 0;
00470 #elif defined(PORTABLE_FIXPOINT)
00471 ch4.Pos_stp = 0;
00472 #else
00473 ch4.Pos_stp &= 0xFFFF;
00474 #endif
00475
00476 GetNextFour();
00477 if ( ch4.Counter == 0xff ) {
00478
00479
00480 ch4.Active = false;
00481 ch4.Mode = FM_GALWAYOFF;
00482 sampleEmuRout = &Sample::sampleEmuSilence;
00483 }
00484 }
00485 return tempSample;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498