1 /* wavbreaker - A tool to split a wave file up into multiple waves. 2 * Copyright (C) 2002-2006 Timothy Robinson 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 #include <config.h> 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <unistd.h> 26 #include <fcntl.h> 27 #include <limits.h> 28 #include <gtk/gtk.h> 29 #include <stdint.h> 30 31 #include "wavbreaker.h" 32 33 #include "sample.h" 34 #include "wav.h" 35 #include "cdda.h" 36 #include "appconfig.h" 37 #include "overwritedialog.h" 38 #include "gettext.h" 39 40 #if defined(HAVE_MPG123) 41 #include <mpg123.h> 42 #endif 43 44 enum AudioType { 45 UNKNOWN = 0, 46 CDDA = 1, 47 WAV = 2, 48 #if defined(HAVE_MPG123) 49 MP3 = 3, 50 #endif 51 }; 52 53 SampleInfo sampleInfo; 54 static AudioFunctionPointers *audio_function_pointers; 55 static unsigned long sample_start = 0; 56 static int playing = 0; 57 static int writing = 0; 58 static gboolean kill_play_thread = FALSE; 59 static enum AudioType audio_type; 60 61 static char *sample_file = NULL; 62 static FILE *read_sample_fp = NULL; 63 static FILE *write_sample_fp = NULL; 64 65 #if defined(HAVE_MPG123) 66 static mpg123_handle *mpg123 = NULL; 67 static size_t mpg123_offset = 0; 68 #endif 69 70 static GThread *thread; 71 static GMutex mutex; 72 73 /* typedef and struct stuff for new thread open junk */ 74 75 typedef struct WriteThreadData_ WriteThreadData; 76 struct WriteThreadData_ { 77 GList *tbl; 78 WriteInfo *write_info; 79 char *outputdir; 80 }; 81 WriteThreadData wtd; 82 83 typedef struct MergeThreadData_ MergeThreadData; 84 struct MergeThreadData_ { 85 char *merge_filename; 86 int num_files; 87 GList *filenames; 88 WriteInfo *write_info; 89 }; 90 MergeThreadData mtd; 91 92 typedef struct OpenThreadData_ OpenThreadData; 93 struct OpenThreadData_ { 94 GraphData *graphData; 95 double *pct; 96 }; 97 OpenThreadData open_thread_data; 98 99 static void sample_max_min(GraphData *graphData, double *pct); 100 101 static char *error_message; 102 103 char *sample_get_error_message() 104 { 105 return g_strdup(error_message ?: ""); 106 } 107 108 void sample_set_error_message(const char *val) 109 { 110 if (error_message) { 111 g_free(error_message); 112 } 113 114 error_message = g_strdup(val); 115 } 116 117 #if defined(HAVE_MPG123) 118 int 119 mp3_read_sample(mpg123_handle *handle, 120 unsigned char *buf, 121 int buf_size, 122 unsigned long start_pos) 123 { 124 size_t result; 125 gboolean retried = FALSE; 126 127 if (mpg123_offset != start_pos) { 128 retry: 129 mpg123_seek(handle, start_pos / sampleInfo.blockAlign, SEEK_SET); 130 mpg123_offset = start_pos; 131 } 132 133 if (mpg123_read(handle, buf, buf_size, &result) == MPG123_OK) { 134 mpg123_offset += result; 135 return result; 136 } else { 137 fprintf(stderr, "MP3 decoding failed: %s\n", mpg123_strerror(mpg123)); 138 if (!retried) { 139 fprintf(stderr, "Retrying read at %zu...\n", mpg123_offset); 140 retried = TRUE; 141 goto retry; 142 } 143 } 144 145 return -1; 146 } 147 148 //#define WAVBREAKER_MP3_DEBUG 149 150 static gboolean 151 mp3_parse_header(uint32_t header, uint32_t *bitrate, uint32_t *frequency, uint32_t *samples, uint32_t *framesize) 152 { 153 // http://www.datavoyage.com/mpgscript/mpeghdr.htm 154 int a = ((header >> 21) & 0x07ff); 155 int b = ((header >> 19) & 0x0003); 156 int c = ((header >> 17) & 0x0003); 157 int e = ((header >> 12) & 0x000f); 158 int f = ((header >> 10) & 0x0003); 159 int g = ((header >> 9) & 0x0001); 160 161 static const int BITRATES_V1_L3[] = { -1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }; 162 static const int FREQUENCIES[] = { 44100, 48000, 32000, 0 }; 163 164 if (a != 0x7ff /* sync */ || 165 b != 0x3 /* MPEG1 */ || 166 c != 0x1 /* Layer III */ || 167 e == 0x0 /* freeform bitrate */ || e == 0xf /* invalid bitrate */ || 168 f == 0x3 /* invalid frequency */) { 169 return FALSE; 170 } 171 172 *bitrate = BITRATES_V1_L3[e]; 173 *frequency = FREQUENCIES[f]; 174 *samples = 1152; 175 *framesize = (int)((*samples) / 8 * 1000 * (*bitrate) / (*frequency)) + g /* padding */; 176 177 #if defined(WAVBREAKER_MP3_DEBUG) 178 static const char *VERSIONS[] = { "MPEG 2.5", NULL, "MPEG 2", "MPEG 1" }; 179 static const char *LAYERS[] = { NULL, "III", "II", "I" }; 180 181 const char *mpeg_version = VERSIONS[b]; 182 const char *layer = LAYERS[c]; 183 184 fprintf(stderr, "MP3 frame: %s %s, %dHz, %dkbps, %d samples (%d bytes)\n", mpeg_version, layer, 185 *frequency, *bitrate, *samples, *framesize); 186 #endif /* WAVBREAKER_MP3_DEBUG */ 187 188 return TRUE; 189 } 190 191 void 192 mp3_write_file(FILE *input_file, const char *filename, SampleInfo *sampleInfo, unsigned long start_pos, unsigned long end_pos) 193 { 194 start_pos /= sampleInfo->blockSize; 195 end_pos /= sampleInfo->blockSize; 196 197 FILE *output_file = fopen(filename, "wb"); 198 199 if (!output_file) { 200 fprintf(stderr, "Could not open '%s' for writing\n", filename); 201 return; 202 } 203 204 fseek(input_file, 0, SEEK_SET); 205 206 uint32_t header = 0x00000000; 207 uint32_t sample_position = 0; 208 uint32_t file_offset = 0; 209 uint32_t last_frame_end = 0; 210 uint32_t frames_written = 0; 211 212 while (!feof(input_file)) { 213 fseek(input_file, file_offset, SEEK_SET); 214 215 int a = fgetc(input_file); 216 if (a == EOF) { 217 break; 218 } 219 220 header = ((header & 0xffffff) << 8) | (a & 0xff); 221 222 uint32_t bitrate = 0; 223 uint32_t frequency = 0; 224 uint32_t samples = 0; 225 uint32_t framesize = 0; 226 227 if (mp3_parse_header(header, &bitrate, &frequency, &samples, &framesize)) { 228 uint32_t frame_start = file_offset - 3; 229 230 if (last_frame_end < frame_start) { 231 fprintf(stderr, "Skipped non-frame data in MP3 @ 0x%08x (%d bytes)\n", 232 last_frame_end, frame_start - last_frame_end); 233 } 234 235 uint32_t start_samples = start_pos * frequency / CD_BLOCKS_PER_SEC; 236 if (start_samples <= sample_position) { 237 // Write this frame to the output file 238 char *buf = malloc(framesize); 239 fseek(input_file, frame_start, SEEK_SET); 240 if (fread(buf, 1, framesize, input_file) != framesize) { 241 fprintf(stderr, "Tried to read over the end of the input file\n"); 242 break; 243 } 244 if (fwrite(buf, 1, framesize, output_file) != framesize) { 245 fprintf(stderr, "Failed to write %d bytes to output file\n", framesize); 246 break; 247 } 248 free(buf); 249 250 frames_written++; 251 252 uint32_t end_samples = end_pos * frequency / CD_BLOCKS_PER_SEC; 253 if (end_samples > 0 && end_samples <= sample_position + samples) { 254 // Done writing this part 255 break; 256 } 257 } 258 259 sample_position += samples; 260 261 file_offset = frame_start + framesize; 262 last_frame_end = file_offset; 263 264 header = 0x00000000; 265 } else { 266 file_offset++; 267 } 268 } 269 270 #if defined(WAVBREAKER_MP3_DEBUG) 271 fprintf(stderr, "Wrote %d MP3 frames from '%s' to '%s'\n", frames_written, sample_file, filename); 272 #endif /* WAVBREAKER_MP3_DEBUG */ 273 274 fclose(output_file); 275 } 276 #endif 277 278 void sample_init() 279 { 280 g_mutex_init(&mutex); 281 282 #if defined(HAVE_MPG123) 283 if (mpg123_init() != MPG123_OK) { 284 fprintf(stderr, "Failed to initialize libmpg123\n"); 285 } 286 #endif 287 } 288 289 static gpointer play_thread(gpointer thread_data) 290 { 291 int read_ret = 0; 292 int i; 293 guint *play_marker = (guint *)thread_data; 294 unsigned char *devbuf; 295 296 audio_function_pointers = get_audio_function_pointers(); 297 298 /* 299 printf("play_thread: calling open_audio_device\n"); 300 */ 301 if (audio_function_pointers->audio_open_device(&sampleInfo) != 0) { 302 g_mutex_lock(&mutex); 303 playing = 0; 304 audio_function_pointers->audio_close_device(); 305 g_mutex_unlock(&mutex); 306 //printf("play_thread: return from open_audio_device != 0\n"); 307 return NULL; 308 } 309 //printf("play_thread: return from open_audio_device\n"); 310 311 i = 0; 312 313 devbuf = malloc(sampleInfo.bufferSize); 314 if (devbuf == NULL) { 315 g_mutex_lock(&mutex); 316 playing = 0; 317 audio_function_pointers->audio_close_device(); 318 g_mutex_unlock(&mutex); 319 printf("play_thread: out of memory\n"); 320 return NULL; 321 } 322 323 if (audio_type == CDDA) { 324 read_ret = cdda_read_sample(read_sample_fp, devbuf, sampleInfo.bufferSize, 325 sample_start + (sampleInfo.bufferSize * i++)); 326 } else if (audio_type == WAV) { 327 read_ret = wav_read_sample(read_sample_fp, devbuf, sampleInfo.bufferSize, 328 sample_start + (sampleInfo.bufferSize * i++)); 329 #if defined(HAVE_MPG123) 330 } else if (audio_type == MP3) { 331 read_ret = mp3_read_sample(mpg123, devbuf, sampleInfo.bufferSize, 332 sample_start + (sampleInfo.bufferSize * i++)); 333 #endif 334 } 335 336 while (read_ret > 0 && read_ret <= sampleInfo.bufferSize) { 337 /* 338 if (read_ret < 0) { 339 printf("read_ret: %d\n", read_ret); 340 } 341 */ 342 343 audio_function_pointers->audio_write(devbuf, read_ret); 344 345 if (g_mutex_trylock(&mutex)) { 346 if (kill_play_thread == TRUE) { 347 audio_function_pointers->audio_close_device(); 348 playing = 0; 349 kill_play_thread = FALSE; 350 g_mutex_unlock(&mutex); 351 return NULL; 352 } 353 g_mutex_unlock(&mutex); 354 } 355 356 if (audio_type == CDDA) { 357 read_ret = cdda_read_sample(read_sample_fp, devbuf, 358 sampleInfo.bufferSize, 359 sample_start + (sampleInfo.bufferSize * i++)); 360 } else if (audio_type == WAV) { 361 read_ret = wav_read_sample(read_sample_fp, devbuf, 362 sampleInfo.bufferSize, 363 sample_start + (sampleInfo.bufferSize * i++)); 364 #if defined(HAVE_MPG123) 365 } else if (audio_type == MP3) { 366 read_ret = mp3_read_sample(mpg123, devbuf, 367 sampleInfo.bufferSize, 368 sample_start + (sampleInfo.bufferSize * i++)); 369 #endif 370 } 371 372 *play_marker = ((sampleInfo.bufferSize * i) + sample_start) / 373 sampleInfo.blockSize; 374 } 375 376 g_mutex_lock(&mutex); 377 378 audio_function_pointers->audio_close_device(); 379 playing = 0; 380 381 g_mutex_unlock(&mutex); 382 383 return NULL; 384 } 385 386 int sample_is_playing() 387 { 388 return playing; 389 } 390 391 int sample_is_writing() 392 { 393 return writing; 394 } 395 396 int play_sample(gulong startpos, gulong *play_marker) 397 { 398 g_mutex_lock(&mutex); 399 if (playing) { 400 g_mutex_unlock(&mutex); 401 return 2; 402 } 403 404 if (sample_file == NULL) { 405 g_mutex_unlock(&mutex); 406 return 3; 407 } 408 409 playing = 1; 410 sample_start = startpos * sampleInfo.blockSize; 411 412 /* setup thread */ 413 414 //printf("creating the thread\n"); 415 fflush(stdout); 416 thread = g_thread_new("play_sample", play_thread, play_marker); 417 418 g_mutex_unlock(&mutex); 419 //printf("finished creating the thread\n"); 420 return 0; 421 } 422 423 void stop_sample() 424 { 425 g_mutex_lock(&mutex); 426 427 if (!playing) { 428 g_mutex_unlock(&mutex); 429 return; 430 } 431 432 kill_play_thread = TRUE; 433 g_mutex_unlock(&mutex); 434 435 // Wait for play thread to actually quit 436 g_thread_join(thread); 437 thread = NULL; 438 } 439 440 static gpointer open_thread(gpointer data) 441 { 442 OpenThreadData *thread_data = data; 443 444 sample_max_min(thread_data->graphData, 445 thread_data->pct); 446 447 return NULL; 448 } 449 450 int ask_open_as_raw() 451 { 452 GtkMessageDialog *dialog; 453 gint result; 454 const gchar *message = _("Open as RAW audio"); 455 const gchar *info_text = _("The file you selected does not contain a wave header. wavbreaker can interpret the file as \"Signed 16 bit, 44100 Hz, Stereo\" audio. Choose the byte order for the RAW audio or cancel to abort."); 456 457 dialog = (GtkMessageDialog*)gtk_message_dialog_new( GTK_WINDOW(wavbreaker_get_main_window()), 458 GTK_DIALOG_DESTROY_WITH_PARENT, 459 GTK_MESSAGE_QUESTION, 460 GTK_BUTTONS_CANCEL, 461 "%s", message); 462 463 gtk_dialog_add_button( GTK_DIALOG(dialog), _("Big endian"), WB_RESPONSE_BIG_ENDIAN); 464 gtk_dialog_add_button( GTK_DIALOG(dialog), _("Little endian"), WB_RESPONSE_LITTLE_ENDIAN); 465 466 gtk_message_dialog_format_secondary_text( dialog, "%s", info_text); 467 gtk_window_set_title( GTK_WINDOW(dialog), message); 468 469 result = gtk_dialog_run( GTK_DIALOG(dialog)); 470 gtk_widget_destroy( GTK_WIDGET( dialog)); 471 472 return result; 473 } 474 475 int sample_open_file(const char *filename, GraphData *graphData, double *pct) 476 { 477 int ask_result = 0; 478 sample_close_file(); 479 480 sample_file = g_strdup(filename); 481 482 audio_type = UNKNOWN; 483 if( wav_read_header(sample_file, &sampleInfo, 0) == 0) { 484 audio_type = WAV; 485 } 486 487 #if defined(HAVE_MPG123) 488 if (audio_type == UNKNOWN) { 489 fprintf(stderr, "Trying to open as MP3...\n"); 490 491 if (mpg123 != NULL) { 492 mpg123_close(mpg123), mpg123 = NULL; 493 } 494 495 if ((mpg123 = mpg123_new(NULL, NULL)) == NULL) { 496 fprintf(stderr, "Failed to create MP3 decoder\n"); 497 } 498 499 if (mpg123_open(mpg123, sample_file) == MPG123_OK) { 500 fprintf(stderr, "Detected MP3 format\n"); 501 502 long rate; 503 int channels; 504 int encoding; 505 if (mpg123_getformat(mpg123, &rate, &channels, &encoding) != MPG123_OK ) { 506 fprintf(stderr, "Could not get file format\n"); 507 } 508 509 fprintf(stderr, "Scanning MP3 file...\n"); 510 if (mpg123_scan(mpg123) != MPG123_OK) { 511 fprintf(stderr, "Failed to scan MP3\n"); 512 } 513 514 struct mpg123_frameinfo fi; 515 memset(&fi, 0, sizeof(fi)); 516 517 if (mpg123_info(mpg123, &fi) == MPG123_OK) { 518 sampleInfo.channels = (fi.mode == MPG123_M_MONO) ? 1 : 2; 519 sampleInfo.samplesPerSec = fi.rate; 520 sampleInfo.bitsPerSample = 16; 521 522 sampleInfo.blockAlign = sampleInfo.channels * (sampleInfo.bitsPerSample / 8); 523 sampleInfo.avgBytesPerSec = sampleInfo.blockAlign * sampleInfo.samplesPerSec; 524 sampleInfo.bufferSize = DEFAULT_BUF_SIZE; 525 sampleInfo.blockSize = sampleInfo.avgBytesPerSec / CD_BLOCKS_PER_SEC; 526 sampleInfo.numBytes = mpg123_length(mpg123) * sampleInfo.blockAlign; 527 fprintf(stderr, "Channels: %d, rate: %d, bits: %d, decoded size: %lu\n", 528 sampleInfo.channels, sampleInfo.samplesPerSec, 529 sampleInfo.bitsPerSample, sampleInfo.numBytes); 530 531 mpg123_format_none(mpg123); 532 if (mpg123_format(mpg123, sampleInfo.samplesPerSec, 533 (sampleInfo.channels == 1) ? MPG123_STEREO : MPG123_MONO, 534 MPG123_ENC_SIGNED_16) != MPG123_OK) { 535 fprintf(stderr, "Failed to set mpg123 format\n"); 536 } else { 537 fprintf(stderr, "MP3 file reading successfully set up\n"); 538 audio_type = MP3; 539 } 540 } 541 } 542 543 } 544 #endif 545 546 547 if (audio_type == UNKNOWN) { 548 ask_result = ask_open_as_raw(); 549 if( ask_result == GTK_RESPONSE_CANCEL) { 550 sample_set_error_message(wav_get_error_message()); 551 return 1; 552 } 553 cdda_read_header(sample_file, &sampleInfo); 554 if( ask_result == WB_RESPONSE_BIG_ENDIAN) { 555 audio_type = CDDA; 556 } else { 557 audio_type = WAV; 558 } 559 } 560 561 if (audio_type == WAV || audio_type == CDDA) { 562 sampleInfo.blockSize = (((sampleInfo.bitsPerSample / 8) * 563 sampleInfo.channels * sampleInfo.samplesPerSec) / 564 CD_BLOCKS_PER_SEC); 565 566 if ((read_sample_fp = fopen(sample_file, "rb")) == NULL) { 567 if (error_message) { 568 g_free(error_message); 569 } 570 error_message = g_strdup_printf(_("Error opening %s: %s"), sample_file, strerror(errno)); 571 return 2; 572 } 573 } 574 575 open_thread_data.graphData = graphData; 576 open_thread_data.pct = pct; 577 578 fflush(stdout); 579 g_thread_unref(g_thread_new("open file", open_thread, &open_thread_data)); 580 581 return 0; 582 } 583 584 void sample_close_file() 585 { 586 #if defined(HAVE_MPG123) 587 if (mpg123 != NULL) { 588 mpg123_close(mpg123), mpg123 = NULL; 589 } 590 #endif 591 592 if( read_sample_fp != NULL) { 593 fclose( read_sample_fp); 594 read_sample_fp = NULL; 595 } 596 597 if( sample_file != NULL) { 598 g_free(sample_file); 599 sample_file = NULL; 600 } 601 } 602 603 static void sample_max_min(GraphData *graphData, double *pct) 604 { 605 int tmp = 0; 606 long int ret = 0; 607 int min, max, xtmp; 608 int min_sample, max_sample; 609 long int i, k; 610 long int numSampleBlocks; 611 long int tmp_sample_calc; 612 unsigned char devbuf[sampleInfo.blockSize]; 613 Points *graph_data; 614 615 tmp_sample_calc = sampleInfo.numBytes; 616 tmp_sample_calc = tmp_sample_calc / sampleInfo.blockSize; 617 numSampleBlocks = (tmp_sample_calc + 1); 618 619 /* DEBUG CODE START */ 620 /* 621 printf("\nsampleInfo.numBytes: %lu\n", sampleInfo.numBytes); 622 printf("sampleInfo.bitsPerSample: %d\n", sampleInfo.bitsPerSample); 623 printf("sampleInfo.blockSize: %d\n", sampleInfo.blockSize); 624 printf("sampleInfo.channels: %d\n", sampleInfo.channels); 625 printf("numSampleBlocks: %d\n\n", numSampleBlocks); 626 */ 627 /* DEBUG CODE END */ 628 629 graph_data = (Points *)malloc(numSampleBlocks * sizeof(Points)); 630 631 if (graph_data == NULL) { 632 printf("NULL returned from malloc of graph_data\n"); 633 return; 634 } 635 636 i = 0; 637 638 if (audio_type == CDDA) { 639 ret = cdda_read_sample(read_sample_fp, devbuf, sampleInfo.blockSize, 640 sampleInfo.blockSize * i); 641 } else if (audio_type == WAV) { 642 ret = wav_read_sample(read_sample_fp, devbuf, sampleInfo.blockSize, 643 sampleInfo.blockSize * i); 644 #if defined(HAVE_MPG123) 645 } else if (audio_type == MP3) { 646 ret = mp3_read_sample(mpg123, devbuf, sampleInfo.blockSize, 647 sampleInfo.blockSize * i); 648 #endif 649 } 650 651 min_sample = SHRT_MAX; /* highest value for 16-bit samples */ 652 max_sample = 0; 653 654 while (ret == sampleInfo.blockSize && i < numSampleBlocks) { 655 min = max = 0; 656 for (k = 0; k < ret; k++) { 657 if (sampleInfo.bitsPerSample == 8) { 658 tmp = devbuf[k]; 659 tmp -= 128; 660 } else if (sampleInfo.bitsPerSample == 16) { 661 tmp = (char)devbuf[k+1] << 8 | (char)devbuf[k]; 662 k++; 663 } else if (sampleInfo.bitsPerSample == 24) { 664 tmp = ((char)devbuf[k]) | ((char)devbuf[k+1] << 8); 665 tmp &= 0x0000ffff; 666 xtmp = (char)devbuf[k+2] << 16; 667 tmp |= xtmp; 668 k += 2; 669 } 670 671 if (tmp > max) { 672 max = tmp; 673 } else if (tmp < min) { 674 min = tmp; 675 } 676 677 // skip over any extra channels 678 k += (sampleInfo.channels - 1) * (sampleInfo.bitsPerSample / 8); 679 } 680 681 graph_data[i].min = min; 682 graph_data[i].max = max; 683 684 if( min_sample > (max-min)) { 685 min_sample = (max-min); 686 } 687 if( max_sample < (max-min)) { 688 max_sample = (max-min); 689 } 690 691 if (audio_type == CDDA) { 692 ret = cdda_read_sample(read_sample_fp, devbuf, 693 sampleInfo.blockSize, 694 sampleInfo.blockSize * i); 695 } else if (audio_type == WAV) { 696 ret = wav_read_sample(read_sample_fp, devbuf, 697 sampleInfo.blockSize, 698 sampleInfo.blockSize * i); 699 #if defined(HAVE_MPG123) 700 } else if (audio_type == MP3) { 701 ret = mp3_read_sample(mpg123, devbuf, 702 sampleInfo.blockSize, 703 sampleInfo.blockSize * i); 704 #endif 705 } 706 707 *pct = (double) i / numSampleBlocks; 708 i++; 709 } 710 711 *pct = 1.0; 712 713 graphData->numSamples = numSampleBlocks; 714 715 if (graphData->data != NULL) { 716 free(graphData->data); 717 } 718 graphData->data = graph_data; 719 720 graphData->minSampleAmp = min_sample; 721 graphData->maxSampleAmp = max_sample; 722 723 if (sampleInfo.bitsPerSample == 8) { 724 graphData->maxSampleValue = UCHAR_MAX; 725 } else if (sampleInfo.bitsPerSample == 16) { 726 graphData->maxSampleValue = SHRT_MAX; 727 } else if (sampleInfo.bitsPerSample == 24) { 728 graphData->maxSampleValue = 0x7fffff; 729 } 730 /* DEBUG CODE START */ 731 /* 732 printf("\ni: %d\n", i); 733 printf("graphData->numSamples: %ld\n", graphData->numSamples); 734 printf("graphData->maxSampleValue: %ld\n\n", graphData->maxSampleValue); 735 */ 736 /* DEBUG CODE END */ 737 } 738 739 static gpointer 740 write_thread(gpointer data) 741 { 742 WriteThreadData *thread_data = data; 743 744 GList *tbl_head = thread_data->tbl; 745 GList *tbl_cur, *tbl_next; 746 char *outputdir = thread_data->outputdir; 747 TrackBreak *tb_cur, *tb_next; 748 WriteInfo *write_info = thread_data->write_info; 749 750 int i; 751 int index; 752 unsigned long start_pos, end_pos; 753 char filename[1024]; 754 755 write_info->num_files = 0; 756 write_info->cur_file = 0; 757 write_info->sync = 0; 758 write_info->sync_check_file_overwrite_to_write_progress = 0; 759 write_info->check_file_exists = 0; 760 write_info->skip_file = -1; 761 762 i = 1; 763 tbl_cur = tbl_head; 764 while (tbl_cur != NULL) { 765 index = g_list_position(tbl_head, tbl_cur); 766 tb_cur = (TrackBreak *)g_list_nth_data(tbl_head, index); 767 768 if (tb_cur->write == TRUE) { 769 write_info->num_files++; 770 } 771 772 tbl_cur = g_list_next(tbl_cur); 773 } 774 775 i = 1; 776 tbl_cur = tbl_head; 777 tbl_next = g_list_next(tbl_cur); 778 779 while (tbl_cur != NULL) { 780 index = g_list_position(tbl_head, tbl_cur); 781 tb_cur = (TrackBreak *)g_list_nth_data(tbl_head, index); 782 if (tb_cur->write == TRUE) { 783 start_pos = tb_cur->offset * sampleInfo.blockSize; 784 785 if (tbl_next == NULL) { 786 end_pos = 0; 787 tb_next = NULL; 788 } else { 789 index = g_list_position(tbl_head, tbl_next); 790 tb_next = (TrackBreak *)g_list_nth_data(tbl_head, index); 791 end_pos = tb_next->offset * sampleInfo.blockSize; 792 } 793 794 /* add output directory to filename */ 795 strcpy(filename, outputdir); 796 strcat(filename, "/"); 797 798 strcat(filename, tb_cur->filename); 799 800 /* add file extension to filename */ 801 if ((audio_type == WAV) && (!strstr(filename, ".wav"))) { 802 strcat(filename, ".wav"); 803 } else if ((audio_type == CDDA) && (!strstr(filename, ".dat"))) { 804 strcat(filename, ".dat"); 805 #if defined(HAVE_MPG123) 806 } else if ((audio_type == MP3) && (!strstr(filename, ".mp3"))) { 807 strcat(filename, ".mp3"); 808 #endif 809 } 810 write_info->pct_done = 0.0; 811 write_info->cur_file++; 812 if (write_info->cur_filename != NULL) { 813 g_free(write_info->cur_filename); 814 } 815 write_info->cur_filename = g_strdup(filename); 816 817 if (write_info->skip_file < 2) { 818 if (g_file_test(filename, G_FILE_TEST_EXISTS)) { 819 write_info->skip_file = -1; 820 write_info->check_file_exists = 1; 821 // sync the threads to wait on overwrite question 822 while (write_info->skip_file < 0) { 823 sleep(1); 824 } 825 } else { 826 write_info->skip_file = 1; 827 } 828 } 829 830 if (write_info->skip_file > 0) { 831 if (audio_type == CDDA) { 832 cdda_write_file(write_sample_fp, filename, 833 sampleInfo.bufferSize, start_pos, end_pos); 834 } else if (audio_type == WAV) { 835 wav_write_file(write_sample_fp, filename, 836 sampleInfo.blockSize, 837 &sampleInfo, start_pos, end_pos, 838 &write_info->pct_done); 839 #if defined(HAVE_MPG123) 840 } else if (audio_type == MP3) { 841 mp3_write_file(write_sample_fp, filename, &sampleInfo, start_pos, end_pos); 842 #endif 843 } 844 i++; 845 } 846 847 if (write_info->skip_file < 2) { 848 write_info->skip_file = -1; 849 } 850 } 851 852 tbl_cur = g_list_next(tbl_cur); 853 tbl_next = g_list_next(tbl_next); 854 } 855 write_info->sync = 1; 856 if (write_info->cur_filename != NULL) { 857 g_free(write_info->cur_filename); 858 } 859 write_info->cur_filename = NULL; 860 861 fclose(write_sample_fp); 862 863 writing = 0; 864 return NULL; 865 } 866 867 void sample_write_files(GList *tbl, WriteInfo *write_info, char *outputdir) 868 { 869 wtd.tbl = tbl; 870 wtd.write_info = write_info; 871 wtd.outputdir = outputdir; 872 873 writing = 1; 874 875 if (sample_file == NULL) { 876 perror("Must open file first\n"); 877 writing = 0; 878 return; 879 } 880 881 if ((write_sample_fp = fopen(sample_file, "rb")) == NULL) { 882 printf("error opening %s\n", sample_file); 883 writing = 0; 884 return; 885 } 886 887 g_thread_unref(g_thread_new("write data", write_thread, &wtd)); 888 } 889 890 static gpointer 891 merge_thread(gpointer data) 892 { 893 MergeThreadData *thread_data = data; 894 char *filenames[g_list_length(thread_data->filenames)]; 895 GList *cur, *head; 896 int index, i; 897 char *list_data; 898 899 head = thread_data->filenames; 900 cur = head; 901 i = 0; 902 while (cur != NULL) { 903 index = g_list_position(head, cur); 904 list_data = (char *)g_list_nth_data(head, index); 905 906 filenames[i++] = list_data; 907 908 cur = g_list_next(cur); 909 } 910 911 wav_merge_files(thread_data->merge_filename, 912 g_list_length(thread_data->filenames), 913 filenames, 914 DEFAULT_BUF_SIZE, 915 thread_data->write_info); 916 917 head = thread_data->filenames; 918 cur = head; 919 while (cur != NULL) { 920 index = g_list_position(head, cur); 921 list_data = (char *)g_list_nth_data(head, index); 922 923 free(list_data); 924 925 cur = g_list_next(cur); 926 } 927 928 g_list_free(thread_data->filenames); 929 930 return NULL; 931 } 932 933 void sample_merge_files(char *merge_filename, GList *filenames, WriteInfo *write_info) 934 { 935 mtd.merge_filename = g_strdup(merge_filename); 936 mtd.filenames = filenames; 937 mtd.write_info = write_info; 938 939 if (write_info->merge_filename != NULL) { 940 g_free(write_info->merge_filename); 941 } 942 write_info->merge_filename = mtd.merge_filename; 943 944 g_thread_unref(g_thread_new("merge files", merge_thread, &mtd)); 945 } 946 947