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 }