From c0fcf293c1833e8586b4147e12ea45d535da4985 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 3 May 2008 16:26:03 +0000 Subject: [PATCH] added bin_to_cso_mp3 tool git-svn-id: file:///home/notaz/opt/svn/PicoDrive@435 be3aeb3a-fb24-0410-a615-afba39da0efa --- platform/gp2x/Makefile | 4 + platform/psp/Makefile | 8 + tools/bin_to_cso_mp3/bin_to_cso_mp3.c | 723 ++++++++++++++++++++++++ tools/bin_to_cso_mp3/bin_to_cso_mp3.exe | Bin 0 -> 31860 bytes tools/bin_to_cso_mp3/readme.txt | 47 ++ 5 files changed, 782 insertions(+) create mode 100644 tools/bin_to_cso_mp3/bin_to_cso_mp3.c create mode 100755 tools/bin_to_cso_mp3/bin_to_cso_mp3.exe create mode 100644 tools/bin_to_cso_mp3/readme.txt diff --git a/platform/gp2x/Makefile b/platform/gp2x/Makefile index 4c55445..59a7c15 100644 --- a/platform/gp2x/Makefile +++ b/platform/gp2x/Makefile @@ -237,6 +237,10 @@ endif rel: PicoDrive.gpe code940/pico940_v2.bin readme.txt PicoDrive.man.txt PicoDrive.png ../game_def.cfg zip -9 -j ../../PicoDrive_$(VER).zip $^ mmuhack.o zip -9 -r ../../PicoDrive_$(VER).zip skin -i \*.png -i \*.txt + mkdir bin_to_cso_mp3 + cp ../../tools/bin_to_cso_mp3/* bin_to_cso_mp3/ + zip -9 -r ../../PicoDrive_$(VER).zip bin_to_cso_mp3 + rm -rf bin_to_cso_mp3 code940/code940.bin: make -C code940/ diff --git a/platform/psp/Makefile b/platform/psp/Makefile index a2f37f0..c89f1d6 100644 --- a/platform/psp/Makefile +++ b/platform/psp/Makefile @@ -179,6 +179,10 @@ rel: EBOOT.PBP readme.txt ../game_def.cfg cp skin/* PicoDrive/skin/ zip -9 -r ../../PicoDrive_psp_$(VER).zip PicoDrive rm -rf PicoDrive + mkdir bin_to_cso_mp3 + cp ../../tools/bin_to_cso_mp3/* bin_to_cso_mp3/ + zip -9 -r ../../PicoDrive_psp_$(VER).zip bin_to_cso_mp3 + rm -rf bin_to_cso_mp3 rel_kxploit: readme.txt ../game_def.cfg mkdir -p PicoDrive/skin/ @@ -186,4 +190,8 @@ rel_kxploit: readme.txt ../game_def.cfg cp skin/* PicoDrive/skin/ zip -9 -r ../../PicoDrive_psp_$(VER)_kxploit.zip PicoDrive zip -9 -r ../../PicoDrive_psp_$(VER)_kxploit.zip PicoDrive% + mkdir bin_to_cso_mp3 + cp ../../tools/bin_to_cso_mp3/* bin_to_cso_mp3/ + zip -9 -r ../../PicoDrive_psp_$(VER)_kxploit.zip bin_to_cso_mp3 + rm -rf bin_to_cso_mp3 diff --git a/tools/bin_to_cso_mp3/bin_to_cso_mp3.c b/tools/bin_to_cso_mp3/bin_to_cso_mp3.c new file mode 100644 index 0000000..87a5599 --- /dev/null +++ b/tools/bin_to_cso_mp3/bin_to_cso_mp3.c @@ -0,0 +1,723 @@ +/* + * bin_to_cso_mp3 + * originally written by Exophase as "bin_to_iso_ogg" + * updated for cso/mp3 by notaz + */ +#include +#include +#include +#include +#include + +#ifndef MAX_PATH +#define MAX_PATH 1024 +#endif + +#ifdef _WIN32 +#include + +#define DIR_SEPARATOR_CHAR '\\' +#define PATH_SEPARATOR_CHAR ';' +#define LAME_BINARY "lame.exe" +#define CISO_BINARY "ciso.exe" +#define NULL_REDIR "> NUL 2>&1" +#else +#define DIR_SEPARATOR_CHAR '/' +#define PATH_SEPARATOR_CHAR ':' +#define LAME_BINARY "lame" +#define CISO_BINARY "ciso" +#define NULL_REDIR "> /dev/null 2>&1" +#define mkdir(x) mkdir(x, S_IRWXU) +#endif + +#define LAME_OPTIONS "-h --cbr" + +typedef unsigned char u8; +typedef unsigned short int u16; +typedef unsigned int u32; +typedef unsigned long long int u64; +typedef signed char s8; +typedef signed short int s16; +typedef signed int s32; +typedef signed long long int s64; + +typedef enum +{ + TRACK_FILE_TYPE_BINARY, + TRACK_FILE_TYPE_WAVE, +} track_file_type_enum; + +typedef struct +{ + u32 file_number; + u32 physical_offset; + + u32 sector_offset; + u32 sector_count; + u32 pregap_offset; + + u32 sector_size; + u32 format_type; +} cd_track_struct; + +typedef struct +{ + track_file_type_enum type; + FILE *file_handle; + + u32 current_offset; +} cd_track_file_struct; + +typedef struct +{ + FILE *bin_file; + cd_track_file_struct track_files[100]; + u32 num_files; + + s32 first_track; + s32 last_track; + u32 num_physical_tracks; + u32 num_sectors; + s32 last_seek_track; + + cd_track_struct physical_tracks[100]; + cd_track_struct *logical_tracks[100]; +} cd_bin_struct; + + +cd_bin_struct cd_bin; +int opt_use_mp3 = 1; +int opt_mp3_bitrate = 128; +int opt_use_cso = 1; + +static void myexit(int code) +{ +#ifdef _WIN32 + system("pause"); +#endif + exit(code); +} + +char *skip_whitespace(char *str) +{ + while(*str == ' ') + str++; + + return str; +} + +s32 load_bin_cue(char *cue_file_name) +{ + FILE *cue_file = fopen(cue_file_name, "rb"); + + printf("loading cue file %s\n", cue_file_name); + + if(cue_file) + { + char line_buffer[256]; + char *line_buffer_ptr; + + char bin_file_name[MAX_PATH]; + char *separator_pos; + s32 current_physical_track_number = -1; + u32 current_physical_offset; + u32 current_pregap = 0; + u32 bin_file_size; + + cd_track_struct *current_physical_track = NULL; + + u32 i; + + // First, get filename. Only support binary right now. + fgets(line_buffer, 255, cue_file); + + strcpy(bin_file_name, strchr(line_buffer, '"') + 1); + + *(strrchr(bin_file_name, '"')) = 0; + + // Might have to change directory first. + separator_pos = strrchr(cue_file_name, DIR_SEPARATOR_CHAR); + + if(separator_pos) + { + char current_dir[MAX_PATH]; + getcwd(current_dir, MAX_PATH); + + *separator_pos = 0; + + chdir(cue_file_name); + +#ifdef GP2X_BUILD + cd_bin.bin_file = open(bin_file_name, O_RDONLY); +#else + cd_bin.bin_file = fopen(bin_file_name, "rb"); +#endif + + printf("loaded bin file %s (%p)\n", bin_file_name, cd_bin.bin_file); + + *separator_pos = DIR_SEPARATOR_CHAR; + chdir(current_dir); + } + else + { +#ifdef GP2X_BUILD + cd_bin.bin_file = open(bin_file_name, O_RDONLY); +#else + cd_bin.bin_file = fopen(bin_file_name, "rb"); +#endif + } + + for(i = 0; i < 100; i++) + { + cd_bin.logical_tracks[i] = NULL; + } + + cd_bin.first_track = -1; + cd_bin.last_track = -1; + cd_bin.num_physical_tracks = 0; + cd_bin.num_sectors = 0; + + // Get line + while(fgets(line_buffer, 256, cue_file)) + { + // Skip trailing whitespace + line_buffer_ptr = skip_whitespace(line_buffer); + + // Dirty, but should work - switch on first character. + switch(line_buffer_ptr[0]) + { + // New track number + case 'T': + { + u32 new_track_number; + char track_type[64]; + + sscanf(line_buffer_ptr, "TRACK %d %s", &new_track_number, + track_type); + + current_physical_track_number++; + current_physical_track = + cd_bin.physical_tracks + current_physical_track_number; + + current_physical_track->sector_size = 2352; + + if(!strcmp(track_type, "AUDIO")) + { + current_physical_track->format_type = 0; + current_physical_track->sector_size = 2352; + } + + if(!strcmp(track_type, "MODE1/2352")) + { + current_physical_track->format_type = 4; + current_physical_track->sector_size = 2352; + } + + if(!strcmp(track_type, "MODE1/2048")) + { + current_physical_track->format_type = 4; + current_physical_track->sector_size = 2048; + } + + cd_bin.logical_tracks[new_track_number] = current_physical_track; + cd_bin.num_physical_tracks++; + + if((cd_bin.first_track == -1) || + (new_track_number < cd_bin.first_track)) + { + cd_bin.first_track = new_track_number; + } + + if((cd_bin.last_track == -1) || + (new_track_number > cd_bin.last_track)) + { + cd_bin.last_track = new_track_number; + } + + break; + } + + // Pregap + case 'P': + { + u32 minutes, seconds, frames; + + sscanf(line_buffer_ptr, "PREGAP %d:%d:%d", &minutes, + &seconds, &frames); + + current_pregap += frames + (seconds * 75) + (minutes * 75 * 60); + break; + } + + // Index + case 'I': + { + u32 index_number; + u32 minutes, seconds, frames; + u32 sector_offset; + + sscanf(line_buffer_ptr, "INDEX %d %d:%d:%d", &index_number, + &minutes, &seconds, &frames); + + sector_offset = frames + (seconds * 75) + (minutes * 75 * 60); + + if(index_number == 1) + { + current_physical_track->pregap_offset = current_pregap; + current_physical_track->sector_offset = sector_offset; + } + + break; + } + } + } + + current_physical_offset = 0; + + for(i = 0; i < cd_bin.num_physical_tracks - 1; i++) + { + cd_bin.physical_tracks[i].sector_count = + cd_bin.physical_tracks[i + 1].sector_offset - + cd_bin.physical_tracks[i].sector_offset; + + cd_bin.physical_tracks[i].physical_offset = current_physical_offset; + current_physical_offset += (cd_bin.physical_tracks[i].sector_count * + cd_bin.physical_tracks[i].sector_size); + + cd_bin.physical_tracks[i].sector_offset += + cd_bin.physical_tracks[i].pregap_offset; + + cd_bin.num_sectors += cd_bin.physical_tracks[i].sector_count; + } + +#ifdef GP2X_BUILD + bin_file_size = lseek(cd_bin.bin_file, 0, SEEK_END); + lseek(cd_bin.bin_file, 0, SEEK_SET); +#else + fseek(cd_bin.bin_file, 0, SEEK_END); + bin_file_size = ftell(cd_bin.bin_file); + fseek(cd_bin.bin_file, 0, SEEK_SET); +#endif + + // Set the last track data + cd_bin.physical_tracks[i].physical_offset = current_physical_offset; + cd_bin.physical_tracks[i].sector_offset += + cd_bin.physical_tracks[i].pregap_offset; + cd_bin.physical_tracks[i].sector_count = + (bin_file_size - current_physical_offset) / + cd_bin.physical_tracks[i].sector_size; + + cd_bin.num_sectors += cd_bin.physical_tracks[i].sector_count; + + printf("finished loading cue %s\n", cue_file_name); + printf("bin file: %s (%p)\n", bin_file_name, cd_bin.bin_file); + printf("first track: %d, last track: %d\n", cd_bin.first_track, + cd_bin.last_track); + + for(i = cd_bin.first_track; i <= cd_bin.last_track; i++) + { + printf("track %d (%p):\n", i, cd_bin.logical_tracks[i]); + if(cd_bin.logical_tracks[i] == NULL) + { + printf(" (invalid)\n"); + } + else + { + printf(" physical offset 0x%x\n", + cd_bin.logical_tracks[i]->physical_offset); + printf(" sector offset 0x%x\n", + cd_bin.logical_tracks[i]->sector_offset); + printf(" sector size %d\n", + cd_bin.logical_tracks[i]->sector_size); + } + } + + cd_bin.last_seek_track = 0; + + fclose(cue_file); + return 0; + } + + return -1; +} + +#define address8(base, offset) \ + *((u8 *)((u8 *)base + (offset))) \ + +#define address16(base, offset) \ + *((u16 *)((u8 *)base + (offset))) \ + +#define address32(base, offset) \ + *((u32 *)((u8 *)base + (offset))) \ + +// This will only work on little endian platforms for now. + +s32 convert_bin_to_wav(FILE *bin_file, char *output_dir, char *wav_file_name, + u32 sector_count) +{ + FILE *wav_file; + u8 wav_header[36]; + u8 *riff_header = wav_header + 0; + u8 *fmt_header = wav_header + 0x0C; + u8 sector_buffer[2352]; + u32 byte_length = sector_count * 2352; + u32 i; + + chdir(output_dir); + wav_file = fopen(wav_file_name, "wb"); + + printf("writing wav %s, %x sectors\n", wav_file_name, sector_count); + + // RIFF type chunk + memcpy(riff_header + 0x00, "RIFF", 4); + address32(riff_header, 0x04) = byte_length + 44 - 8; + memcpy(riff_header + 0x08, "WAVE", 4); + + // WAVE file chunk: format + memcpy(fmt_header + 0x00, "fmt ", 4); + // Chunk data size + address32(fmt_header, 0x04) = 16; + // Compression code: PCM + address16(fmt_header, 0x08) = 1; + // Number of channels: Stereo + address16(fmt_header, 0x0a) = 2; + // Sample rate: 44100Hz + address32(fmt_header, 0x0c) = 44100; + // Average bytes per second: sample rate * 4 + address32(fmt_header, 0x10) = 44100 * 4; + // Block align (bytes per sample) + address16(fmt_header, 0x14) = 4; + // Bit depth + address16(fmt_header, 0x16) = 16; + + // Write out header + fwrite(wav_header, 36, 1, wav_file); + + // DATA chunk + fprintf(wav_file, "data"); + // length + fwrite(&byte_length, 4, 1, wav_file); + + // Write out sectors + for(i = 0; i < sector_count; i++) + { + printf("\b\b\b%3i", i*100 / sector_count); + fflush(stdout); + fread(sector_buffer, 2352, 1, bin_file); + fwrite(sector_buffer, 2352, 1, wav_file); + } + printf("\b\b\b100\n"); + + fclose(wav_file); + chdir(".."); + return 0; +} + +void convert_wav_to_ogg(char *wav_file_name, char *output_dir, + char *ogg_file_name) +{ + char cmd_string[(MAX_PATH * 2) + 16]; + + chdir(output_dir); + sprintf(cmd_string, "oggenc %s", wav_file_name); + system(cmd_string); + + unlink(wav_file_name); + chdir(".."); +} + +void convert_wav_to_mp3(char *wav_file_name, char *output_dir, + char *mp3_file_name) +{ + char cmd_string[(MAX_PATH * 2) + 16]; + + chdir(output_dir); + sprintf(cmd_string, LAME_BINARY " " LAME_OPTIONS " -b %i \"%s\" \"%s\"", + opt_mp3_bitrate, wav_file_name, mp3_file_name); + if (system(cmd_string) != 0) + { + printf("failed to encode mp3\n"); + myexit(1); + } + + unlink(wav_file_name); + chdir(".."); +} + +s32 convert_bin_to_iso(FILE *bin_file, char *output_dir, char *iso_file_name, + u32 sector_count) +{ + FILE *iso_file; + u8 sector_buffer[2352]; + u32 i; + + chdir(output_dir); + iso_file = fopen(iso_file_name, "wb"); + if (iso_file == NULL) + { + printf("failed to open: %s\n", iso_file_name); + myexit(1); + } + printf("writing iso %s, %x sectors\n", iso_file_name, sector_count); + + for(i = 0; i < sector_count; i++) + { + printf("\b\b\b%3i", i*100 / sector_count); + fflush(stdout); + fread(sector_buffer, 2352, 1, bin_file); + fwrite(sector_buffer + 16, 2048, 1, iso_file); + } + printf("\b\b\b100\n"); + + fclose(iso_file); + chdir(".."); + return 0; +} + +void convert_iso_to_cso(char *output_dir, char *iso_file_name, char *cso_file_name) +{ + char cmd_string[(MAX_PATH * 2) + 16]; + + chdir(output_dir); + sprintf(cmd_string, CISO_BINARY " 9 \"%s\" \"%s\"", iso_file_name, cso_file_name); + if (system(cmd_string) != 0) + { + printf("failed to convert iso to cso\n"); + myexit(1); + } + + unlink(iso_file_name); + chdir(".."); +} + + +#define sector_offset_to_msf(offset, minutes, seconds, frames) \ +{ \ + u32 _offset = offset; \ + minutes = (_offset / 75) / 60; \ + seconds = (_offset / 75) % 60; \ + frames = _offset % 75; \ +} \ + + +s32 convert_bin_cue(char *output_name_base) +{ + char output_file_name[MAX_PATH]; + FILE *output_cue_file; + FILE *bin_file = cd_bin.bin_file; + cd_track_struct *current_track; + u32 m, s, f; + u32 current_pregap = 0; + u32 last_pregap = 0; + u32 i; + struct stat sb; + + if(stat(output_name_base, &sb)) + mkdir(output_name_base); + + sprintf(output_file_name, "%s.cue", output_name_base); + chdir(output_name_base); + output_cue_file = fopen(output_file_name, "wb"); + chdir(".."); + + // Every track gets its own file. It's either going to be of type ISO + // or of type WAV. + + for(i = 0; i < 100; i++) + { + current_track = cd_bin.logical_tracks[i]; + if(current_track != NULL) + { + switch(current_track->format_type) + { + char output_name_tmp[MAX_PATH]; + + // Audio + case 0: + { + sprintf(output_file_name, "%s_%02d.mp3", output_name_base, i); + sprintf(output_name_tmp, "%s_%02d.wav", output_name_base, i); + + fprintf(output_cue_file, "FILE \"%s\" %s\n", + opt_use_mp3 ? output_file_name : output_name_tmp, + opt_use_mp3 ? "MP3" : "WAVE"); + fprintf(output_cue_file, " TRACK %02d AUDIO\n", i); + current_pregap = current_track->pregap_offset - last_pregap; + last_pregap = current_track->pregap_offset; + if(current_pregap > 0) + { + sector_offset_to_msf(current_pregap, m, s, f); + fprintf(output_cue_file, " PREGAP %02d:%02d:%02d\n", m, s, f); + } + fprintf(output_cue_file, " INDEX 01 00:00:00\n"); + sector_offset_to_msf(current_track->sector_count, m, s, f); + fprintf(output_cue_file, " REM LENGTH %02d:%02d:%02d\n", m, s, f); + + fseek(bin_file, current_track->physical_offset, SEEK_SET); + convert_bin_to_wav(bin_file, output_name_base, output_name_tmp, + current_track->sector_count); + if(opt_use_mp3) + { + convert_wav_to_mp3(output_name_tmp, output_name_base, + output_file_name); + } + break; + } + + // Data + default: + sprintf(output_file_name, "%s_%02d.cso", output_name_base, i); + sprintf(output_name_tmp, "%s_%02d.iso", output_name_base, i); + fprintf(output_cue_file, "FILE \"%s\" BINARY\n", + opt_use_cso ? output_file_name : output_name_tmp); + fprintf(output_cue_file, " TRACK %02d MODE1/2048\n", i); + current_pregap = current_track->pregap_offset - last_pregap; + last_pregap = current_track->pregap_offset; + if(current_pregap > 0) + { + sector_offset_to_msf(current_pregap, m, s, f); + fprintf(output_cue_file, " PREGAP %02d:%02d:%02d\n", m, s, f); + } + fprintf(output_cue_file, " INDEX 01 00:00:00\n"); + + fseek(bin_file, current_track->physical_offset, SEEK_SET); + convert_bin_to_iso(bin_file, output_name_base, output_name_tmp, + current_track->sector_count); + if(opt_use_cso) + { + convert_iso_to_cso(output_name_base, output_name_tmp, output_file_name); + } + break; + } + } + } + + fclose(output_cue_file); + + return 0; +} + +#ifdef _WIN32 +static void update_path(void) +{ + char buff1[MAX_PATH], buff2[MAX_PATH]; + char *path; + int i; + + path = getenv("PATH"); + GetModuleFileNameA(NULL, buff1, sizeof(buff1)); + for (i = strlen(buff1)-1; i > 0; i--) + if (buff1[i] == '\\') break; + buff1[i] = 0; + + snprintf(buff2, sizeof(buff2), "%s;%s", path, buff1); + SetEnvironmentVariableA("PATH", buff2); +} +#endif + +int main(int argc, char *argv[]) +{ + char out_buff[MAX_PATH], *cue_file, *out_base; + int a; + + if(argc < 2) + { + printf("bin/cue to cso/mp3 converter\n"); + printf("usage: %s [options] [output base]\n", argv[0]); + printf("options:\n" + " -m output mp3 files for audio (default) (lame required)\n" + " -b mp3 bitrate to use (default is 128)\n" + " -w output wav files for audio\n" + " -c output cso as data track (default) (ciso required)\n" + " -i output iso as data track\n"); + return 0; + } + + for (a = 1; a < argc - 1; a++) + { + if (strcmp(argv[a], "-m") == 0) + opt_use_mp3 = 1; + else if (strcmp(argv[a], "-w") == 0) + opt_use_mp3 = 0; + else if (strcmp(argv[a], "-c") == 0) + opt_use_cso = 1; + else if (strcmp(argv[a], "-i") == 0) + opt_use_cso = 0; + else if (strcmp(argv[a], "-b") == 0) + { + opt_mp3_bitrate = atoi(argv[++a]); + } + else + break; + } + cue_file = argv[a]; + out_base = argv[a+1]; + + /* some sanity checks */ + if(strlen(cue_file) < 4 || strcasecmp(cue_file + strlen(cue_file) - 4, ".cue") != 0) + { + printf("error: not a cue file specified?\n"); + myexit(1); + } + +#ifdef _WIN32 + update_path(); +#endif + + if(opt_use_mp3 && system(LAME_BINARY " --help " NULL_REDIR) != 0) + { + printf("LAME seems to be missing.\n" +#ifdef _WIN32 + "Download from http://lame.sourceforge.net/links.php#Binaries and extract\n" + "lame.exe to the same directory as %s\n", argv[0] +#else + "Install lame using your packet manager, obtain binaries or build from\n" + "sources at http://lame.sourceforge.net/\n" +#endif + ); + myexit(1); + } + + if(opt_use_cso && system(CISO_BINARY " " NULL_REDIR) != 0) + { + printf("CISO seems to be missing.\n" +#ifdef _WIN32 + "Download ciso.exe and extract to the same directory as %s\n" + "You can take ciso.exe from yacc at http://yacc.pspgen.com/\n", argv[0] +#else + "Install ciso using your packet manager, obtain binaries or build from\n" + "sources at http://ciso.tenshu.fr/\n" +#endif + ); + myexit(1); + } + + if(load_bin_cue(cue_file) == 0) + { + if(out_base == NULL) + { + char *p; + strncpy(out_buff, cue_file, sizeof(out_buff)); + out_buff[sizeof(out_buff)-1] = 0; + p = strrchr(out_buff, DIR_SEPARATOR_CHAR); + if (p != NULL) + { + *p++ = 0; + chdir(out_buff); + memmove(out_buff, p, strlen(p)+1); + } + out_buff[strlen(out_buff)-4] = 0; + out_base = out_buff; + } + if(convert_bin_cue(out_base) != 0) + myexit(1); + } + else + { + printf("error: could not load cue file %s\n", cue_file); + myexit(1); + } + + return 0; +} + diff --git a/tools/bin_to_cso_mp3/bin_to_cso_mp3.exe b/tools/bin_to_cso_mp3/bin_to_cso_mp3.exe new file mode 100755 index 0000000000000000000000000000000000000000..733795cbb4926cfa6fb6a9ef04a518c7eb50e161 GIT binary patch literal 31860 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

