Mercurial > codedump
comparison win95kggui/dep/ft2play/pmp_mix.c @ 126:8e4ee43d3b81
remove submodules
| author | Paper <mrpapersonic@gmail.com> |
|---|---|
| date | Sun, 01 Oct 2023 03:48:43 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 125:5cc85ef3a675 | 126:8e4ee43d3b81 |
|---|---|
| 1 #include <stdint.h> | |
| 2 #include <stdbool.h> | |
| 3 #include <stdlib.h> | |
| 4 #include <string.h> | |
| 5 #include <math.h> | |
| 6 #include "pmplay.h" | |
| 7 #include "pmp_main.h" | |
| 8 #include "snd_masm.h" | |
| 9 #include "tables.h" | |
| 10 | |
| 11 // fast 32-bit -> 16-bit clamp | |
| 12 #define CLAMP16(i) if ((int16_t)(i) != i) i = 0x7FFF ^ (i >> 31) | |
| 13 | |
| 14 static bool dump_Flag; | |
| 15 static int32_t oldReplayRate; | |
| 16 | |
| 17 // globalized | |
| 18 int16_t chnReloc[32]; | |
| 19 int32_t *CDA_MixBuffer = NULL; | |
| 20 CIType CI[32 * 2]; | |
| 21 // ------------ | |
| 22 | |
| 23 static void mix_UpdateChannel(int32_t nr, WaveChannelInfoType *WCI); | |
| 24 | |
| 25 void P_SetSpeed(uint16_t bpm) | |
| 26 { | |
| 27 // 8bb: added this | |
| 28 if (bpm == 0) | |
| 29 bpm = 125; | |
| 30 | |
| 31 speedVal = ((realReplayRate + realReplayRate) + (realReplayRate >> 1)) / bpm; // 8bb: same as doing "((realReplayRate * 5) / 2) / bpm" | |
| 32 } | |
| 33 | |
| 34 void P_StartTone(sampleTyp *s, int32_t smpStartPos) | |
| 35 { | |
| 36 WaveChannelInfoType WCI; | |
| 37 | |
| 38 WCI.SStartPos = smpStartPos; | |
| 39 WCI.SBase = s->pek; | |
| 40 WCI.SLen = s->len; | |
| 41 WCI.SRepS = s->repS; | |
| 42 WCI.SRepL = s->repL; | |
| 43 WCI.SType = s->typ; | |
| 44 WCI.Status = Status_StartTone+Status_StopTone; | |
| 45 | |
| 46 mix_UpdateChannel(PMPTmpActiveChannel, &WCI); | |
| 47 } | |
| 48 | |
| 49 // 8bb: added these two | |
| 50 bool mix_Init(int32_t audioBufferSize) | |
| 51 { | |
| 52 CDA_MixBuffer = (int32_t *)malloc(audioBufferSize * 2 * sizeof (int32_t)); | |
| 53 if (CDA_MixBuffer == NULL) | |
| 54 return false; | |
| 55 | |
| 56 PMPLeft = 0; | |
| 57 return true; | |
| 58 } | |
| 59 | |
| 60 void mix_Free(void) | |
| 61 { | |
| 62 if (CDA_MixBuffer != NULL) | |
| 63 { | |
| 64 free(CDA_MixBuffer); | |
| 65 CDA_MixBuffer = NULL; | |
| 66 } | |
| 67 } | |
| 68 // -------------------- | |
| 69 | |
| 70 static void updateVolume(CIType *v, int32_t volIPLen) | |
| 71 { | |
| 72 const uint32_t vol = v->SVol * CDA_Amp; | |
| 73 | |
| 74 v->SLVol1 = (vol * panningTab[256-v->SPan]) >> (32-28); | |
| 75 v->SRVol1 = (vol * panningTab[ v->SPan]) >> (32-28); | |
| 76 | |
| 77 if (volumeRampingFlag) | |
| 78 { | |
| 79 v->SLVolIP = (v->SLVol1 - v->SLVol2) / volIPLen; | |
| 80 v->SRVolIP = (v->SRVol1 - v->SRVol2) / volIPLen; | |
| 81 v->SVolIPLen = volIPLen; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 static void mix_UpdateChannel(int32_t nr, WaveChannelInfoType *WCI) | |
| 86 { | |
| 87 CIType *v = &CI[chnReloc[nr]]; | |
| 88 const uint8_t status = WCI->Status; | |
| 89 | |
| 90 if (status & Status_StopTone) | |
| 91 { | |
| 92 if (volumeRampingFlag) | |
| 93 { | |
| 94 // 8bb: fade out current voice | |
| 95 v->SType |= SType_Fadeout; | |
| 96 v->SVol = 0; | |
| 97 updateVolume(v, quickVolSizeVal); | |
| 98 | |
| 99 // 8bb: swap current voice with neighbor | |
| 100 chnReloc[nr] ^= 1; | |
| 101 v = &CI[chnReloc[nr]]; | |
| 102 } | |
| 103 | |
| 104 v->SType = SType_Off; | |
| 105 } | |
| 106 | |
| 107 if (status & Status_SetPan) | |
| 108 v->SPan = (uint8_t)WCI->SPan; | |
| 109 | |
| 110 if (status & Status_SetVol) | |
| 111 { | |
| 112 uint16_t vol = WCI->SVol; | |
| 113 if (vol > 0) vol--; // 8bb: 0..256 -> 0..255 ( FT2 does this to prevent mul overflow in updateVolume() ) | |
| 114 v->SVol = (uint8_t)vol; | |
| 115 } | |
| 116 | |
| 117 if (status & (Status_SetVol+Status_SetPan)) | |
| 118 updateVolume(v, (status & Status_QuickVol) ? quickVolSizeVal : speedVal); | |
| 119 | |
| 120 if (status & Status_SetFrq) | |
| 121 v->SFrq = WCI->SFrq; | |
| 122 | |
| 123 if (status & Status_StartTone) | |
| 124 { | |
| 125 int32_t len; | |
| 126 | |
| 127 uint8_t type = WCI->SType; | |
| 128 const bool sample16Bit = (type >> 4) & 1; | |
| 129 | |
| 130 if (type & (SType_Fwd+SType_Rev)) | |
| 131 { | |
| 132 int32_t repL = WCI->SRepL; | |
| 133 int32_t repS = WCI->SRepS; | |
| 134 | |
| 135 if (sample16Bit) | |
| 136 { | |
| 137 repL >>= 1; | |
| 138 repS >>= 1; | |
| 139 | |
| 140 v->SRevBase = (int16_t *)WCI->SBase + (repS+repS+repL); | |
| 141 } | |
| 142 else | |
| 143 { | |
| 144 v->SRevBase = (int8_t *)WCI->SBase + (repS+repS+repL); | |
| 145 } | |
| 146 | |
| 147 v->SRepL = repL; | |
| 148 v->SRepS = repS; | |
| 149 | |
| 150 len = repS + repL; | |
| 151 } | |
| 152 else | |
| 153 { | |
| 154 type &= ~(SType_Fwd+SType_Rev); // 8bb: keep loop flags only | |
| 155 | |
| 156 len = WCI->SLen; | |
| 157 if (sample16Bit) | |
| 158 len >>= 1; | |
| 159 | |
| 160 if (len == 0) | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 // 8bb: overflown 9xx (set sample offset), cut voice (voice got ended earlier in "if (status & Status_StopTone)") | |
| 165 if (WCI->SStartPos >= len) | |
| 166 return; | |
| 167 | |
| 168 v->SLen = len; | |
| 169 v->SPos = WCI->SStartPos; | |
| 170 v->SPosDec = 0; | |
| 171 v->SBase = WCI->SBase; | |
| 172 v->SMixType = (sample16Bit * 4) + (volumeRampingFlag * 2) + interpolationFlag; | |
| 173 v->SType = type; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 static void mix_UpdateChannelVolPanFrq(void) | |
| 178 { | |
| 179 WaveChannelInfoType WCI; | |
| 180 | |
| 181 stmTyp *ch = stm; | |
| 182 for (int32_t i = 0; i < song.antChn; i++, ch++) | |
| 183 { | |
| 184 uint8_t newStatus = 0; | |
| 185 | |
| 186 const uint8_t status = ch->status; | |
| 187 ch->status = 0; | |
| 188 | |
| 189 if (status == 0) | |
| 190 continue; | |
| 191 | |
| 192 if (status & IS_Vol) | |
| 193 { | |
| 194 WCI.SVol = ch->finalVol; | |
| 195 newStatus |= Status_SetVol; | |
| 196 } | |
| 197 | |
| 198 if (status & IS_QuickVol) | |
| 199 newStatus |= Status_QuickVol; | |
| 200 | |
| 201 if (status & IS_Pan) | |
| 202 { | |
| 203 WCI.SPan = ch->finalPan; | |
| 204 newStatus |= Status_SetPan; | |
| 205 } | |
| 206 | |
| 207 if (status & IS_Period) | |
| 208 { | |
| 209 WCI.SFrq = getFrequenceValue(ch->finalPeriod); | |
| 210 newStatus |= Status_SetFrq; | |
| 211 } | |
| 212 | |
| 213 WCI.Status = newStatus; | |
| 214 mix_UpdateChannel(i, &WCI); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 void mix_ClearChannels(void) // 8bb: rewritten to handle all voices instead of song.antChn | |
| 219 { | |
| 220 lockMixer(); | |
| 221 | |
| 222 memset(CI, 0, sizeof (CI)); | |
| 223 | |
| 224 CIType *v = CI; | |
| 225 for (int16_t i = 0; i < 32*2; i++, v++) | |
| 226 { | |
| 227 v->SPan = 128; | |
| 228 v->SType = SType_Off; | |
| 229 } | |
| 230 | |
| 231 for (int16_t i = 0; i < 32; i++) | |
| 232 chnReloc[i] = i+i; | |
| 233 | |
| 234 unlockMixer(); | |
| 235 } | |
| 236 | |
| 237 static void mix_SaveIPVolumes(void) | |
| 238 { | |
| 239 CIType *v = CI; | |
| 240 for (int32_t i = 0; i < song.antChn*2; i++, v++) | |
| 241 { | |
| 242 // 8bb: this cuts any active fade-out voices (volume ramping) | |
| 243 if (v->SType & SType_Fadeout) | |
| 244 v->SType = SType_Off; | |
| 245 | |
| 246 v->SLVol2 = v->SLVol1; | |
| 247 v->SRVol2 = v->SRVol1; | |
| 248 v->SVolIPLen = 0; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 void mix_UpdateBuffer(int16_t *buffer, int32_t numSamples) | |
| 253 { | |
| 254 if (numSamples <= 0) | |
| 255 return; | |
| 256 | |
| 257 if (musicPaused || WAVDump_Flag) // silence output | |
| 258 { | |
| 259 memset(buffer, 0, numSamples * (2 * sizeof (int16_t))); | |
| 260 return; | |
| 261 } | |
| 262 | |
| 263 memset(CDA_MixBuffer, 0, numSamples * (2 * sizeof (int32_t))); | |
| 264 | |
| 265 int32_t c = 0; | |
| 266 int32_t a = numSamples; | |
| 267 | |
| 268 while (a > 0) | |
| 269 { | |
| 270 if (PMPLeft == 0) | |
| 271 { | |
| 272 mix_SaveIPVolumes(); | |
| 273 mainPlayer(); | |
| 274 mix_UpdateChannelVolPanFrq(); | |
| 275 PMPLeft = speedVal; | |
| 276 } | |
| 277 | |
| 278 int32_t b = a; | |
| 279 if (b > PMPLeft) | |
| 280 b = PMPLeft; | |
| 281 | |
| 282 CIType *v = CI; | |
| 283 for (int32_t i = 0; i < song.antChn*2; i++, v++) | |
| 284 PMPMix32Proc(v, b, c); | |
| 285 | |
| 286 c += b; | |
| 287 a -= b; | |
| 288 PMPLeft -= b; | |
| 289 } | |
| 290 | |
| 291 numSamples *= 2; // 8bb: stereo | |
| 292 | |
| 293 /* 8bb: Done a bit differently since we don't use a | |
| 294 ** Sound Blaster with its master volume setting. | |
| 295 ** Instead we change the amplitude here. | |
| 296 */ | |
| 297 | |
| 298 if (masterVol == 256) // 8bb: max master volume, no need to change amp | |
| 299 { | |
| 300 for (int32_t i = 0; i < numSamples; i++) | |
| 301 { | |
| 302 int32_t out32 = CDA_MixBuffer[i] >> 8; | |
| 303 CLAMP16(out32); | |
| 304 buffer[i] = (int16_t)out32; | |
| 305 } | |
| 306 } | |
| 307 else | |
| 308 { | |
| 309 for (int32_t i = 0; i < numSamples; i++) | |
| 310 { | |
| 311 int32_t out32 = CDA_MixBuffer[i] >> 8; | |
| 312 CLAMP16(out32); | |
| 313 out32 = (out32 * masterVol) >> 8; | |
| 314 buffer[i] = (int16_t)out32; | |
| 315 } | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 bool dump_Init(int32_t frq, int32_t amp, int16_t songPos) | |
| 320 { | |
| 321 setPos(songPos, 0); | |
| 322 | |
| 323 oldReplayRate = realReplayRate; | |
| 324 | |
| 325 realReplayRate = frq; | |
| 326 updateReplayRate(); | |
| 327 CDA_Amp = 8 * amp; | |
| 328 | |
| 329 mix_ClearChannels(); | |
| 330 stopVoices(); | |
| 331 song.globVol = 64; | |
| 332 speedVal = (frq*5 / 2) / song.speed; | |
| 333 quickVolSizeVal = frq / 200; | |
| 334 | |
| 335 dump_Flag = false; | |
| 336 return true; | |
| 337 } | |
| 338 | |
| 339 void dump_Close(void) | |
| 340 { | |
| 341 stopVoices(); | |
| 342 realReplayRate = oldReplayRate; | |
| 343 updateReplayRate(); | |
| 344 } | |
| 345 | |
| 346 bool dump_EndOfTune(int32_t endSongPos) | |
| 347 { | |
| 348 bool returnValue = (dump_Flag && song.pattPos == 0 && song.timer == 1) || (song.tempo == 0); | |
| 349 | |
| 350 // 8bb: FT2 bugfix for EEx (pattern delay) on first row of a pattern | |
| 351 if (song.pattDelTime2 > 0) | |
| 352 returnValue = false; | |
| 353 | |
| 354 if (song.songPos == endSongPos && song.pattPos == 0 && song.timer == 1) | |
| 355 dump_Flag = true; | |
| 356 | |
| 357 return returnValue; | |
| 358 } | |
| 359 | |
| 360 int32_t dump_GetFrame(int16_t *p) // 8bb: returns bytes mixed to 16-bit stereo buffer | |
| 361 { | |
| 362 mix_SaveIPVolumes(); | |
| 363 mainPlayer(); | |
| 364 mix_UpdateChannelVolPanFrq(); | |
| 365 | |
| 366 memset(CDA_MixBuffer, 0, speedVal * (2 * sizeof (int32_t))); | |
| 367 | |
| 368 CIType *v = CI; | |
| 369 for (int32_t i = 0; i < song.antChn*2; i++, v++) | |
| 370 PMPMix32Proc(v, speedVal, 0); | |
| 371 | |
| 372 const int32_t numSamples = speedVal * 2; // 8bb: *2 for stereo | |
| 373 for (int32_t i = 0; i < numSamples; i++) | |
| 374 { | |
| 375 int32_t out32 = CDA_MixBuffer[i] >> 8; | |
| 376 CLAMP16(out32); | |
| 377 p[i] = (int16_t)out32; | |
| 378 } | |
| 379 | |
| 380 return speedVal * (2 * sizeof (int16_t)); | |
| 381 } |
