platform ps2, handle audio similar to psp
[picodrive.git] / tools / bin_to_cso_mp3 / bin_to_cso_mp3.c
1 /*\r
2  * bin_to_cso_mp3\r
3  * originally written by Exophase as "bin_to_iso_ogg"\r
4  * updated for cso/mp3 by notaz\r
5  * v2\r
6  */\r
7 #include <stdio.h>\r
8 #include <stdlib.h>\r
9 #include <unistd.h>\r
10 #include <sys/stat.h>\r
11 #include <string.h>\r
12 #include <ctype.h>\r
13 #include <stdint.h>\r
14 \r
15 #ifndef MAX_PATH\r
16 #define MAX_PATH 1024\r
17 #endif\r
18 \r
19 #ifdef _WIN32\r
20 #include <windows.h>\r
21 \r
22 #define DIR_SEPARATOR_CHAR '\\'\r
23 #define PATH_SEPARATOR_CHAR ';'\r
24 #define LAME_BINARY "lame.exe"\r
25 #define CISO_BINARY "ciso.exe"\r
26 #define NULL_REDIR  "> NUL 2>&1"\r
27 #else\r
28 #define DIR_SEPARATOR_CHAR '/'\r
29 #define PATH_SEPARATOR_CHAR ':'\r
30 #define LAME_BINARY "lame"\r
31 #define CISO_BINARY "ciso"\r
32 #define NULL_REDIR  "> /dev/null 2>&1"\r
33 #define mkdir(x) mkdir(x, S_IRWXU)\r
34 #endif\r
35 \r
36 #define LAME_OPTIONS "-h --cbr"\r
37 \r
38 typedef uint8_t u8;\r
39 typedef uint16_t u16;\r
40 typedef uint32_t u32;\r
41 typedef uint64_t u64;\r
42 typedef int8_t s8;\r
43 typedef int16_t s16;\r
44 typedef int32_t s32;\r
45 typedef int64_t s64;\r
46 \r
47 typedef enum\r
48 {\r
49   TRACK_FILE_TYPE_BINARY,\r
50   TRACK_FILE_TYPE_WAVE,\r
51 } track_file_type_enum;\r
52 \r
53 typedef struct\r
54 {\r
55   u32 file_number;\r
56   u32 physical_offset;\r
57 \r
58   u32 sector_offset;\r
59   u32 sector_count;\r
60   u32 pregap_offset;\r
61 \r
62   u32 sector_size;\r
63   u32 format_type;\r
64 } cd_track_struct;\r
65 \r
66 typedef struct\r
67 {\r
68   track_file_type_enum type;\r
69   FILE *file_handle;\r
70 \r
71   u32 current_offset;\r
72 } cd_track_file_struct;\r
73 \r
74 typedef struct\r
75 {\r
76   FILE *bin_file;\r
77   cd_track_file_struct track_files[100];\r
78   u32 num_files;\r
79 \r
80   s32 first_track;\r
81   s32 last_track;\r
82   u32 num_physical_tracks;\r
83   u32 num_sectors;\r
84   s32 last_seek_track;\r
85 \r
86   cd_track_struct physical_tracks[100];\r
87   cd_track_struct *logical_tracks[100];\r
88 } cd_bin_struct;\r
89 \r
90 \r
91 cd_bin_struct cd_bin;\r
92 int opt_use_mp3 = 1;\r
93 int opt_mp3_bitrate = 128;\r
94 int opt_use_cso = 1;\r
95 \r
96 static void myexit(int code)\r
97 {\r
98 #ifdef _WIN32\r
99   system("pause");\r
100 #endif\r
101   exit(code);\r
102 }\r
103 \r
104 char *skip_whitespace(char *str)\r
105 {\r
106   while (isspace(*str))\r
107     str++;\r
108 \r
109   return str;\r
110 }\r
111 \r
112 char *skip_whitespace_rev(char *str)\r
113 {\r
114   while (isspace(*str))\r
115     str--;\r
116 \r
117   return str;\r
118 }\r
119 \r
120 char *skip_nonspace_rev(char *str)\r
121 {\r
122   while (!isspace(*str))\r
123     str--;\r
124 \r
125   return str;\r
126 }\r
127 \r
128 s32 load_bin_cue(char *cue_file_name)\r
129 {\r
130   FILE *cue_file = fopen(cue_file_name, "rb");\r
131 \r
132   printf("loading cue file %s\n", cue_file_name);\r
133 \r
134   if(cue_file)\r
135   {\r
136     char line_buffer[256];\r
137     char *line_buffer_ptr;\r
138     char *tmp;\r
139 \r
140     char bin_file_name[MAX_PATH];\r
141     char *separator_pos;\r
142     s32 current_physical_track_number = -1;\r
143     u32 current_physical_offset;\r
144     u32 current_pregap = 0;\r
145     u32 bin_file_size;\r
146 \r
147     cd_track_struct *current_physical_track = NULL;\r
148 \r
149     u32 i;\r
150 \r
151     // First, get filename. Only support binary right now.\r
152     tmp = fgets(line_buffer, 255, cue_file);\r
153     if (tmp == NULL) goto invalid;\r
154     separator_pos = line_buffer + strlen(line_buffer) - 1;\r
155     separator_pos = skip_whitespace_rev(separator_pos);\r
156     if (separator_pos <= line_buffer) goto invalid;\r
157     separator_pos = skip_nonspace_rev(separator_pos);\r
158     if (separator_pos <= line_buffer) goto invalid;\r
159     separator_pos = skip_whitespace_rev(separator_pos);\r
160     if (separator_pos <= line_buffer) goto invalid;\r
161     // see if what's there is a quote.\r
162     if(*separator_pos == '"')\r
163     {\r
164       separator_pos[0] = 0;\r
165       separator_pos = strrchr(line_buffer, '"');\r
166       if (separator_pos == NULL) goto invalid;\r
167       strcpy(bin_file_name, separator_pos + 1);\r
168     }\r
169     else\r
170     {\r
171       // Otherwise go to the next space.\r
172       separator_pos[1] = 0;\r
173       separator_pos = strrchr(line_buffer, ' ');\r
174       if (separator_pos == NULL) goto invalid;\r
175       strcpy(bin_file_name, separator_pos + 1);\r
176     }\r
177 \r
178     // Might have to change directory first.\r
179     separator_pos = strrchr(cue_file_name, DIR_SEPARATOR_CHAR);\r
180 \r
181     if(separator_pos)\r
182     {\r
183       char current_dir[MAX_PATH];\r
184       getcwd(current_dir, MAX_PATH);\r
185 \r
186       *separator_pos = 0;\r
187 \r
188       chdir(cue_file_name);\r
189 \r
190 #ifdef GP2X_BUILD\r
191       cd_bin.bin_file = open(bin_file_name, O_RDONLY);\r
192 #else\r
193       cd_bin.bin_file = fopen(bin_file_name, "rb");\r
194 #endif\r
195 \r
196       *separator_pos = DIR_SEPARATOR_CHAR;\r
197       chdir(current_dir);\r
198     }\r
199     else\r
200     {\r
201 #ifdef GP2X_BUILD\r
202       cd_bin.bin_file = open(bin_file_name, O_RDONLY);\r
203 #else\r
204       cd_bin.bin_file = fopen(bin_file_name, "rb");\r
205 #endif\r
206     }\r
207 \r
208     if (cd_bin.bin_file == NULL)\r
209     {\r
210       printf("can't open bin file: \"%s\"\n", bin_file_name);\r
211       return -1;\r
212     }\r
213     else\r
214     {\r
215       printf("found bin file: %s\n", bin_file_name);\r
216     }\r
217 \r
218     for(i = 0; i < 100; i++)\r
219     {\r
220       cd_bin.logical_tracks[i] = NULL;\r
221     }\r
222 \r
223     cd_bin.first_track = -1;\r
224     cd_bin.last_track = -1;\r
225     cd_bin.num_physical_tracks = 0;\r
226     cd_bin.num_sectors = 0;\r
227 \r
228     // Get line\r
229     while(fgets(line_buffer, 256, cue_file))\r
230     {\r
231       // Skip trailing whitespace\r
232       line_buffer_ptr = skip_whitespace(line_buffer);\r
233 \r
234       // Dirty, but should work - switch on first character.\r
235       switch(line_buffer_ptr[0])\r
236       {\r
237         // New track number\r
238         case 'T':\r
239         {\r
240           u32 new_track_number;\r
241           char track_type[64];\r
242 \r
243           sscanf(line_buffer_ptr, "TRACK %d %s", &new_track_number,\r
244            track_type);\r
245 \r
246           current_physical_track_number++;\r
247           current_physical_track =\r
248            cd_bin.physical_tracks + current_physical_track_number;\r
249 \r
250           current_physical_track->sector_size = 2352;\r
251 \r
252           if(!strcmp(track_type, "AUDIO"))\r
253           {\r
254             current_physical_track->format_type = 0;\r
255             current_physical_track->sector_size = 2352;\r
256           }\r
257 \r
258           if(!strcmp(track_type, "MODE1/2352"))\r
259           {\r
260             current_physical_track->format_type = 4;\r
261             current_physical_track->sector_size = 2352;\r
262           }\r
263 \r
264           if(!strcmp(track_type, "MODE1/2048"))\r
265           {\r
266             current_physical_track->format_type = 4;\r
267             current_physical_track->sector_size = 2048;\r
268           }\r
269 \r
270           cd_bin.logical_tracks[new_track_number] = current_physical_track;\r
271           cd_bin.num_physical_tracks++;\r
272 \r
273           if((cd_bin.first_track == -1) ||\r
274            (new_track_number < cd_bin.first_track))\r
275           {\r
276             cd_bin.first_track = new_track_number;\r
277           }\r
278 \r
279           if((cd_bin.last_track == -1) ||\r
280            (new_track_number > cd_bin.last_track))\r
281           {\r
282             cd_bin.last_track = new_track_number;\r
283           }\r
284 \r
285           break;\r
286         }\r
287 \r
288         // Pregap\r
289         case 'P':\r
290         {\r
291           u32 minutes, seconds, frames;\r
292 \r
293           sscanf(line_buffer_ptr, "PREGAP %d:%d:%d", &minutes,\r
294            &seconds, &frames);\r
295 \r
296           current_pregap += frames + (seconds * 75) + (minutes * 75 * 60);\r
297           break;\r
298         }\r
299 \r
300         // Index\r
301         case 'I':\r
302         {\r
303           u32 index_number;\r
304           u32 minutes, seconds, frames;\r
305           u32 sector_offset;\r
306 \r
307           sscanf(line_buffer_ptr, "INDEX %d %d:%d:%d", &index_number,\r
308            &minutes, &seconds, &frames);\r
309 \r
310           sector_offset = frames + (seconds * 75) + (minutes * 75 * 60);\r
311 \r
312           if(index_number == 1)\r
313           {\r
314             current_physical_track->pregap_offset = current_pregap;\r
315             current_physical_track->sector_offset = sector_offset;\r
316           }\r
317 \r
318           break;\r
319         }\r
320       }\r
321     }\r
322 \r
323     current_physical_offset = 0;\r
324 \r
325     for(i = 0; i < cd_bin.num_physical_tracks - 1; i++)\r
326     {\r
327       cd_bin.physical_tracks[i].sector_count =\r
328        cd_bin.physical_tracks[i + 1].sector_offset -\r
329        cd_bin.physical_tracks[i].sector_offset;\r
330 \r
331       cd_bin.physical_tracks[i].physical_offset = current_physical_offset;\r
332       current_physical_offset += (cd_bin.physical_tracks[i].sector_count *\r
333        cd_bin.physical_tracks[i].sector_size);\r
334 \r
335       cd_bin.physical_tracks[i].sector_offset +=\r
336        cd_bin.physical_tracks[i].pregap_offset;\r
337 \r
338       cd_bin.num_sectors += cd_bin.physical_tracks[i].sector_count;\r
339     }\r
340 \r
341 #ifdef GP2X_BUILD\r
342     bin_file_size = lseek(cd_bin.bin_file, 0, SEEK_END);\r
343     lseek(cd_bin.bin_file, 0, SEEK_SET);\r
344 #else\r
345     fseek(cd_bin.bin_file, 0, SEEK_END);\r
346     bin_file_size = ftell(cd_bin.bin_file);\r
347     fseek(cd_bin.bin_file, 0, SEEK_SET);\r
348 #endif\r
349 \r
350     // Set the last track data\r
351     cd_bin.physical_tracks[i].physical_offset = current_physical_offset;\r
352     cd_bin.physical_tracks[i].sector_offset +=\r
353      cd_bin.physical_tracks[i].pregap_offset;\r
354     cd_bin.physical_tracks[i].sector_count =\r
355      (bin_file_size - current_physical_offset) /\r
356      cd_bin.physical_tracks[i].sector_size;\r
357 \r
358     cd_bin.num_sectors += cd_bin.physical_tracks[i].sector_count;\r
359 \r
360     printf("finished loading cue %s\n", cue_file_name);\r
361     printf("bin file: %s (%p)\n", bin_file_name, cd_bin.bin_file);\r
362     printf("first track: %d, last track: %d\n", cd_bin.first_track,\r
363      cd_bin.last_track);\r
364 \r
365     for(i = cd_bin.first_track; i <= cd_bin.last_track; i++)\r
366     {\r
367       printf("track %d (%p):\n", i, cd_bin.logical_tracks[i]);\r
368       if(cd_bin.logical_tracks[i] == NULL)\r
369       {\r
370         printf("  (invalid)\n");\r
371       }\r
372       else\r
373       {\r
374         printf("  physical offset 0x%x\n",\r
375          cd_bin.logical_tracks[i]->physical_offset);\r
376         printf("  sector offset 0x%x\n",\r
377          cd_bin.logical_tracks[i]->sector_offset);\r
378         printf("  sector size %d\n",\r
379          cd_bin.logical_tracks[i]->sector_size);\r
380       }\r
381     }\r
382 \r
383     cd_bin.last_seek_track = 0;\r
384 \r
385     fclose(cue_file);\r
386     return 0;\r
387   }\r
388 \r
389   return -1;\r
390 invalid:\r
391   printf("error: invalid/unsupported .cue file\n");\r
392   return -1;\r
393 }\r
394 \r
395 #define address8(base, offset)                                                \\r
396   *((u8 *)((u8 *)base + (offset)))                                            \\r
397 \r
398 #define address16(base, offset)                                               \\r
399   *((u16 *)((u8 *)base + (offset)))                                           \\r
400 \r
401 #define address32(base, offset)                                               \\r
402   *((u32 *)((u8 *)base + (offset)))                                           \\r
403 \r
404 // This will only work on little endian platforms for now.\r
405 \r
406 s32 convert_bin_to_wav(FILE *bin_file, char *output_dir, char *wav_file_name,\r
407  u32 sector_count)\r
408 {\r
409   FILE *wav_file;\r
410   u8 wav_header[36];\r
411   u8 *riff_header = wav_header + 0;\r
412   u8 *fmt_header = wav_header + 0x0C;\r
413   u8 sector_buffer[2352];\r
414   u32 byte_length = sector_count * 2352;\r
415   u32 i;\r
416 \r
417   chdir(output_dir);\r
418   wav_file = fopen(wav_file_name, "wb");\r
419 \r
420   printf("writing wav %s, %x sectors\n", wav_file_name, sector_count);\r
421 \r
422   // RIFF type chunk\r
423   memcpy(riff_header   + 0x00, "RIFF", 4);\r
424   address32(riff_header, 0x04) = byte_length + 44 - 8;\r
425   memcpy(riff_header   + 0x08, "WAVE", 4);\r
426 \r
427   // WAVE file chunk: format\r
428   memcpy(fmt_header   + 0x00, "fmt ", 4);\r
429   // Chunk data size\r
430   address32(fmt_header, 0x04) = 16;\r
431   // Compression code: PCM\r
432   address16(fmt_header, 0x08) = 1;\r
433   // Number of channels: Stereo\r
434   address16(fmt_header, 0x0a) = 2;\r
435   // Sample rate: 44100Hz\r
436   address32(fmt_header, 0x0c) = 44100;\r
437   // Average bytes per second: sample rate * 4\r
438   address32(fmt_header, 0x10) = 44100 * 4;\r
439   // Block align (bytes per sample)\r
440   address16(fmt_header, 0x14) = 4;\r
441   // Bit depth\r
442   address16(fmt_header, 0x16) = 16;\r
443 \r
444   // Write out header\r
445   fwrite(wav_header, 36, 1, wav_file);\r
446 \r
447   // DATA chunk\r
448   fprintf(wav_file, "data");\r
449   // length\r
450   fwrite(&byte_length, 4, 1, wav_file);\r
451 \r
452   // Write out sectors\r
453   for(i = 0; i < sector_count; i++)\r
454   {\r
455     printf("\b\b\b%3i", i*100 / sector_count);\r
456     fflush(stdout);\r
457     fread(sector_buffer, 2352, 1, bin_file);\r
458     fwrite(sector_buffer, 2352, 1, wav_file);\r
459   }\r
460   printf("\b\b\b100\n");\r
461 \r
462   fclose(wav_file);\r
463   chdir("..");\r
464   return 0;\r
465 }\r
466 \r
467 void convert_wav_to_ogg(char *wav_file_name, char *output_dir,\r
468  char *ogg_file_name)\r
469 {\r
470   char cmd_string[(MAX_PATH * 2) + 16];\r
471 \r
472   chdir(output_dir);\r
473   sprintf(cmd_string, "oggenc %s", wav_file_name);\r
474   system(cmd_string);\r
475 \r
476   unlink(wav_file_name);\r
477   chdir("..");\r
478 }\r
479 \r
480 void convert_wav_to_mp3(char *wav_file_name, char *output_dir,\r
481  char *mp3_file_name)\r
482 {\r
483   char cmd_string[(MAX_PATH * 2) + 16];\r
484 \r
485   chdir(output_dir);\r
486   sprintf(cmd_string, LAME_BINARY " " LAME_OPTIONS " -b %i \"%s\" \"%s\"",\r
487    opt_mp3_bitrate, wav_file_name, mp3_file_name);\r
488   if (system(cmd_string) != 0)\r
489   {\r
490     printf("failed to encode mp3\n");\r
491     myexit(1);\r
492   }\r
493 \r
494   unlink(wav_file_name);\r
495   chdir("..");\r
496 }\r
497 \r
498 s32 convert_bin_to_iso(FILE *bin_file, char *output_dir, char *iso_file_name,\r
499  u32 sector_count)\r
500 {\r
501   FILE *iso_file;\r
502   u8 sector_buffer[2352];\r
503   u32 i;\r
504 \r
505   chdir(output_dir);\r
506   iso_file = fopen(iso_file_name, "wb");\r
507   if (iso_file == NULL)\r
508   {\r
509     printf("failed to open: %s\n", iso_file_name);\r
510     myexit(1);\r
511   }\r
512   printf("writing iso %s, %x sectors\n", iso_file_name, sector_count);\r
513 \r
514   for(i = 0; i < sector_count; i++)\r
515   {\r
516     printf("\b\b\b%3i", i*100 / sector_count);\r
517     fflush(stdout);\r
518     fread(sector_buffer, 2352, 1, bin_file);\r
519     fwrite(sector_buffer + 16, 2048, 1, iso_file);\r
520   }\r
521   printf("\b\b\b100\n");\r
522 \r
523   fclose(iso_file);\r
524   chdir("..");\r
525   return 0;\r
526 }\r
527 \r
528 void convert_iso_to_cso(char *output_dir, char *iso_file_name, char *cso_file_name)\r
529 {\r
530   char cmd_string[(MAX_PATH * 2) + 16];\r
531 \r
532   chdir(output_dir);\r
533   sprintf(cmd_string, CISO_BINARY " 9 \"%s\" \"%s\"", iso_file_name, cso_file_name);\r
534   if (system(cmd_string) != 0)\r
535   {\r
536     printf("failed to convert iso to cso\n");\r
537     myexit(1);\r
538   }\r
539 \r
540   unlink(iso_file_name);\r
541   chdir("..");\r
542 }\r
543 \r
544 \r
545 #define sector_offset_to_msf(offset, minutes, seconds, frames)                \\r
546 {                                                                             \\r
547   u32 _offset = offset;                                                       \\r
548   minutes = (_offset / 75) / 60;                                              \\r
549   seconds = (_offset / 75) % 60;                                              \\r
550   frames = _offset % 75;                                                      \\r
551 }                                                                             \\r
552 \r
553 \r
554 s32 convert_bin_cue(char *output_name_base)\r
555 {\r
556   char output_file_name[MAX_PATH];\r
557   FILE *output_cue_file;\r
558   FILE *bin_file = cd_bin.bin_file;\r
559   cd_track_struct *current_track;\r
560   u32 m, s, f;\r
561   u32 current_pregap = 0;\r
562   u32 last_pregap = 0;\r
563   u32 i;\r
564   struct stat sb;\r
565 \r
566   if(stat(output_name_base, &sb))\r
567     mkdir(output_name_base);\r
568 \r
569   sprintf(output_file_name, "%s.cue", output_name_base);\r
570   chdir(output_name_base);\r
571   output_cue_file = fopen(output_file_name, "wb");\r
572   chdir("..");\r
573 \r
574   // Every track gets its own file. It's either going to be of type ISO\r
575   // or of type WAV.\r
576 \r
577   for(i = 0; i < 100; i++)\r
578   {\r
579     current_track = cd_bin.logical_tracks[i];\r
580     if(current_track != NULL)\r
581     {\r
582       switch(current_track->format_type)\r
583       {\r
584         char output_name_tmp[MAX_PATH];\r
585 \r
586         // Audio\r
587         case 0:\r
588         {\r
589           sprintf(output_file_name, "%s_%02d.mp3", output_name_base, i);\r
590           sprintf(output_name_tmp, "%s_%02d.wav", output_name_base, i);\r
591 \r
592           fprintf(output_cue_file, "FILE \"%s\" %s\n",\r
593            opt_use_mp3 ? output_file_name : output_name_tmp,\r
594            opt_use_mp3 ? "MP3" : "WAVE");\r
595           fprintf(output_cue_file, "  TRACK %02d AUDIO\n", i);\r
596           current_pregap = current_track->pregap_offset - last_pregap;\r
597           last_pregap = current_track->pregap_offset;\r
598           if(current_pregap > 0)\r
599           {\r
600             sector_offset_to_msf(current_pregap, m, s, f);\r
601             fprintf(output_cue_file, "    PREGAP %02d:%02d:%02d\n", m, s, f);\r
602           }\r
603           fprintf(output_cue_file, "    INDEX 01 00:00:00\n");\r
604           sector_offset_to_msf(current_track->sector_count, m, s, f);\r
605           fprintf(output_cue_file, "    REM LENGTH %02d:%02d:%02d\n", m, s, f);\r
606 \r
607           fseek(bin_file, current_track->physical_offset, SEEK_SET);\r
608           convert_bin_to_wav(bin_file, output_name_base, output_name_tmp,\r
609            current_track->sector_count);\r
610           if(opt_use_mp3)\r
611           {\r
612             convert_wav_to_mp3(output_name_tmp, output_name_base,\r
613              output_file_name);\r
614           }\r
615           break;\r
616         }\r
617 \r
618         // Data\r
619         default:\r
620           sprintf(output_file_name, "%s_%02d.cso", output_name_base, i);\r
621           sprintf(output_name_tmp, "%s_%02d.iso", output_name_base, i);\r
622           fprintf(output_cue_file, "FILE \"%s\" BINARY\n",\r
623            opt_use_cso ? output_file_name : output_name_tmp);\r
624           fprintf(output_cue_file, "  TRACK %02d MODE1/2048\n", i);\r
625           current_pregap = current_track->pregap_offset - last_pregap;\r
626           last_pregap = current_track->pregap_offset;\r
627           if(current_pregap > 0)\r
628           {\r
629             sector_offset_to_msf(current_pregap, m, s, f);\r
630             fprintf(output_cue_file, "    PREGAP %02d:%02d:%02d\n", m, s, f);\r
631           }\r
632           fprintf(output_cue_file, "    INDEX 01 00:00:00\n");\r
633 \r
634           fseek(bin_file, current_track->physical_offset, SEEK_SET);\r
635           convert_bin_to_iso(bin_file, output_name_base, output_name_tmp,\r
636            current_track->sector_count);\r
637           if(opt_use_cso)\r
638           {\r
639             convert_iso_to_cso(output_name_base, output_name_tmp, output_file_name);\r
640           }\r
641           break;\r
642       }\r
643     }\r
644   }\r
645 \r
646   fclose(output_cue_file);\r
647 \r
648   return 0;\r
649 }\r
650 \r
651 #ifdef _WIN32\r
652 static void update_path(void)\r
653 {\r
654   char buff1[MAX_PATH*4], *buff2;\r
655   char *path;\r
656   int size, i;\r
657 \r
658   path = getenv("PATH");\r
659   GetModuleFileNameA(NULL, buff1, sizeof(buff1));\r
660   for (i = strlen(buff1)-1; i > 0; i--)\r
661     if (buff1[i] == '\\') break;\r
662   buff1[i] = 0;\r
663 \r
664   size = strlen(path) + strlen(buff1) + 3;\r
665   buff2 = malloc(size);\r
666   if (buff2 == NULL) return;\r
667 \r
668   snprintf(buff2, size, "%s;%s", path, buff1);\r
669   SetEnvironmentVariableA("PATH", buff2);\r
670   free(buff2);\r
671 }\r
672 #endif\r
673 \r
674 int main(int argc, char *argv[])\r
675 {\r
676   char out_buff[MAX_PATH], *cue_file, *out_base;\r
677   int a;\r
678 \r
679   if(argc < 2)\r
680   {\r
681     printf("bin/cue to cso/mp3 converter\n");\r
682     printf("usage: %s [options] <input cue> [output base]\n", argv[0]);\r
683     printf("options:\n"\r
684            "   -m        output mp3 files for audio (default) (lame required)\n"\r
685            "   -b <rate> mp3 bitrate to use (default is 128)\n"\r
686            "   -w        output wav files for audio\n"\r
687            "   -c        output cso as data track (default) (ciso required)\n"\r
688            "   -i        output iso as data track\n");\r
689     return 0;\r
690   }\r
691 \r
692   for (a = 1; a < argc - 1; a++)\r
693   {\r
694     if      (strcmp(argv[a], "-m") == 0)\r
695       opt_use_mp3 = 1;\r
696     else if (strcmp(argv[a], "-w") == 0)\r
697       opt_use_mp3 = 0;\r
698     else if (strcmp(argv[a], "-c") == 0)\r
699       opt_use_cso = 1;\r
700     else if (strcmp(argv[a], "-i") == 0)\r
701       opt_use_cso = 0;\r
702     else if (strcmp(argv[a], "-b") == 0)\r
703     {\r
704       opt_mp3_bitrate = atoi(argv[++a]);\r
705     }\r
706     else\r
707       break;\r
708   }\r
709   cue_file = argv[a];\r
710   out_base = argv[a+1];\r
711 \r
712   /* some sanity checks */\r
713   if(strlen(cue_file) < 4 || strcasecmp(cue_file + strlen(cue_file) - 4, ".cue") != 0)\r
714   {\r
715     printf("error: not a cue file specified?\n");\r
716     myexit(1);\r
717   }\r
718 \r
719 #ifdef _WIN32\r
720   update_path();\r
721 #endif\r
722 \r
723   if(opt_use_mp3 && system(LAME_BINARY " --help " NULL_REDIR) != 0)\r
724   {\r
725     printf("LAME seems to be missing.\n"\r
726 #ifdef _WIN32\r
727       "Download from http://lame.sourceforge.net/links.php#Binaries and extract\n"\r
728       "lame.exe to the same directory as %s\n", argv[0]\r
729 #else\r
730       "Install lame using your packet manager, obtain binaries or build from\n"\r
731       "sources at http://lame.sourceforge.net/\n"\r
732 #endif\r
733       );\r
734     myexit(1);\r
735   }\r
736 \r
737   if(opt_use_cso && system(CISO_BINARY " " NULL_REDIR) != 0)\r
738   {\r
739     printf("CISO seems to be missing.\n"\r
740 #ifdef _WIN32\r
741       "Download ciso.exe and extract to the same directory as %s\n"\r
742       "You can take ciso.exe from yacc at http://yacc.pspgen.com/\n", argv[0]\r
743 #else\r
744       "Install ciso using your packet manager, obtain binaries or build from\n"\r
745       "sources at http://ciso.tenshu.fr/\n"\r
746 #endif\r
747       );\r
748     myexit(1);\r
749   }\r
750 \r
751   if(load_bin_cue(cue_file) == 0)\r
752   {\r
753     if(out_base == NULL)\r
754     {\r
755       char *p;\r
756       strncpy(out_buff, cue_file, sizeof(out_buff));\r
757       out_buff[sizeof(out_buff)-1] = 0;\r
758       p = strrchr(out_buff, DIR_SEPARATOR_CHAR);\r
759       if (p != NULL)\r
760       {\r
761         *p++ = 0;\r
762         chdir(out_buff);\r
763         memmove(out_buff, p, strlen(p)+1);\r
764       }\r
765       out_buff[strlen(out_buff)-4] = 0;\r
766       out_base = out_buff;\r
767     }\r
768     if(convert_bin_cue(out_base) != 0)\r
769       myexit(1);\r
770   }\r
771   else\r
772   {\r
773     printf("error: could not load cue file %s\n", cue_file);\r
774     myexit(1);\r
775   }\r
776 \r
777   return 0;\r
778 }\r
779 \r