// MODplay for the PS1 // Music Module Player // Supports ProTracker (.mod) module format // Requires libADPCM! // If NO_PSX_LIB is defined, no parts using PSXSDK functions are compiled // This is useful if you want to use the library to handle module files in tools #ifndef NO_PSX_LIB #include #endif #include #include #include #include #ifndef NO_PSX_LIB #include #endif #include "modplay.h" #include "modplay_int.h" // Configuration defines // Size of ADPCM buffer used by MODUploadSamples when // converting 8-bit unsigned PCM samples to PS1 ADPCM format // By default it is set to 0x4000, 16 kilobytes #define ADPCM_BUFFER_SIZE 0x4000 int modplay_base_voice = 0; int modplay_max_vol = 0x3fff; int modplay_chan_vols[8]; int modplay_int_cnt = 0; int modplay_samples_off[32]; int modplay_chan_mask = 0; int modplay_is_mono = 0; unsigned char modplay_adpcm_buffer[ADPCM_BUFFER_SIZE]; unsigned int modload_flags = 0; ModMusic *MODLoad(void *d) { return MODLoadEx(d, 0); } ModMusic *MODLoadEx(void *d, unsigned int flags) { modload_flags = flags; // If the module file was in no other format, assume the module file is // in ProTracker format. There's no real way to detect a ProTracker module // file 100% correctly so this will do. return MODLoad_MOD(d); } void MODUnload(ModMusic *m) { int x; MODStop(m); switch(m->fmt) { case MOD_FMT_MOD: free(m->pattern_data); for(x = 0; x < m->sample_num; x++) { if(m->sample[x].data != NULL) free(m->sample[x].data); } free(m->sample); free(m); break; } } #ifdef NO_PSX_LIB void MODPlay_func(ModMusic *m, int c, int s, int p, int vl, int vr) { // Just a stub } #else void MODPlay_func(ModMusic *m, int c, int s, int p, int vl, int vr) { int v = c + modplay_base_voice; // static int mask = 0; // if(s != -1) // { // SsKeyOff(v); if(p != -1) SsVoicePitch(v, p); // } if(modplay_max_vol != 0x3fff) { vl = (modplay_max_vol * vl) / 0x4000; vr = (modplay_max_vol * vr) / 0x4000; vl&=0x3fff; vr&=0x3fff; } if(modplay_is_mono) { if(vl>vr) vr=vl; else vl=vr; } SsVoiceVol(v, vl, vr); if(s != -1) { if(modplay_samples_off[s] != -1) { SsVoiceStartAddr(v, modplay_samples_off[s]); modplay_chan_mask|=(1<fmt) { case MOD_FMT_MOD: MODPlay_MOD(m, t); break; } //printf("modplay_chan_mask = %d\n", modplay_chan_mask); #ifndef NO_PSX_LIB SsKeyOnMask(modplay_chan_mask); #endif } void MODStop(ModMusic *m) { #ifndef NO_PSX_LIB int mask = 0; int x; for(x = 0; xchannel_num; x++) mask|=1<<(modplay_base_voice+x); SsKeyOffMask(mask); #endif } #ifndef NO_PSX_LIB int MODUploadSamples(ModMusic *m, int base_addr) { int x, b; if(base_addr == -1) base_addr = SPU_DATA_BASE_ADDR; modplay_samples_off[0] = base_addr; for(x = 0; x < m->sample_num; x++) { b = SsAdpcmPack(m->sample[x].data, modplay_adpcm_buffer, m->sample[x].length, FMT_U8, sizeof(modplay_adpcm_buffer), 0); SsUpload(modplay_adpcm_buffer, b, modplay_samples_off[x]); if(x!=30) modplay_samples_off[x+1] = modplay_samples_off[x]+b; } return modplay_samples_off[x]; } int MOD4PSX_Upload(void *d, int base_addr) { unsigned char *c = d; int x; int o; int sz; int n; int smpOff; // Check magic string if(strncmp((char*)c, "_mod4psx", 8) != 0) return -1; o = 12; n = *((int*)(c+8)); if(base_addr == -1) smpOff = SPU_DATA_BASE_ADDR; else smpOff = base_addr; //smpOff = modplay_samples_off[0]; printf("Number of samples: %d\n", n); for(x = 0; x < n; x++) { // Get size sz = *((int*)(c+o)); printf("Size: %d\n", sz); // Ignore eight reserved bytes (for future expension) o+=12; if(sz > 0) { modplay_samples_off[x] = smpOff; SsUpload(c+o, sz, modplay_samples_off[x]); smpOff+=sz; } else modplay_samples_off[x] = -1; o += sz; } return modplay_samples_off[x]; } #endif void MODSetBaseVoice(int base_voice) { modplay_base_voice = base_voice; } void MODSetMaxVolume(unsigned short max_volume) { // Default is 0x3fff. // Valid values 0 (MUTE) - 0x3FFF (MAX) modplay_max_vol = max_volume & 0x3fff; } void MODRewind(ModMusic *m) { MODStop(m); m->song_pos = 0; m->pat_pos = 0; if(m->fmt == MOD_FMT_MOD) { m->divisions_sec = 7; m->beats_minute = 125; m->ticks_division = 6; } } void MODSetTranspose(ModMusic *m, short transpose) { m->transpose = transpose; } void MODSetMono(int value) { /* Sets mono audio mode left volume = right volume */ modplay_is_mono = value; } #ifdef NO_PSX_LIB // Some code might use this, so use a stub. unsigned short SsFreqToPitch(int hz) { return 0; } #endif