f1Zgit0 z^llA(sfPZ5hQ3@wZzu_UmxjJvLyv0c%^G^JB=jx~y+K3YsG(Oo=(0b&5tPZ=yXp^} z_)+~~QH;s>X;xN13-9q}_lG2($InIj!}-b^7wHe1Z8>nJ=TQA&=pz16{oz|^dsE_K zI?GwXs!Q8`<5Mbrd^0?jJKqXXtcuu(IKSnKbw<^9L)Ridh|;*w^Uhlt3Ep4IO;F3G zT$U!jt-$wI+|EU~(0_WNQB+XY;W8jShIMpuF_(DvrAloA&n}yX1X2G@2VKPN!?C|@TY7y5TK%D=fNrdWQ*#9JC=#jD^+xb*oQD37=(QvqGg zYe$v33KaF-sIaS%)Wbm+LAe#T?r3SHOqZn}2W8Mzr!+E%?}-%Fr$JF;laTzkpomdV z@f-!k?TsI5l%IgI(Ph^!KsjYoOcR@tVC@+lj-TmyQN526==7G<;W6cc$U#>`y$d}3 zj%2wwvDw9Q9eC92R7j>hUJ-Xi=&M25W6Po37UHpeh+i_(Qcw1POY&CmoOG4?I4Fm0 ziYXUs4!KG_0Unwo6M)cXFK*p6_-#;9jvNyUUn8Q<$=$r2V*L;FakZ3}NFkSM zW&2z@?OXP_K+Q7(Wo>Z1Gsl(Q~MCH;^MVx87B7nBhfPdzA4yC};*x!|I#28HTM$e~5o zwCuRs_75$(j#A6*R&9rm7g#?0fU9r$800kBl1;S?*_K1LcY$Z49jm5VI_;A4IC!2b zl7q1cOOjJIk0}>22W<*Teg>uXI;F(IYG$~24uFSh!|~WrqS$s(?hiqsj@{uo1In;1 znRtEy%03rm6qJICGNpnz=|Hs5N-2hH&v6xa4!TOs2c_MnsMYW(S3A9#B)fF}5GV_s zQm8>%W8ZI=GR5+8R_*eJiBbkcIqftFO3;==%03MW2u0p_4iq{Z|9nTvK`8PlNAE}! zSG~Us%1bWEL!cb7DHKt(sJz*w;eUf?x6MPSzXyd5>hcH=|3(l$iX3v4dJiaFb}3UV z!)M(to`v*NN*sHeuY%%^jn}D^&11?1`-fcUmtkSvY!q~A@ExEW zwM*3^RUeJDX18FL(@Hz69*fy2IJ`OSTl3O~nW=!o0VTx@c(!nO= zn0)b>iKPnnTH&;nO^KBj#pw^nJJ(`iOfktcKeWV92Dx5eT9^b7+=n(oR^W+!~4# zu+W8e!Ln&c(BczehNWWh>z6Ju z@xM2%ct;F|W4!<-DQU8~`1knSE)eC9+gb7Yg1Q9ug2RK7tWkHZ71t-PL2teDzF+*9 z84gpMWB{J3CA4l81_~tBx2)T+dTq#TzBkme>TYv=XwBU#)$RkP8SlVO9&((KDSIOh z%oDK<6;KcoLRRtGVH2B;OtcY6a4Ar^Sn)7XzdaV-S`VePz3)JrIA(ZhwKoWuprRPz z33IXyPAHJ?(DqgdHZCS7Scy!L9r%&F*hj()qjp4`a!j#33U)6+5Sqz0DiYa>;OOXx z3lF$6XthFmTa5drBm7`8ZDz8qqFI~R!!3ht%7ovry3OoL6lq{`N_+x}7~oY^6z{X5 zXtZ~VW2xLNhBsrfE18IrMMak39da?w23#VMh%S~BCji~Kkq*`!&(N;AS z1Udx`gB+16R!34?X7e3rq+B_7ktzOU$Ga;yJDG8Lnb)9P@MxM)K57nO%)B~|QC1I*%m zOJpW`4w~PX*lv$j8lpeuTjMEXFVaO&3GALnr4+Y#9FUUblbcdPY;L1c;vETk1#B-d zQJu*tj1tVB9i6g#`y5*5NiBAwAhNrW;>P9b`$S!;ZG@y~IfZt*58i-^I|<=$tH|F@ zhhayEobM>1VjCkzdzyhy)SD_}#p99W=Y6}qag*!_Rb=qG_Qs%V>{2o>(d|lC#yhBe z6?c3zXvflgSC9;EQ51|c>O(Lhm~ZzaHML_`L?GXUNf`l;@ZF%CR<|{l?u;d_Uu=dU z$=M)E6%boZseZ!oaj|Zg@}T;4onCSO converters, for example yacc + (http://yacc.pspgen.com/). Extract ciso.exe to the directory from previous + step. +3. Drag the .cue file you want to convert onto bin_to_cso_mp3.exe . It should + pop up console window with some scrolling text, which should close by itself + when done. After that you should see new directory with converted files. + + +Advanced usage +-------------- + +Just run bin_to_cso_mp3.exe from console terminal (or "command prompt") without +any parameters to see usage. + + +Linux +----- + +You will need to compile bin_to_cso_mp3.c yourself using gcc: +$ gcc bin_to_cso_mp3.c -o bin_to_cso_mp3 + +You will also need to have lame and ciso binaries in PATH. Those can sometimes +be installed using packet manager from the distribution, or you can compile +them from sources: +lame: http://lame.sourceforge.net/ +ciso: http://ciso.tenshu.fr/ + -- 2.39.2