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 } |