📄 read_cdda.c
字号:
intcdda_init(unsigned char **bufadr, unsigned char **bufadr2, long *buflen, char *device){ int fd; struct cdrom_cdda cdda; *bufadr = malloc(NUM_BLOCKS * CDDA_BLKSIZE); *bufadr2 = malloc(NUM_BLOCKS * CDDA_BLKSIZE); if(*bufadr == NULL || *bufadr2 == NULL) pop_error(ERR_MALLOC, "Malloc of buffer failed"); *buflen = NUM_BLOCKS * CDDA_BLKSIZE; /* open the device */ if(device != NULL) fd = open(device, 0); else { fd = open("/dev/rdsk/c0t6d0s2", 0); if(fd < 0) fd = open("/vol/dev/aliases/cdrom0", 0); } if(fd < 0) pop_error(ERR_FILE, "Open of CD-ROM device failed"); cdda.cdda_addr = 200; cdda.cdda_length = 1; cdda.cdda_data = *bufadr; cdda.cdda_subcode = CDROM_DA_NO_SUBCODE; if(ioctl(fd, CDROMCDDA, &cdda) < 0) pop_error(ERR_GEN, "Error initializing CD-ROM DA"); return fd;}/* * Reads a bunch of data from the cdrom returning the number of * bytes read. To do jitter control we always re-read 7 extra * block from the cd. Next time around we compare the first * block read to the previous last block, adjusting +- bytes * * eg: * first read: (writing out all blocks 1->n) * |------||------||------||------||------| * blk 1 blk 2 ... blk n * next read: * |------||------||------||------| * blk n blk n+1 ... * ideally the last CDDABLKSIZE bytes of the old buffer would match * exactly with the first CDDABLKSIZE bytes of the new buffer and we * would write out from newbuffer+CDDABLKSIZE. But because of jitter * the usually won't so we write out a little bit more or less. */longcdda_read(int fd, unsigned char *rawbuf, int to_read, int addr){ struct cdrom_cdda cdda; cdda.cdda_addr = addr; cdda.cdda_length = to_read; cdda.cdda_data = rawbuf; cdda.cdda_subcode = CDROM_DA_NO_SUBCODE; if(ioctl(fd, CDROMCDDA, &cdda) < 0) { if(errno == ENXIO) { pop_error(NO_ERR, "CD has been ejected\n"); return -1; } if(ioctl(fd, CDROMCDDA, &cdda) < 0) { if(ioctl(fd, CDROMCDDA, &cdda) < 0) { if(ioctl(fd, CDROMCDDA, &cdda) < 0) { pop_error(NO_ERR, "CDROM CDDA failed\n"); return -1; } } } } return (cdda.cdda_length);}/* * Write out the data */voidcdda_write(int fd, unsigned char *buf, long len, boolean swap, int fmt){ int blocks = len / CDDA_BLKSIZE, ctr, ctr2; int write_len = SAMPLES_PER_BLK * 2 * 2; /* i.e. 2352 */ unsigned char *outbuf = NULL, *ptr; if(outbuf == NULL) outbuf = malloc(CDDA_BLKSIZE + 1); for(ctr = 0; ctr < blocks; ctr++) { ptr = outbuf; /* if they want swapping then we don't swap - make sense? */ if(!swap) { for(ctr2 = 0; ctr2 < SAMPLES_PER_BLK * 2; ctr2++) { *(ptr+1) = *buf++; *ptr = *buf++; ptr += 2; } } if(fmt == AU8) write_len = convert(outbuf); write(fd, outbuf, write_len); }}/* * Read the Table of Contents */intread_toc(int fd, boolean toc){ int ctr, prev_time, start_sec; struct cdrom_tochdr hdr; struct cdrom_tocentry entry; if(ioctl(fd, CDROMREADTOCHDR, &hdr) < 0) pop_error(ERR_GEN, "Error getting TOC header from CD"); if(ioctl(fd, CDROMSBLKMODE, CDDA_BLKSIZE) < 0) fprintf(stderr, "Unable to set blocksize, continuing anyways..."); if(verbose) fprintf(stderr, "Number of tracks %d\n", hdr.cdth_trk1); prev_time = 0; for(ctr = 1; ctr <= hdr.cdth_trk1; ctr++) { entry.cdte_track = ctr; entry.cdte_format = CDROM_MSF; if(ioctl(fd, CDROMREADTOCENTRY, &entry) < 0) pop_error(ERR_GEN, "Error getting TOC entry from CD"); tracks[ctr].mins = entry.cdte_addr.msf.minute; tracks[ctr].secs = entry.cdte_addr.msf.second; tracks[ctr].frames = entry.cdte_addr.msf.frame; start_sec = entry.cdte_addr.msf.minute * 60 + entry.cdte_addr.msf.second; entry.cdte_format = CDROM_LBA; if(ioctl(fd, CDROMREADTOCENTRY, &entry) < 0) pop_error(ERR_GEN, "Error getting TOC entry from CD"); tracks[ctr].start_block = entry.cdte_addr.lba; if(ctr != 1) { tracks[ctr - 1].num_blocks = tracks[ctr].start_block - tracks[ctr - 1].start_block; tracks[ctr - 1].length = start_sec - prev_time; } prev_time = start_sec; } /* get last lba */ entry.cdte_track = CDROM_LEADOUT; entry.cdte_format = CDROM_MSF; if(ioctl(fd, CDROMREADTOCENTRY, &entry) < 0) pop_error(ERR_GEN, "Error getting TOC entry from CD"); start_sec = entry.cdte_addr.msf.minute * 60 + entry.cdte_addr.msf.second; entry.cdte_track = CDROM_LEADOUT; entry.cdte_format = CDROM_LBA; if(ioctl(fd, CDROMREADTOCENTRY, &entry) < 0) pop_error(ERR_GEN, "Error getting TOC entry from CD"); tracks[ctr - 1].num_blocks = entry.cdte_addr.lba - tracks[ctr - 1].start_block; tracks[ctr - 1].length = start_sec - prev_time; /* if needed print out info */ if(verbose) { for(ctr = 1; ctr <= hdr.cdth_trk1; ctr++) { fprintf(stderr, "Track %02d: Start: %02d:%02d:%02d Length: %02d:%02d %3.2f MB lba: %d/%d\n", ctr, tracks[ctr].mins, tracks[ctr].secs, tracks[ctr].frames, tracks[ctr].length / 60, tracks[ctr].length % 60, (double) tracks[ctr].num_blocks * CDDA_BLKSIZE / (1024 * 1024), tracks[ctr].start_block, tracks[ctr].num_blocks); } } return hdr.cdth_trk1;}/* * write_sun_header - Write sun .au fmt type header */voidwrite_sun_header(int fd, int fmt){ int wrote, val; typedef unsigned long u_32; struct auheader { u_32 magic; u_32 hdr_size; u_32 data_size; u_32 encoding; u_32 sample_rate; u_32 channels; } hdr; /* initialize ulaw mappings */ ulawmap = (unsigned char *) malloc(65536); if(ulawmap == NULL) pop_error(ERR_MALLOC, "Error mallocing memory for ulawmap"); for(val = 0; val < 65536; val++) ulawmap[val] = linear_to_ulaw(val - 32768); ulawmap += 32768; hdr.magic = 0x2e736e64; hdr.hdr_size = sizeof(hdr) + 28; hdr.data_size = (fmt == AU16) ? 16 : 8; hdr.encoding = (fmt == AU16) ? 3 : 1; hdr.sample_rate = (fmt == AU16) ? 44100 : 8000; hdr.channels = (fmt == AU16) ? 2 : 1; wrote = write(fd, &hdr, sizeof(hdr)); if(wrote != sizeof(hdr)) pop_error(ERR_FILE, "Error writing to output file"); wrote = write(fd, "Recorded from CD by Read_CDDA", 28); if(wrote != 28) pop_error(ERR_FILE, "Error writing to output file");}intconvert(unsigned char *buf){ short *buf16 = (short *) buf; int ctr, ctr2, samples; int mono_value; unsigned char *bufend = buf + SAMPLES_PER_BLK * 4; for(ctr = 0; buf16 < (short *)(bufend); ctr++) { samples = (ctr & 1) ? ((ctr % 20) ? 10 : 12) : 12; if(buf16 + samples > (short *)(bufend)) samples = ((short *)bufend) - buf16; mono_value = 0; for(ctr2 = 0; ctr2 < samples; ctr2++) mono_value += *buf16++; mono_value /= samples; buf[ctr] = ulawmap[mono_value]; } return ctr;}/* * usage - Print out some command line help */voidusage(char *prog_name){ fprintf(stderr, "%s: Read audio track from CD to a file\n", prog_name); fprintf(stderr, "Written by Jim Mintha (mintha@geog.ubc.ca)\n"); fprintf(stderr, "Usage: %s [-h] [-a] [-8] [-d] [-t] [-D dev] [-s start] [-e end] track [outfile]\n", prog_name); fprintf(stderr, " track Track number to read\n"); fprintf(stderr, " outfile File name for PCM or .au output (\"-\" for stdout)\n"); fprintf(stderr, " -s --start Starting second for the track\n"); fprintf(stderr, " -e --end Ending second for the track\n"); fprintf(stderr, " -t --toc Only print out the Table of Contents\n"); fprintf(stderr, " -x --swap Swap bytes (for x86?)\n"); fprintf(stderr, " -8 --au8 Output in Sun .au format 8KHz\n"); fprintf(stderr, " -a --au16 Output in Sun .au format 44.1KHz\n"); fprintf(stderr, " -b --buffer Size of read-ahead buffer\n"); fprintf(stderr, " -v --verbose Be talkative while running\n"); fprintf(stderr, " -d --drvtype Print CD-ROM model type only\n"); fprintf(stderr, " -D --device Device to read from\n"); /* fprintf(stderr, " -W --whole Extract all tracks to [outfile].[t#]\n");*/ fprintf(stderr, " -V --version Print program version number only\n\n"); fprintf(stderr, " Default is to output in CDR format the whole track\n"); exit(0);}/* * all-done - Reset the blocksize and finish */voidall_done(int fd){ /* reset block size on cdrom */ if(ioctl(fd, CDROMSBLKMODE, 512) < 0) fprintf(stderr, "Unable to reset blocksize"); close(fd); exit(0);}/*** This routine converts from linear to ulaw.**** Craig Reese: IDA/Supercomputing Research Center** Joe Campbell: Department of Defense** 29 September 1989**** References:** 1) CCITT Recommendation G.711 (very difficult to follow)** 2) "A New Digital Technique for Implementation of Any** Continuous PCM Companding Law," Villeret, Michel,** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,** 1973, pg. 11.12-11.17** 3) MIL-STD-188-113,"Interoperability and Performance Standards** for Analog-to_Digital Conversion Techniques,"** 17 February 1987**** Input: Signed 16 bit linear sample** Output: 8 bit ulaw sample*/#define ZEROTRAP /* turn on the trap as per the MIL-STD */#define BIAS 0x84 /* define the add-in bias for 16 bit samples */#define CLIP 32635 unsigned charlinear_to_ulaw( sample )int sample;{ static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; int sign, exponent, mantissa; unsigned char ulawbyte; /* Get the sample into sign-magnitude. */ sign = (sample >> 8) & 0x80; /* set aside the sign */ if ( sign != 0 ) sample = -sample; /* get magnitude */ if ( sample > CLIP ) sample = CLIP; /* clip the magnitude */ /* Convert from 16 bit linear to ulaw. */ sample = sample + BIAS; exponent = exp_lut[( sample >> 7 ) & 0xFF]; mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F; ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );#ifdef ZEROTRAP if ( ulawbyte == 0 ) ulawbyte = 0x02; /* optional CCITT trap */#endif return ulawbyte;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -