📄 read_cdda.c
字号:
/* * $Id: read_cdda.c,v 1.13 1997/10/14 08:46:39 jim Exp $ * Read audio track from a CD using CDDA * * Written by Jim Mintha (mintha@geog.ubc.ca) * Large portions are borrowed from the Workman * sources written by Steven Grimm (koreth@hyperion.com) * * $Log: read_cdda.c,v $ * Revision 1.13 1997/10/14 08:46:39 jim * make sure we clean up on exit * * Revision 1.12 1997/10/14 07:32:31 jim * Added -D dev, fixed getopt struct, updated help * * Revision 1.11 1997/10/10 09:22:56 jim * type * * Revision 1.10 1997/10/10 09:09:44 jim * added patches from "Alexander V. Panasyuk" <panasyuk@cfauvcs5.harvard.edu> * * Revision 1.9 1997/10/02 16:57:01 jim * (int) stdout isn't correct, 1 is better * * Revision 1.8 1997/09/10 00:17:07 jim * lots of changes to add jitter control, clean things up * reset block size when done, better output, etc. * * Revision 1.7 1997/08/31 21:36:18 jim * added changes from Andreas Karrer for output to stdout, changed * options a bit. * * Revision 1.6 1996/06/04 23:00:45 jim * Patches from Hans Werner Strube (strube@physik3.gwdg.de) * to open volmgt device if normal open fails. To allow * output to stdout (- filename) and don't call cdda_init if * just checking drive type. * * Revision 1.5 1996/01/18 14:05:49 jim * Added ability to query drive type * moved some stuff back from header file * * Revision 1.4 1996/01/10 10:05:33 jim * Fixed display on song sectors * * Revision 1.3 1996/01/10 09:53:22 jim * mistake in checking starting time * * Revision 1.2 1996/01/10 09:44:01 jim * Added -q to help * * Revision 1.1 1996/01/10 09:11:32 jim * Initial revision * *//* * Notes: (this is my understanding of things) * * One CDDA block is 2368 bytes each block contains: * 588 frames and 16bytes for Q data. * Each frame is 4 bytes (presumably 2 16bit values) * 588 * 4 = 2352 + 16 = 2368 * Each frame is 1/44100 th. of a second (44100 Hz) * therefore each block is 1/75 th. of a second * * You can also read without the Q data in which case * each block is only 2352 bytes long. */#include "read_cdda.h"#include "version.h"/* disable X window stuff in my general utilities */NO_X_WIN/* Global variables - yuk *//* * This is the fastest way to convert from BCD to 8-bit. */unsigned char unbcd[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,0,0,0,0,0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0,0,0,0,0,0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0,0,0,0,0,0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0,0,0,0,0,0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0,0,0,0,0,0, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0,0,0,0,0,0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,0,0,0,0,0, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0,0,0,0,0,0, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0,0,0,0,0,0, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};/* where we are and where we want to be */typedef struct { int length; int start_block; int num_blocks; int mins,secs,frames;} Track;Track tracks[60];boolean verbose = FALSE;unsigned char *ulawmap;int NUM_BLOCKS=150;intmain(int argc, char **argv){ unsigned char *cdda_buf, *cdda_buf2, *temp_buf, *prev_end; long cddabuf_len, to_write, to_reread, jitter = 0, to_read, to_skip, num_read; int cd_fd, out_fd, track, fmt = CDR, ch, ctr, want_percent; int start_block, num_blocks, current_block, num_tracks; int starting_sec = 0, ending_sec = 0, end_block; boolean toc = FALSE, swap = FALSE, drv_type = FALSE; char *device_name = NULL; extern char *optarg; extern int optind; struct option const longopts[] = { /* name, has_arg, *flag, val */ { "help", 0, 0, 'h'}, { "start", 1, 0, 's'}, { "end", 1, 0, 'e'}, { "au16", 0, 0, 'a'}, { "au8", 0, 0, '8'}, { "swap", 0, 0, 'x'}, { "buffer", 1, 0, 'b'}, { "verbose", 0, 0, 'v'}, { "toc", 0, 0, 't'}, { "drvtype", 0, 0, 'd'}, { "device", 1, 0, 'D'}, { "version", 0, 0, 'V'}, { NULL, 0, NULL, 0} }; while((ch = getopt_long(argc, argv, "hs:e:a8xb:vtdD:V", longopts, (int *) 0)) != -1) { switch(ch) { case 'h': /* help */ usage(argv[0]); break; case 'v': /* quiet */ verbose = TRUE; break; case 't': /* toc */ toc = TRUE; verbose = TRUE; break; case 'd': /* drive type */ drv_type = TRUE; break; case 'D': /* device */ device_name = optarg; break; case 'x': /* swap */ swap = TRUE; break; case '8': /* Sun .au 8KHz */ fmt = AU8; break; case 'a': /* Sun .au 44.1KHz */ fmt = AU16; break; case 'w': /* WAV format */ fmt = WAV; break; case 'b': /* Buffer size in blocks */ sscanf(optarg, "%d", &NUM_BLOCKS); if(NUM_BLOCKS < 10 || NUM_BLOCKS > 400) pop_error(ERR_GEN, "Buffer size: %d invalid", NUM_BLOCKS); break; case 's': /* start time */ sscanf(optarg, "%d", &starting_sec); if(starting_sec < 0) pop_error(ERR_GEN, "Starting time: %d invalid", starting_sec); break; case 'e': /* end time */ sscanf(optarg, "%d", &ending_sec); if(ending_sec < 0) pop_error(ERR_GEN, "Ending time: %d invalid", ending_sec); break; case 'V': fprintf(stderr, "%s\n", version_string); fprintf(stderr, "Written by Jim Mintha (mintha@geog.ubc.ca)\n"); exit(0); break; case '?': usage(argv[0]); break; } } if(starting_sec > ending_sec && ending_sec != 0) pop_error(ERR_GEN, "Starting time is after ending time"); if(!toc && !drv_type) { if(optind + 2 > argc) pop_error(ERR_GEN, "Must specify a track and filename\n"); sscanf(argv[optind], "%d", &track); if(track <= 0 || track > 99) pop_error(ERR_GEN, "Invalid track specified: %d", track); if(argv[optind + 1][0] == '-') out_fd = 1; else out_fd = open(argv[optind + 1], O_WRONLY | O_CREAT, 0666); if(out_fd < 0) pop_error(ERR_FILE, "Error opening output file: %s", argv[optind + 1]); if(fmt == AU8 || fmt == AU16) write_sun_header(out_fd, fmt); } if(drv_type) { get_drv_type(cd_fd, device_name); all_done(cd_fd); } cd_fd = cdda_init(&cdda_buf, &cdda_buf2, &cddabuf_len, device_name); num_tracks = read_toc(cd_fd, toc); if(toc) all_done(cd_fd); if(track > num_tracks) pop_error(ERR_GEN, "Invalid track specified: %d", track); if(verbose) fprintf(stderr, "\nWriting track %d to %s\n", track, argv[optind + 1]); if(starting_sec * 75 > tracks[track].num_blocks || ending_sec * 75 > tracks[track].num_blocks) pop_error(ERR_GEN, "Start/End times too long\n"); start_block = tracks[track].start_block + starting_sec * 75; num_blocks = tracks[track].num_blocks - starting_sec * 75; end_block = start_block + num_blocks; current_block = start_block; want_percent = 10; if(ending_sec != 0) { end_block = tracks[track].start_block + ending_sec * 75; num_blocks = end_block - num_blocks; } else ending_sec = tracks[track].length; if(verbose) { fprintf(stderr, "Song is sectors: %d to %d\n", tracks[track].start_block, tracks[track].start_block + tracks[track].num_blocks); fprintf(stderr, "Recording sectors: %d to %d\n", start_block, end_block); fprintf(stderr, "Song start time: %02d:%02d end time: %02d:%02d\n", starting_sec / 60, starting_sec % 60, ending_sec / 60, ending_sec % 60); } /* * Okay - now we do the actual reading. * */ while(current_block < end_block) { to_reread = REREAD_BLKS; to_read = NUM_BLOCKS; if((current_block - start_block) * 100 / num_blocks >= want_percent && verbose) { fprintf(stderr, "%02d%% ", want_percent); while(want_percent <= (current_block - start_block) * 100 / num_blocks) want_percent += 10; } if(current_block == start_block) to_reread = 0; if(end_block - (current_block - to_reread) < to_read) to_read = end_block - (current_block - to_reread); /* printf("Current block: %d\n",current_block); printf("to_read %d\n",to_read); */ num_read = cdda_read(cd_fd, cdda_buf, to_read, current_block - to_reread); if(num_read != to_read) pop_error(ERR_GEN, "Error reading CD"); if(current_block == start_block) { to_skip = 0; to_write = to_read; } else { jitter = calc_jitter(cdda_buf, prev_end, to_read); /* printf("jitter %d\n", jitter - (CDDA_BLKSIZE * (REREAD_BLKS - COMPARE_BLKS)));*/ to_skip = jitter + CDDA_BLKSIZE * COMPARE_BLKS; to_write = to_read - to_reread; /* don't write more than we read */ while(to_skip + to_write * CDDA_BLKSIZE > to_read * CDDA_BLKSIZE) to_write--; /* don't write more than the length of track */ if(to_write + current_block > end_block) to_write = end_block - current_block; /* if necessary add a padded block at end */ if(to_write == 0) { current_block = end_block - 1; to_write = 1; for(ctr = CDDA_BLKSIZE - (to_skip % CDDA_BLKSIZE); ctr < CDDA_BLKSIZE; ctr++) cdda_buf[to_skip + ctr] = 0; } } cdda_write(out_fd, cdda_buf + to_skip, CDDA_BLKSIZE * to_write, swap, fmt); prev_end = cdda_buf + to_skip + to_write * CDDA_BLKSIZE; temp_buf = cdda_buf; cdda_buf = cdda_buf2; cdda_buf2 = temp_buf; current_block += to_write; } if(verbose) fprintf(stderr, "100%%\nAll Done.\n"); all_done(cd_fd);}/* * calculate jitter (see explanation before cdda_read) * compare 128 frames or 512 bytes */longcalc_jitter(unsigned char *buf, unsigned char *last, int to_read){ int offset; for(offset = CDDA_BLKSIZE * (REREAD_BLKS - COMPARE_BLKS); offset >= 0; offset -= SAMPLE) { if(!memcmp(last - CDDA_BLKSIZE * COMPARE_BLKS, buf + offset, CDDA_BLKSIZE * COMPARE_BLKS)) return offset; } for(offset = CDDA_BLKSIZE * (REREAD_BLKS - COMPARE_BLKS); offset < to_read * CDDA_BLKSIZE; offset += SAMPLE) { if(!memcmp(last - CDDA_BLKSIZE * COMPARE_BLKS, buf + offset, CDDA_BLKSIZE * COMPARE_BLKS)) return offset; } fprintf(stderr, "Jitter Control Failed!!\n"); return CDDA_BLKSIZE * (REREAD_BLKS - COMPARE_BLKS);} /* * Initialize CDDA data buffer and open device. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -