165 lines
3.7 KiB
C
165 lines
3.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "../libmodplay/modplay.h"
|
|
#include "adpcm.h"
|
|
|
|
unsigned char *mod_data;
|
|
ModMusic *mod;
|
|
|
|
// Container format
|
|
|
|
// Header
|
|
|
|
// 8 bytes - "_mod4psx"
|
|
// 4 bytes - Number of samples contained
|
|
|
|
// Sample format
|
|
// 4 bytes - Length of ADPCM sample
|
|
// 8 bytes - Reserved
|
|
// ... Data ...
|
|
|
|
// All multi word numerical values are in little endian format
|
|
// which is used by the processor of the PlayStation.
|
|
// All data is aligned to 4 bytes.
|
|
|
|
unsigned char adpcm_buffer[0x10000];
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
FILE *f;
|
|
int sz, x,y;
|
|
|
|
if(argc < 3)
|
|
{
|
|
printf("mod4psx <mod_music> <adpcm_dat>\n");
|
|
printf(
|
|
"\nMOD4PSX gets the sound samples from a music module supported by libmodplay, "
|
|
"and then converts them to PS1 ADPCM format and puts them all in a datafile, which will be able to be loaded "
|
|
"by libmodplay. In this way the CPU time needed by the PlayStation processor to convert at runtime from PCM to ADPCM is saved.\n"
|
|
);
|
|
return -1;
|
|
}
|
|
|
|
f = fopen(argv[1], "rb");
|
|
|
|
if(f == NULL)
|
|
{
|
|
printf("Could not open %s for reading. Aborting.\n", argv[1]);
|
|
return -1;
|
|
}
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
sz = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
mod_data = malloc(sz);
|
|
|
|
if(mod_data == NULL)
|
|
{
|
|
printf("Could not allocate %d bytes of memory. Aborting.\n", sz);
|
|
return -1;
|
|
}
|
|
|
|
fread(mod_data, sizeof(char), sz, f);
|
|
|
|
fclose(f);
|
|
|
|
mod = MODLoad(mod_data);
|
|
|
|
printf("Title: %s\n", mod->title);
|
|
|
|
|
|
|
|
f = fopen(argv[2], "wb");
|
|
|
|
// Write header
|
|
|
|
// Magic string
|
|
fprintf(f, "_mod4psx");
|
|
// Write number of samples
|
|
fputc(mod->sample_num & 0xff, f);
|
|
fputc((mod->sample_num >> 8) & 0xff, f);
|
|
fputc(0, f);
|
|
fputc(0, f);
|
|
|
|
for(x = 0; x < mod->sample_num; x++)
|
|
{
|
|
//printf("%d: %s\n", x, mod->sample[x].name);
|
|
printf("sample[%d].bits = %d, sample[%d].data_type = %d\n", x, mod->sample[x].bits, x, mod->sample[x].data_type);
|
|
|
|
|
|
if(mod->sample[x].length >= 32)
|
|
{
|
|
if((mod->sample[x].data_type & 1) && mod->sample[x].bits == 8)
|
|
{
|
|
for(y = 0; y < mod->sample[x].length; y++)
|
|
mod->sample[x].data[y]^=0x80;
|
|
}
|
|
|
|
if(//mod->fmt == MOD_FMT_MOD &&
|
|
mod->sample[x].repeat_len > 2)
|
|
{
|
|
|
|
sz = SsAdpcmPack(mod->sample[x].data, adpcm_buffer, // FIX THIS!!!
|
|
mod->sample[x].length / (mod->sample[x].bits / 8), (mod->sample[x].bits==16)?FMT_S16:FMT_U8,
|
|
sizeof(adpcm_buffer),
|
|
1, mod->sample[x].repeat_off);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
sz = SsAdpcmPack(mod->sample[x].data, adpcm_buffer,
|
|
mod->sample[x].length / (mod->sample[x].bits / 8), (mod->sample[x].bits==16)?FMT_S16:FMT_U8,
|
|
sizeof(adpcm_buffer), 0, 0);
|
|
|
|
}
|
|
|
|
printf("%d) %s, %d -> %d, %d, %d, FIN=%d\n", x, mod->sample[x].name,
|
|
mod->sample[x].length, sz,
|
|
mod->sample[x].repeat_off,
|
|
mod->sample[x].repeat_len, mod->sample[x].finetune);
|
|
}
|
|
else
|
|
{
|
|
printf("%d) %s, Not written\n", x, mod->sample[x].name);
|
|
sz = 0;
|
|
}
|
|
|
|
// Write length of ADPCM sample
|
|
|
|
fputc(sz & 0xff, f);
|
|
fputc((sz>>8)&0xff, f);
|
|
fputc((sz>>16)&0xff, f);
|
|
fputc((sz>>24)&0xff, f);
|
|
|
|
// Skip 8 reserved bytes - for future expansion...
|
|
|
|
fseek(f, 8, SEEK_CUR);
|
|
|
|
// Write ADPCM sample data
|
|
|
|
// Manipulate the samples to do looping for Protracker MOD samples
|
|
// The PCM to ADPCM conversion routines haven't been modified to do this yet.
|
|
|
|
/*if(mod->sample[x].repeat_len > 2 &&
|
|
mod->fmt == MOD_FMT_MOD)
|
|
{
|
|
|
|
for(y = 0; y < ((sz / 16)-1); y++)
|
|
{
|
|
if((mod->sample[x].repeat_off / 28) == y)
|
|
adpcm_buffer[(y<<4) + 1] = 6;
|
|
else
|
|
adpcm_buffer[(y<<4) + 1] = 2;
|
|
}
|
|
|
|
adpcm_buffer[(y<<4) + 1] = 3;
|
|
}*/
|
|
|
|
fwrite(adpcm_buffer, sizeof(char), sz, f);
|
|
}
|
|
|
|
return 0;
|
|
}
|