Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
modplayer.c
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2021 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27#include "modplayer/modplayer.h"
28
29#include <stddef.h>
30#include <stdint.h>
31
32#include "common/hardware/dma.h"
33#include "common/hardware/spu.h"
34
35/* This code is a reverse engineering of the file MODPLAY.BIN, located in the zip file
36 "Asm-Mod" from http://hitmen.c02.at/html/psx_tools.html, that has the CRC32 bb91769f. */
37
39 char name[22];
40 union {
41 uint16_t length;
42 uint8_t lenarr[2];
43 };
44 uint8_t finetune;
45 uint8_t volume;
47 uint16_t repeatLength;
48};
49
51 char title[20];
53 uint8_t songLength;
54 uint8_t padding;
55 uint8_t patternTable[128];
56 uint8_t signature[4];
57};
58
60 uint16_t note;
61 int16_t period;
62 uint16_t slideTo;
63 uint8_t slideSpeed;
64 uint8_t volume;
65 uint8_t sampleID;
66 int8_t vibrato;
67 uint8_t fx[4];
68 uint32_t samplePos; // MOD samples can be up to 128kB long
69 uint16_t sampleOffset;
70 uint8_t keyOns;
71};
72
74 uint16_t baseAddress;
75 uint8_t finetune;
76 uint8_t volume;
77 // The fields below are only used to locate 9xx sample offsets in the ADPCM data.
78 uint16_t length; // ADPCM bytes
79 uint32_t loopStart; // MOD sample bytes
80 uint32_t loopLength; // MOD sample bytes, 0 for one-shot samples
81 uint8_t skip; // MOD sample bytes dropped at the start of the sample
82 uint8_t pad; // silent samples inserted at the start of the ADPCM data
83};
84
85static struct SpuInstrumentData s_spuInstrumentData[31];
86
87static uint16_t readBE16(const void* ptr) {
88 const uint8_t* bytes = (const uint8_t*)ptr;
89 return (bytes[0] << 8) | bytes[1];
90}
91
92// SPU address of an instrument, started at samplePos, in MOD sample bytes. The SPU can only start
93// on a 16 bytes ADPCM block of 28 samples, so the position is rounded down to its block. This follows
94// the layout modconv uses: the first word of the MOD sample is skipped, unless a loop starts at 0, and
95// looped samples are front-padded with silence so that the loop starts on a block boundary. Both are
96// derived from the instrument's loop fields, which modconv keeps from the MOD file. Files converted by
97// older versions of modconv have no padding, and offsets into their looped samples can land a block late.
98static uint32_t SPUInstrumentAddress(unsigned sampleID, uint32_t samplePos) {
99 const struct SpuInstrumentData* instrument = &s_spuInstrumentData[sampleID];
100 uint32_t address = instrument->baseAddress << 4;
101 if (samplePos == 0) return address;
102 if (instrument->loopLength != 0) {
103 uint32_t loopEnd = instrument->loopStart + instrument->loopLength;
104 // Past the loop end, MOD players are back into the loop.
105 if (samplePos >= loopEnd) {
106 samplePos = instrument->loopStart + (samplePos - instrument->loopStart) % instrument->loopLength;
107 }
108 }
109 if (samplePos < instrument->skip) samplePos = instrument->skip;
110 uint32_t offset = (instrument->pad + samplePos - instrument->skip) / 28 * 16;
111 if ((offset + 16) >= instrument->length) {
112 // Past the end of a one-shot sample: its last block is the silent loop block.
113 offset = instrument->length >= 16 ? instrument->length - 16 : 0;
114 }
115 return address + offset;
116}
117
118static void SPUInit() {
119 DPCR |= 0x000b0000;
120 SPU_VOL_MAIN_LEFT = 0x3800;
121 SPU_VOL_MAIN_RIGHT = 0x3800;
122 SPU_CTRL = 0;
123 SPU_KEY_ON_LOW = 0;
124 SPU_KEY_ON_HIGH = 0;
125 SPU_KEY_OFF_LOW = 0xffff;
126 SPU_KEY_OFF_HIGH = 0xffff;
127 SPU_RAM_DTC = 4;
128 SPU_VOL_CD_LEFT = 0;
138 SPU_CTRL = 0x8000;
139}
140
141static void SPUResetVoice(int voiceID) {
142 SPU_VOICES[voiceID].volumeLeft = 0;
143 SPU_VOICES[voiceID].volumeRight = 0;
144 SPU_VOICES[voiceID].sampleRate = 0;
145 SPU_VOICES[voiceID].sampleStartAddr = 0;
146 SPU_VOICES[voiceID].adsrLo = 0x000f;
147 SPU_VOICES[voiceID].currentVolume = 0;
148 SPU_VOICES[voiceID].sampleRepeatAddr = 0;
149 SPU_VOICES[voiceID].adsrHi = 0x0000;
150}
151
152static void SPUUploadInstruments(uint32_t SpuAddr, const uint8_t* data, uint32_t size) {
153 uint32_t bcr = size >> 6;
154 if (size & 0x3f) bcr++;
155 bcr <<= 16;
156 bcr |= 0x10;
157
158 SPU_RAM_DTA = SpuAddr >> 3;
159 SPU_CTRL = (SPU_CTRL & ~0x0030) | 0x0020;
160 while ((SPU_CTRL & 0x0030) != 0x0020);
161 // original code erroneously was doing SBUS_DEV4_CTRL = SBUS_DEV4_CTRL;
162 SBUS_DEV4_CTRL &= ~0x0f000000;
163 DMA_CTRL[DMA_SPU].MADR = (uint32_t)data;
164 DMA_CTRL[DMA_SPU].BCR = bcr;
165 DMA_CTRL[DMA_SPU].CHCR = 0x01000201;
166
167 while ((DMA_CTRL[DMA_SPU].CHCR & 0x01000000) != 0);
168}
169
170static void SPUUnMute() { SPU_CTRL = 0xc000; }
171
172static uint32_t s_masterVolume = 16384;
173
174static void SPUSetVoiceVolume(int voiceID, uint32_t left, uint32_t right) {
175 SPU_VOICES[voiceID].volumeLeft = (left * s_masterVolume) >> 16;
176 SPU_VOICES[voiceID].volumeRight = (right * s_masterVolume) >> 16;
177}
178
179static void SPUSetStartAddress(int voiceID, uint32_t spuAddr) { SPU_VOICES[voiceID].sampleStartAddr = spuAddr >> 3; }
180
181static void SPUWaitIdle() {
182 do {
183 for (unsigned c = 0; c < 2045; c++) __asm__ volatile("");
184 } while ((SPU_STATUS & 0x07ff) != 0);
185}
186
187static void SPUKeyOn(uint32_t voiceBits) {
188 SPU_KEY_ON_LOW = voiceBits;
189 SPU_KEY_ON_HIGH = voiceBits >> 16;
190}
191
192static void SPUKeyOff(uint32_t voiceBits) {
193 SPU_KEY_OFF_LOW = voiceBits;
194 SPU_KEY_OFF_HIGH = voiceBits >> 16;
195}
196
197// An empty instrument has no SPU data of its own, and its address is the next instrument's.
198// Play silence for it instead, like pt2-clone does, by stopping the voice rather than keying it on.
199static void SPUKeyOnInstrument(int voiceID, unsigned sampleID) {
200 if (s_spuInstrumentData[sampleID].length == 0) {
201 SPUKeyOff(1 << voiceID);
202 } else {
203 SPUKeyOn(1 << voiceID);
204 }
205}
206
207static void SPUSetVoiceSampleRate(int voiceID, uint16_t sampleRate) { SPU_VOICES[voiceID].sampleRate = sampleRate; }
208
209unsigned MOD_Check(const struct MODFileFormat* module) {
210 const char* s = module->signature;
211 if ((s[0] == 'H') && (s[1] == 'I') && (s[2] == 'T')) {
212 return module->signature[3] - '0';
213 } else if ((s[0] == 'H') && (s[1] == 'M')) {
214 return ((module->signature[2] - '0') * 10) + module->signature[3] - '0';
215 }
216 return 0;
217}
218
219unsigned MOD_Channels = 0;
220unsigned MOD_SongLength = 0;
221// original code keeps this one to the very beginning of the file,
222// while this code keeps the pointer to the beginning of the order table
223static const uint8_t* MOD_ModuleData = NULL;
224unsigned MOD_CurrentOrder = 0;
226unsigned MOD_CurrentRow = 0;
227unsigned MOD_Speed = 0;
228unsigned MOD_Tick = 0;
229// this never seems to be updated in the original code, which is a
230// mistake; the F command handler was all wrong
231unsigned MOD_BPM = 0;
232// original code keeps this one to the NEXT row,
233// while this code keeps the pointer to the CURRENT row
234const uint8_t* MOD_RowPointer = NULL;
236unsigned MOD_NextRow = 0;
238unsigned MOD_NextOrder = 0;
240unsigned MOD_LoopStart = 0;
241unsigned MOD_LoopCount = 0;
243uint32_t MOD_hblanks;
244uint32_t MOD_SampleRateScale = 4096;
245
246// This function is now more of a helper to calculate the number of hsync
247// values to wait until the next call to MOD_Poll. If the user wants to use
248// another method, they will have to inspect MOD_BPM manually and make their
249// own math based on their own timer.
250static void MOD_SetBPM(unsigned bpm) {
251 MOD_BPM = bpm;
252 // The original code only uses 39000 here but the reality is a bit more
253 // complex than that, as not all clocks are exactly the same, depending
254 // on the machine's region, and the video mode selected.
255
256 uint32_t status = GPU_STATUS;
257 int isPalConsole = *((const char*)0xbfc7ff52) == 'E';
258 int isPal = (status & 0x00100000) != 0;
259 uint32_t base;
260 if (isPal && isPalConsole) { // PAL video on PAL console
261 base = 39062; // 312.5 * 125 * 50.000 / 50 or 314 * 125 * 49.761 / 50
262 } else if (isPal && !isPalConsole) { // PAL video on NTSC console
263 base = 39422; // 312.5 * 125 * 50.460 / 50 or 314 * 125 * 50.219 / 50
264 } else if (!isPal && isPalConsole) { // NTSC video on PAL console
265 base = 38977; // 262.5 * 125 * 59.393 / 50 or 263 * 125 * 59.280 / 50
266 } else { // NTSC video on NTSC console
267 base = 39336; // 262.5 * 125 * 59.940 / 50 or 263 * 125 * 59.826 / 50
268 }
269 MOD_hblanks = base / bpm;
270}
271
272static struct SPUChannelData s_channelData[24];
273
274static uint32_t loadInternal(const struct MODFileFormat* module, const uint8_t* sampleData) {
275 SPUInit();
277
278 if (MOD_Channels == 0) return 0;
279
281 for (unsigned i = 0; i < 31; i++) {
282 s_spuInstrumentData[i].baseAddress = currentSpuAddress >> 4;
283 s_spuInstrumentData[i].finetune = module->samples[i].finetune;
284 s_spuInstrumentData[i].volume = module->samples[i].volume;
285 uint16_t length = module->samples[i].lenarr[0] * 0x100 + module->samples[i].lenarr[1];
286 // These match the sample layout of modconv, see SPUInstrumentAddress.
287 uint32_t loopStart = readBE16(&module->samples[i].repeatLocation) * 2;
288 uint32_t loopLength = readBE16(&module->samples[i].repeatLength) * 2;
289 if (loopLength <= 2) loopLength = 0;
290 uint8_t skip = ((loopLength != 0) && (loopStart == 0)) ? 0 : 2;
291 s_spuInstrumentData[i].length = length;
292 s_spuInstrumentData[i].loopStart = loopStart;
293 s_spuInstrumentData[i].loopLength = loopLength;
294 s_spuInstrumentData[i].skip = skip;
295 s_spuInstrumentData[i].pad = loopLength != 0 ? (28 - (loopStart - skip) % 28) % 28 : 0;
296 currentSpuAddress += length;
297 }
298
299 MOD_SongLength = module->songLength;
300
301 unsigned maxPatternID = 0;
302 for (unsigned i = 0; i < 128; i++) {
303 if (maxPatternID < module->patternTable[i]) maxPatternID = module->patternTable[i];
304 }
305
306 MOD_ModuleData = (const uint8_t*)&module->patternTable[0];
307
308 if (sampleData && (sampleData != (const uint8_t*)-1)) {
309 SPUUploadInstruments(0x1010, sampleData, currentSpuAddress - 0x1010);
310 } else if (sampleData == NULL) {
311 SPUUploadInstruments(0x1010, MOD_ModuleData + 4 + 128 + MOD_Channels * 0x100 * (maxPatternID + 1),
312 currentSpuAddress - 0x1010);
313 }
314
316 MOD_CurrentPattern = module->patternTable[0];
317 MOD_CurrentRow = 0;
318 MOD_Speed = 6;
319 MOD_Tick = 6;
320 MOD_RowPointer = MOD_ModuleData + 4 + 128 + MOD_CurrentPattern * MOD_Channels * 0x100;
321 // original code goes only up to MOD_Channels; let's reset all 24
322 for (unsigned i = 0; i < 24; i++) SPUResetVoice(i);
325 MOD_LoopStart = 0;
326 MOD_LoopCount = 0;
327
328 // these two are erroneously missing from the original code, at
329 // least for being able to play more than one music
331 __builtin_memset(s_channelData, 0, sizeof(s_channelData));
332
333 SPUUnMute();
334
335 // this one is also missing, and is necessary, for being able to call MOD_Load
336 // after another song that changed the tempo previously
337 MOD_SetBPM(125);
338
339 // the original code would do:
340 // return MOD_Channels;
341 // but we are returning the size for the MOD_Relocate call
342 return 4 + 128 + MOD_Channels * 0x100 * (maxPatternID + 1);
343}
344
345uint32_t MOD_Load(const struct MODFileFormat* module) { return loadInternal(module, NULL); }
346
347unsigned MOD_LoadEx(const struct MODFileFormat* module, const uint8_t* sampleData) {
348 loadInternal(module, sampleData ? sampleData : (const uint8_t*)-1);
349 return MOD_Channels;
350}
351
353 SPUInit();
354 for (unsigned i = 0; i < 24; i++) {
355 SPUResetVoice(i);
356 }
357}
358
360 if (MOD_ModuleData == s1) return;
361 unsigned maxPatternID = 0;
362 for (unsigned i = 0; i < 128; i++) {
363 if (maxPatternID < MOD_ModuleData[i]) maxPatternID = MOD_ModuleData[i];
364 }
365
366 size_t n = 4 + 128 + MOD_Channels * 0x100 * (maxPatternID + 1);
367
368 const uint8_t* s2 = MOD_ModuleData;
369 size_t i;
370
371 if (s1 < s2) {
372 for (i = 0; i < n; i++) *s1++ = *s2++;
373 } else if (s1 > s2) {
374 s1 += n;
375 s2 += n;
376 for (i = 0; i < n; i++) *--s1 = *--s2;
377 }
378
379 MOD_ModuleData = s1;
380}
381
382static const uint8_t MOD_SineTable[32] = {
383 0x00, 0x18, 0x31, 0x4a, 0x61, 0x78, 0x8d, 0xa1, 0xb4, 0xc5, 0xd4, 0xe0, 0xeb, 0xf4, 0xfa, 0xfd,
384 0xff, 0xfd, 0xfa, 0xf4, 0xeb, 0xe0, 0xd4, 0xc5, 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x4a, 0x31, 0x18,
385};
386
387// C C# D D# E F F# G G# A A# B
388const uint16_t MOD_PeriodTable[36 * 16] = {
389 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, // octave 1 tune 0
390 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, // octave 2 tune 0
391 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, // octave 3 tune 0
392 850, 802, 757, 715, 674, 637, 601, 567, 535, 505, 477, 450, // octave 1 tune 1
393 425, 401, 379, 357, 337, 318, 300, 284, 268, 253, 239, 225, // octave 2 tune 1
394 213, 201, 189, 179, 169, 159, 150, 142, 134, 126, 119, 113, // octave 3 tune 1
395 844, 796, 752, 709, 670, 632, 597, 563, 532, 502, 474, 447, // octave 1 tune 2
396 422, 398, 376, 355, 335, 316, 298, 282, 266, 251, 237, 224, // octave 2 tune 2
397 211, 199, 188, 177, 167, 158, 149, 141, 133, 125, 118, 112, // octave 3 tune 2
398 838, 791, 746, 704, 665, 628, 592, 559, 528, 498, 470, 444, // octave 1 tune 3
399 419, 395, 373, 352, 332, 314, 296, 280, 264, 249, 235, 222, // octave 2 tune 3
400 209, 198, 187, 176, 166, 157, 148, 140, 132, 125, 118, 111, // octave 3 tune 3
401 832, 785, 741, 699, 660, 623, 588, 555, 524, 495, 467, 441, // octave 1 tune 4
402 416, 392, 370, 350, 330, 312, 294, 278, 262, 247, 233, 220, // octave 2 tune 4
403 208, 196, 185, 175, 165, 156, 147, 139, 131, 124, 117, 110, // octave 3 tune 4
404 826, 779, 736, 694, 655, 619, 584, 551, 520, 491, 463, 437, // octave 1 tune 5
405 413, 390, 368, 347, 328, 309, 292, 276, 260, 245, 232, 219, // octave 2 tune 5
406 206, 195, 184, 174, 164, 155, 146, 138, 130, 123, 116, 109, // octave 3 tune 5
407 820, 774, 730, 689, 651, 614, 580, 547, 516, 487, 460, 434, // octave 1 tune 6
408 410, 387, 365, 345, 325, 307, 290, 274, 258, 244, 230, 217, // octave 2 tune 6
409 205, 193, 183, 172, 163, 154, 145, 137, 129, 122, 115, 109, // octave 3 tune 6
410 814, 768, 725, 684, 646, 610, 575, 543, 513, 484, 457, 431, // octave 1 tune 7
411 407, 384, 363, 342, 323, 305, 288, 272, 256, 242, 228, 216, // octave 2 tune 7
412 204, 192, 181, 171, 161, 152, 144, 136, 128, 121, 114, 108, // octave 3 tune 7
413 907, 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, // octave 1 tune -8
414 453, 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, // octave 2 tune -8
415 226, 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, // octave 3 tune -8
416 900, 850, 802, 757, 715, 675, 636, 601, 567, 535, 505, 477, // octave 1 tune -7
417 450, 425, 401, 379, 357, 337, 318, 300, 284, 268, 253, 238, // octave 2 tune -7
418 225, 212, 200, 189, 179, 169, 159, 150, 142, 134, 126, 119, // octave 3 tune -7
419 894, 844, 796, 752, 709, 670, 632, 597, 563, 532, 502, 474, // octave 1 tune -6
420 447, 422, 398, 376, 355, 335, 316, 298, 282, 266, 251, 237, // octave 2 tune -6
421 223, 211, 199, 188, 177, 167, 158, 149, 141, 133, 125, 118, // octave 3 tune -6
422 887, 838, 791, 746, 704, 665, 628, 592, 559, 528, 498, 470, // octave 1 tune -5
423 444, 419, 395, 373, 352, 332, 314, 296, 280, 264, 249, 235, // octave 2 tune -5
424 222, 209, 198, 187, 176, 166, 157, 148, 140, 132, 125, 118, // octave 3 tune -5
425 881, 832, 785, 741, 699, 660, 623, 588, 555, 524, 494, 467, // octave 1 tune -4
426 441, 416, 392, 370, 350, 330, 312, 294, 278, 262, 247, 233, // octave 2 tune -4
427 220, 208, 196, 185, 175, 165, 156, 147, 139, 131, 123, 117, // octave 3 tune -4
428 875, 826, 779, 736, 694, 655, 619, 584, 551, 520, 491, 463, // octave 1 tune -3
429 437, 413, 390, 368, 347, 328, 309, 292, 276, 260, 245, 232, // octave 2 tune -3
430 219, 206, 195, 184, 174, 164, 155, 146, 138, 130, 123, 116, // octave 3 tune -3
431 868, 820, 774, 730, 689, 651, 614, 580, 547, 516, 487, 460, // octave 1 tune -2
432 434, 410, 387, 365, 345, 325, 307, 290, 274, 258, 244, 230, // octave 2 tune -2
433 217, 205, 193, 183, 172, 163, 154, 145, 137, 129, 122, 115, // octave 3 tune -2
434 862, 814, 768, 725, 684, 646, 610, 575, 543, 513, 484, 457, // octave 1 tune -1
435 431, 407, 384, 363, 342, 323, 305, 288, 272, 256, 242, 228, // octave 2 tune -1
436 216, 203, 192, 181, 171, 161, 152, 144, 136, 128, 121, 114, // octave 3 tune -1
437};
438
439#define SETVOICESAMPLERATE(channel, newPeriod) \
440 SPUSetVoiceSampleRate(channel, ((((7093789 / (newPeriod * 2)) << 12) / 44100) * MOD_SampleRateScale) >> 12)
441#define SETVOICEVOLUME(channel, volume) \
442 volume <<= 8; \
443 if (MOD_Stereo) { \
444 int pan = (channel & 1) ^ (channel >> 1); \
445 int16_t left = pan == 0 ? volume : 0; \
446 int16_t right = pan == 0 ? 0 : volume; \
447 SPUSetVoiceVolume(channel, left, right); \
448 } else { \
449 SPUSetVoiceVolume(channel, volume, volume); \
450 }
451
452static void MOD_UpdateEffect() {
454 const unsigned channels = MOD_Channels;
455 for (unsigned channel = 0; channel < channels; channel++) {
457 uint8_t effectNibble1 = rowPointer[2] & 0x0f;
460
465 uint8_t fx;
468
469 struct SPUChannelData* const channelData = &s_channelData[channel];
470
471 switch (effectNibble1) {
472 case 0: // arpeggio
473 if (effectNibble23 == 0) break;
475 arpeggioTick %= 3;
476 switch (arpeggioTick) {
477 case 0:
479 break;
480 case 1:
482 break;
483 case 2:
485 break;
486 }
488 break;
489 case 1: // portamento up
490 newPeriod = channelData->period;
492 if (newPeriod < 108) newPeriod = 108;
493 channelData->period = newPeriod;
495 break;
496 case 2: // portamento down
497 newPeriod = channelData->period;
499 if (newPeriod > 907) newPeriod = 907;
500 channelData->period = newPeriod;
502 break;
503 case 5:
504 volume = channelData->volume;
505 if (effectNibble23 < 0x10) {
507 if (volume < 0) volume = 0;
508 } else {
510 if (volume > 63) volume = 63;
511 }
512 channelData->volume = volume;
513 SETVOICEVOLUME(channel, volume);
514 /* fall through */
515 case 3: // glissando
516 newPeriod = channelData->period;
517 slideTo = channelData->slideTo;
518 if (newPeriod < slideTo) {
519 newPeriod += channelData->slideSpeed;
521 } else if (newPeriod > slideTo) {
522 newPeriod -= channelData->slideSpeed;
524 }
525 channelData->period = newPeriod;
527 break;
528 case 6:
529 volume = channelData->volume;
530 if (effectNibble23 < 0x10) {
532 if (volume < 0) volume = 0;
533 } else {
535 if (volume > 63) volume = 63;
536 }
537 channelData->volume = volume;
538 SETVOICEVOLUME(channel, volume);
539 /* fall through */
540 case 4: // vibrato
541 mutation = channelData->vibrato & 0x1f;
542 switch (channelData->fx[3] & 3) {
543 case 0:
544 case 3: // 3 is technically random
545 mutation = MOD_SineTable[mutation];
546 break;
547 case 1:
548 if (channelData->vibrato < 0) {
549 mutation *= -8;
550 mutation += 0xff;
551 } else {
552 mutation *= 8;
553 }
554 break;
555 case 2:
556 mutation = 0xff;
557 break;
558 }
559 mutation *= channelData->fx[1] >> 4;
560 mutation >>= 7;
561 newPeriod = channelData->period;
562 if (channelData->vibrato < 0) {
564 } else {
566 }
567 newValue = channelData->vibrato;
568 newValue += channelData->fx[1] & 0x0f;
569 if (newValue >= 32) newValue -= 64;
570 channelData->vibrato = newValue;
572 break;
573 case 7: // tremolo
574 // fx[0] is the tremolo position, fx[2] holds speed (low) and depth (high),
575 // and the tremolo waveform is the high nibble of fx[3] (E7x).
576 mutation = channelData->fx[0] & 0x1f;
577 switch ((channelData->fx[3] >> 4) & 3) {
578 case 0:
579 case 3: // 3 is technically random
580 mutation = MOD_SineTable[mutation];
581 break;
582 case 1:
583 if (channelData->fx[0] & 0x80) {
584 mutation *= -8;
585 mutation += 0xff;
586 } else {
587 mutation *= 8;
588 }
589 break;
590 case 2:
591 mutation = 0xff;
592 break;
593 }
594 mutation *= channelData->fx[2] >> 4;
595 mutation >>= 6;
596 volume = channelData->volume;
597 if (channelData->fx[0] & 0x80) {
598 volume -= mutation;
599 } else {
600 volume += mutation;
601 }
602 newValue = channelData->fx[0] + (channelData->fx[2] & 0x0f);
603 if (newValue >= 32) newValue -= 64;
604 channelData->fx[0] = newValue;
605 if (volume < 0) volume = 0;
606 if (volume > 63) volume = 63;
607 SETVOICEVOLUME(channel, volume);
608 break;
609 case 10: // volume slide
610 volume = channelData->volume;
611 if (effectNibble23 < 0x10) {
613 if (volume < 0) volume = 0;
614 } else {
616 if (volume > 63) volume = 63;
617 }
618 channelData->volume = volume;
619 SETVOICEVOLUME(channel, volume);
620 break;
621 case 14: // extended
622 switch (effectNibble3) {
623 case 9: // retrigger sample
624 // this doesn't look right, we probably want to reset the sample location
625 // Tick 0 only gets here on the repeats of a delayed row. Like ProTracker, a row
626 // with a note doesn't retrigger on tick 0, even then.
627 if ((MOD_Tick == 0) && (((rowPointer[0] & 0x0f) << 8) | rowPointer[1])) break;
628 if (effectNibble2 && (MOD_Tick % effectNibble2) == 0) {
629 SPUKeyOnInstrument(channel, channelData->sampleID);
630 channelData->keyOns++;
631 }
632 break;
633 case 12: // cut sample
634 if (MOD_Tick != effectNibble2) break;
635 channelData->volume = 0;
636 SPUSetVoiceVolume(channel, 0, 0);
637 }
638 break;
639 }
640
641 rowPointer += 4;
642 }
643}
644
645static void MOD_UpdateRow() {
646 const unsigned channels = MOD_Channels;
648 unsigned newOrder = MOD_NextOrder;
649 if (newOrder >= MOD_SongLength) newOrder = 0;
650 MOD_CurrentRow = 0;
652 MOD_CurrentPattern = MOD_ModuleData[newOrder];
653 }
655 unsigned newRow = (MOD_NextRow >> 4) * 10 + (MOD_NextRow & 0x0f);
656 if (newRow >= 64) newRow = 0;
660 MOD_CurrentPattern = MOD_ModuleData[MOD_CurrentOrder];
661 }
662 }
666 MOD_ModuleData + 128 + 4 + MOD_CurrentPattern * MOD_Channels * 0x100 + MOD_CurrentRow * channels * 4;
668
669 for (unsigned channel = 0; channel < channels; channel++) {
671 struct SPUChannelData* const channelData = &s_channelData[channel];
672
676 unsigned sampleID = (nibble0 & 0xf0) | (effectNibble1 >> 4);
679 unsigned period = ((nibble0 & 0x0f) << 8) | rowPointer[1];
681 uint8_t fx;
682 effectNibble1 &= 0x0f;
683
684 // samplePos is where the channel's sample starts, like ProTracker's n_start: a sample number
685 // resets it, and 9xx (xx * 256 MOD sample bytes, 900 reusing the channel's last offset) adds
686 // to it, so notes without a sample number keep starting there. It needs to be known before
687 // setting the start address below, which the original code did after, in the effects switch.
688 if (sampleID != 0) channelData->samplePos = 0;
689 if (effectNibble1 == 9) {
690 if (effectNibble23 != 0) channelData->sampleOffset = effectNibble23 << 8;
691 channelData->samplePos += channelData->sampleOffset;
692 }
693 if (sampleID != 0) {
694 channelData->sampleID = --sampleID;
695 volume = s_spuInstrumentData[sampleID].volume;
696 if (volume > 63) volume = 63;
697 channelData->volume = volume;
698 if (effectNibble1 != 7) {
699 SETVOICEVOLUME(channel, volume);
700 }
701 SPUSetStartAddress(channel, SPUInstrumentAddress(sampleID, channelData->samplePos));
702 } else if (effectNibble1 == 9) {
703 // 9xx without a sample number applies to the channel's current sample.
704 SPUSetStartAddress(channel, SPUInstrumentAddress(channelData->sampleID, channelData->samplePos));
705 }
706
707 if (period != 0) {
708 int periodIndex;
709 // Scan the whole finetune 0 row, down to C-1 at index 0. A period that
710 // isn't in it leaves periodIndex at -1.
711 for (periodIndex = 35; periodIndex >= 0; periodIndex--) {
712 if (MOD_PeriodTable[periodIndex] == period) break;
713 }
714 channelData->note = periodIndex + s_spuInstrumentData[channelData->sampleID].finetune * 36;
715 fx = channelData->fx[3];
716 if ((fx & 0x0f) < 4) {
717 channelData->vibrato = 0;
718 }
719 if ((fx >> 4) < 4) {
720 channelData->fx[0] = 0;
721 }
722 if ((effectNibble1 != 3) && (effectNibble1 != 5)) {
723 SPUWaitIdle();
724 SPUKeyOnInstrument(channel, channelData->sampleID);
725 channelData->keyOns++;
726 channelData->period = MOD_PeriodTable[channelData->note];
727 }
728 newPeriod = channelData->period;
730 }
731
732 switch (effectNibble1) {
733 case 3: // glissando
734 if (effectNibble23 != 0) {
735 channelData->slideSpeed = effectNibble23;
736 }
737 if (period != 0) {
738 channelData->slideTo = MOD_PeriodTable[channelData->note];
739 }
740 break;
741 case 4: // vibrato
742 if (effectNibble3 != 0) {
743 fx = channelData->fx[1];
744 fx &= ~0x0f;
745 fx |= effectNibble3;
746 channelData->fx[1] = fx;
747 }
748 if (effectNibble2 != 0) {
749 fx = channelData->fx[1];
750 fx &= ~0xf0;
751 fx |= effectNibble2 << 4;
752 channelData->fx[1] = fx;
753 }
754 break;
755 case 7: // tremolo
756 if (effectNibble3 != 0) {
757 fx = channelData->fx[2];
758 fx &= ~0x0f;
759 fx |= effectNibble3;
760 channelData->fx[2] = fx;
761 }
762 if (effectNibble2 != 0) {
763 fx = channelData->fx[2];
764 fx &= ~0xf0;
765 fx |= effectNibble2 << 4;
766 channelData->fx[2] = fx;
767 }
768 break;
769 case 9: // sample jump, handled above
770 break;
771 case 11: // order jump
775 }
776 break;
777 case 12: // set volume
779 if (volume > 64) volume = 63;
780 channelData->volume = volume;
781 SETVOICEVOLUME(channel, volume);
782 break;
783 case 13: // pattern break
787 }
788 break;
789 case 14: // extended
790 switch (effectNibble3) {
791 case 1: // fineslide up
792 newPeriod = channelData->period;
794 channelData->period = newPeriod;
796 break;
797 case 2: // fineslide down
798 newPeriod = channelData->period;
800 channelData->period = newPeriod;
802 break;
803 case 4: // set vibrato waveform
804 fx = channelData->fx[3];
805 fx &= ~0x0f;
806 fx |= effectNibble2;
807 channelData->fx[3] = fx;
808 break;
809 case 5: // set finetune value
810 // Applies to the channel's current sample, which a sample number
811 // on this row has already selected.
812 s_spuInstrumentData[channelData->sampleID].finetune = effectNibble2;
813 break;
814 case 6: // loop pattern
815 if (MOD_LoopCount-- == 0) {
817 }
818 if (MOD_LoopCount != 0) {
820 }
821 break;
822 case 7: // set tremolo waveform
823 fx = channelData->fx[3];
824 fx &= ~0xf0;
825 fx |= effectNibble2 << 4;
826 channelData->fx[3] = fx;
827 break;
828 case 9: // retrigger sample
829 // Like ProTracker, a row without a note retriggers on tick 0 too. With a note,
830 // the note itself is the tick 0 trigger. Later ticks are in MOD_UpdateEffect.
831 if (effectNibble2 && (period == 0)) {
832 SPUKeyOnInstrument(channel, channelData->sampleID);
833 channelData->keyOns++;
834 }
835 break;
836 case 10: // fine volume up
837 volume = channelData->volume;
839 if (volume > 63) volume = 63;
840 channelData->volume = volume;
841 SETVOICEVOLUME(channel, volume);
842 break;
843 case 11: // fine volume down
844 volume = channelData->volume;
846 if (volume < 0) volume = 0;
847 channelData->volume = volume;
848 SETVOICEVOLUME(channel, volume);
849 break;
850 case 14: // delay pattern
852 break;
853 }
854 break;
855 case 15: // set speed
856 // the original code here is very wrong with regards to
857 // how to interpret the command; also it was very opinionated
858 // about using timer1 for its clock source
859 if (effectNibble23 == 0) break;
860 if (effectNibble23 < 32) {
862 } else {
863 MOD_SetBPM(effectNibble23);
864 }
865 break;
866 }
867
868 rowPointer += 4;
869 }
870}
871
872void MOD_Poll() {
873 // the original code is getting the delay pattern wrong here, and
874 // isn't processing them as actual line delays, rather as a sort
875 // of ticks delay, and was basically going too fast
877 if (++MOD_Tick < MOD_Speed) {
878 MOD_UpdateEffect();
879 } else {
880 MOD_Tick = 0;
881 if (newPatternDelay-- == 0) {
882 MOD_UpdateRow();
884 // I don't think the original code was handling this properly...
885 if (++MOD_CurrentRow >= 64 || MOD_ChangeRowNextTick) {
886 MOD_CurrentRow = 0;
889 }
890 MOD_CurrentPattern = MOD_ModuleData[MOD_CurrentOrder];
891 }
892 } else {
893 MOD_UpdateEffect();
894 }
895 }
897}
898
899void MOD_PlayNote(unsigned channel, unsigned sampleID, unsigned note, int16_t volume) {
900 if (volume < 0) volume = 0;
901 if (volume > 63) volume = 63;
902 struct SPUChannelData* const channelData = &s_channelData[channel];
904 SPUSetVoiceVolume(channel, volume << 8, volume << 8);
905 SPUSetStartAddress(channel, SPUInstrumentAddress(sampleID, channelData->samplePos));
906 SPUWaitIdle();
907 SPUKeyOnInstrument(channel, sampleID);
908 channelData->note = note = note + s_spuInstrumentData[sampleID].finetune * 36;
911}
912
913void MOD_PlaySoundEffect(unsigned channel, unsigned sampleID, unsigned note, int16_t volume) {
914 uint32_t prevVolume = s_masterVolume;
915 s_masterVolume = 16384;
916 MOD_PlayNote(channel, sampleID, note, volume);
917 s_masterVolume = prevVolume;
918}
919
921 s_masterVolume = musicVolume;
922 for (unsigned channel = 0; channel < MOD_Channels; channel++) {
923 SETVOICEVOLUME(channel, s_channelData[channel].volume);
924 }
925}
926
927unsigned MOD_GetChannelVolume(unsigned channel) { return s_channelData[channel].volume; }
928
929unsigned MOD_GetChannelKeyOns(unsigned channel) { return s_channelData[channel].keyOns; }
DMA_CTRL[DMA_CDROM] CHCR
Definition cdlreadn.c:185
__builtin_memset(response, 0xff, 16)
#define SPU_VOL_CD_RIGHT
Definition spu.h:108
#define SPU_VOL_CD_LEFT
Definition spu.h:107
#define SPU_VOICES
Definition spu.h:42
#define SPU_REVERB_EN_HIGH
Definition spu.h:97
#define SPU_STATUS
Definition spu.h:106
#define SPU_KEY_ON_LOW
Definition spu.h:88
#define SPU_VOL_MAIN_LEFT
Definition spu.h:84
#define SPU_KEY_OFF_LOW
Definition spu.h:90
#define SPU_KEY_OFF_HIGH
Definition spu.h:91
#define SPU_CTRL
Definition spu.h:104
#define SPU_VOL_EXT_LEFT
Definition spu.h:109
#define SPU_VOL_MAIN_RIGHT
Definition spu.h:85
#define SPU_NOISE_EN_HIGH
Definition spu.h:95
#define SPU_VOL_EXT_RIGHT
Definition spu.h:110
#define SPU_KEY_ON_HIGH
Definition spu.h:89
#define SPU_PITCH_MOD_HIGH
Definition spu.h:93
#define SPU_REVERB_EN_LOW
Definition spu.h:96
#define SPU_NOISE_EN_LOW
Definition spu.h:94
#define SPU_PITCH_MOD_LOW
Definition spu.h:92
#define SPU_RAM_DTC
Definition spu.h:105
#define SPU_RAM_DTA
Definition spu.h:103
static int size
Definition string.h:149
volatile uint32_t * ptr
Definition cop0.c:80
uintptr_t bcr
Definition dma.c:129
#define DMA_CTRL
Definition dma.h:36
@ DMA_SPU
Definition dma.h:43
int i
Definition gte-regio.c:299
#define SBUS_DEV4_CTRL
Definition hwregs.h:40
#define DPCR
Definition hwregs.h:49
#define GPU_STATUS
Definition hwregs.h:53
#define SETVOICESAMPLERATE(channel, newPeriod)
Definition modplayer.c:439
unsigned MOD_GetChannelVolume(unsigned channel)
Definition modplayer.c:927
unsigned MOD_LoopCount
Definition modplayer.c:241
int MOD_ChangeRowNextTick
Definition modplayer.c:235
unsigned MOD_CurrentRow
Definition modplayer.c:226
unsigned MOD_Tick
Definition modplayer.c:228
uint8_t MOD_PatternDelay
Definition modplayer.c:239
void MOD_Silence()
Definition modplayer.c:352
unsigned MOD_GetChannelKeyOns(unsigned channel)
Definition modplayer.c:929
void MOD_Poll()
Definition modplayer.c:872
unsigned MOD_LoadEx(const struct MODFileFormat *module, const uint8_t *sampleData)
Definition modplayer.c:347
int MOD_ChangeOrderNextTick
Definition modplayer.c:237
int MOD_Stereo
Definition modplayer.c:242
const uint8_t * MOD_RowPointer
Definition modplayer.c:234
void MOD_SetMusicVolume(uint32_t musicVolume)
Definition modplayer.c:920
unsigned MOD_NextRow
Definition modplayer.c:236
void MOD_Relocate(uint8_t *s1)
Definition modplayer.c:359
uint32_t MOD_SampleRateScale
Definition modplayer.c:244
unsigned MOD_Check(const struct MODFileFormat *module)
Definition modplayer.c:209
void MOD_PlaySoundEffect(unsigned channel, unsigned sampleID, unsigned note, int16_t volume)
Definition modplayer.c:913
unsigned MOD_CurrentPattern
Definition modplayer.c:225
unsigned MOD_Speed
Definition modplayer.c:227
unsigned MOD_NextOrder
Definition modplayer.c:238
unsigned MOD_CurrentOrder
Definition modplayer.c:224
uint32_t MOD_Load(const struct MODFileFormat *module)
Definition modplayer.c:345
void MOD_PlayNote(unsigned channel, unsigned sampleID, unsigned note, int16_t volume)
Definition modplayer.c:899
#define SETVOICEVOLUME(channel, volume)
Definition modplayer.c:441
unsigned MOD_BPM
Definition modplayer.c:231
unsigned MOD_LoopStart
Definition modplayer.c:240
const uint16_t MOD_PeriodTable[36 *16]
Definition modplayer.c:388
uint32_t MOD_hblanks
Definition modplayer.c:243
unsigned MOD_SongLength
Definition modplayer.c:220
unsigned MOD_Channels
Definition modplayer.c:219
__asm__(" .section .text.monitorSlotEntry, \"ax\", @progbits\n" " .align 2\n" " .global monitorSlotEntry\n" " .type monitorSlotEntry, @function\n" " .set push\n" " .set noreorder\n" " .set noat\n" "monitorSlotEntry:\n" " mfc0 $v0, $13\n" " nop\n" " andi $v0, $v0, 0x7c\n" " beqz $v0, 1f\n" " srl $v0, $v0, 2\n" " li $v1, " MON_STR(MON_SLOT_EXCMASK) "\n" " srlv $v1, $v1, $v0\n" " andi $v1, $v1, 1\n" " bnez $v1, 2f\n" " nop\n" " jr $ra\n" " nop\n" "1:\n" MON_SLOT_RX_TEST " jr $ra\n" " nop\n" "2:\n" " sw $a0, 0x10($k0)\n" " sw $a1, 0x14($k0)\n" " sw $a2, 0x18($k0)\n" " sw $a3, 0x1c($k0)\n" " mfc0 $a0, $12\n" " nop\n" " sw $a0, 0x8c($k0)\n" " mfc0 $a1, $13\n" " nop\n" " sw $a1, 0x90($k0)\n" " sw $k1, 0x6c($k0)\n" " sw $s0, 0x40($k0)\n" " sw $s1, 0x44($k0)\n" " sw $s2, 0x48($k0)\n" " sw $s3, 0x4c($k0)\n" " sw $s4, 0x50($k0)\n" " sw $s5, 0x54($k0)\n" " sw $s6, 0x58($k0)\n" " sw $s7, 0x5c($k0)\n" " sw $t0, 0x20($k0)\n" " sw $t1, 0x24($k0)\n" " sw $t2, 0x28($k0)\n" " sw $t3, 0x2c($k0)\n" " sw $t4, 0x30($k0)\n" " sw $t5, 0x34($k0)\n" " sw $t6, 0x38($k0)\n" " sw $t7, 0x3c($k0)\n" " sw $t8, 0x60($k0)\n" " sw $t9, 0x64($k0)\n" " sw $gp, 0x70($k0)\n" " sw $sp, 0x74($k0)\n" " sw $fp, 0x78($k0)\n" " mfhi $a0\n" " nop\n" " sw $a0, 0x84($k0)\n" " mflo $a0\n" " nop\n" " sw $a0, 0x88($k0)\n" " move $s0, $ra\n" " la $sp, monitorSlotStack + " MON_STR(MONITOR_SLOT_STACK_WORDS) " * 4 - 16\n" " jal monitorSlotDispatch\n" " nop\n" " lw $k0, 0x108($zero)\n" " move $ra, $s0\n" " lw $k0, 0($k0)\n" " nop\n" " addiu $k0, $k0, 8\n" " lw $a0, 0x84($k0)\n" " lw $a1, 0x88($k0)\n" " mthi $a0\n" " mtlo $a1\n" " lw $a0, 0x10($k0)\n" " lw $a1, 0x14($k0)\n" " lw $a2, 0x18($k0)\n" " lw $a3, 0x1c($k0)\n" " lw $t0, 0x20($k0)\n" " lw $t1, 0x24($k0)\n" " lw $t2, 0x28($k0)\n" " lw $t3, 0x2c($k0)\n" " lw $t4, 0x30($k0)\n" " lw $t5, 0x34($k0)\n" " lw $t6, 0x38($k0)\n" " lw $t7, 0x3c($k0)\n" " lw $t8, 0x60($k0)\n" " lw $t9, 0x64($k0)\n" " lw $s0, 0x40($k0)\n" " lw $sp, 0x74($k0)\n" " jr $ra\n" " nop\n" " .set pop\n" " .size monitorSlotEntry, . - monitorSlotEntry\n" " .previous\n")
instrument(name, pcm, loop=0, loopstart=0, relnote=0, vol=64, volenv=None, sustain=None, panenv=None, fade=0, vib=(0, 0, 0, 0))
Definition make-demo-song.py:27
char * s
Definition string.c:48
Definition modplayer.c:50
char title[20]
Definition modplayer.c:51
uint8_t patternTable[128]
Definition modplayer.c:55
uint8_t padding
Definition modplayer.c:54
struct MODSampleData samples[31]
Definition modplayer.c:52
uint8_t signature[4]
Definition modplayer.c:56
uint8_t songLength
Definition modplayer.c:53
Definition modplayer.c:38
char name[22]
Definition modplayer.c:39
uint16_t length
Definition modplayer.c:41
uint16_t repeatLocation
Definition modplayer.c:46
uint8_t finetune
Definition modplayer.c:44
uint8_t volume
Definition modplayer.c:45
uint16_t repeatLength
Definition modplayer.c:47
uint8_t lenarr[2]
Definition modplayer.c:42
Definition modplayer.c:59
uint32_t samplePos
Definition modplayer.c:68
int8_t vibrato
Definition modplayer.c:66
uint16_t note
Definition modplayer.c:60
uint8_t keyOns
Definition modplayer.c:70
uint8_t fx[4]
Definition modplayer.c:67
uint8_t volume
Definition modplayer.c:64
int16_t period
Definition modplayer.c:61
uint8_t sampleID
Definition modplayer.c:65
uint16_t slideTo
Definition modplayer.c:62
uint16_t sampleOffset
Definition modplayer.c:69
uint8_t slideSpeed
Definition modplayer.c:63
Definition modplayer.c:73
uint8_t skip
Definition modplayer.c:81
uint8_t pad
Definition modplayer.c:82
uint32_t loopStart
Definition modplayer.c:79
uint32_t loopLength
Definition modplayer.c:80
uint8_t finetune
Definition modplayer.c:75
uint16_t baseAddress
Definition modplayer.c:74
uint8_t volume
Definition modplayer.c:76
uint16_t length
Definition modplayer.c:78
static const char * s2
Definition syscalls.h:144
static int c
Definition syscalls.h:172