📄 cdda2wav.c
字号:
/* @(#)cdda2wav.c 1.6 00/01/11 Copyright 1998,1999,2000 Heiko Eissfeldt */#ifndef lintstatic char sccsid[] ="@(#)cdda2wav.c 1.6 00/01/11 Copyright 1998,1999,2000 Heiko Eissfeldt";#endif#undef DEBUG_BUFFER_ADDRESSES#undef GPROF#undef DEBUG_FORKED#undef DEBUG_CLEANUP#undef DEBUG_DYN_OVERLAP#undef DEBUG_READS/* * Copyright: GNU Public License 2 applies * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * CDDA2WAV (C) 1995-1998 Heiko Eissfeldt heiko@colossus.escape.de * parts (C) Peter Widow * parts (C) Thomas Niederreiter * parts (C) RSA Data Security, Inc. * * last changes: * 18.12.93 - first version, OK * 01.01.94 - generalized & clean up HE * 10.06.94 - first linux version HE * 12.06.94 - wav header alignment problem fixed HE * 12.08.94 - open the cdrom device O_RDONLY makes more sense :-) * no more floating point math * change to sector size 2352 which is more common * sub-q-channel information per kernel ioctl requested * doesn't work as well as before * some new options (-max -i) * 01.02.95 - async i/o via semaphores and shared memory * 03.02.95 - overlapped reading on sectors * 03.02.95 - generalized sample rates. all integral divisors are legal * 04.02.95 - sun format added * more divisors: all integral halves >= 1 allowed * floating point math needed again * 06.02.95 - bugfix for last track and not d0 * tested with photo-cd with audio tracks * tested with xa disk * 29.01.96 - new options for bulk transfer * 01.06.96 - tested with enhanced cd * 01.06.96 - tested with cd-plus * 02.06.96 - support pipes * 02.06.96 - support raw format * 04.02.96 - security hole fixed * 22.04.97 - large parts rewritten * 28.04.97 - make file names DOS compatible * 01.09.97 - add speed control * 20.10.97 - add find mono option * Jan/Feb 98 - conversion to use Joerg Schillings SCSI library * */#include "config.h"#if defined (HAVE_UNISTD_H) && (HAVE_UNISTD_H == 1)#include <sys/types.h>#include <unistd.h>#endif#include <stdio.h>#include <standard.h>#include <stdlib.h>#include <strdefs.h>#if defined HAVE_STRINGS_H#include <strings.h>#endif#include <signal.h>#include <math.h>#include <fctldefs.h>#include <time.h>#if (defined (HAVE_SYS_TIME_H) || (HAVE_SYS_TIME_H != 1)) && defined (TIME_WITH_SYS_TIME)#include <sys/time.h>#endif#if defined (HAVE_LIMITS_H) && (HAVE_LIMITS_H == 1)#include <limits.h>#endif#if defined (HAVE_SYS_IOCTL_H) && (HAVE_SYS_IOCTL_H == 1)#include <sys/ioctl.h>#endif#if defined (HAVE_SYS_WAIT_H) && (HAVE_SYS_WAIT_H == 1)#include <sys/wait.h>#endif#include <vadefs.h>#include <standard.h>#include <scg/scsitransp.h>#include "mytype.h"#include "sndconfig.h"#include "semshm.h" /* semaphore functions */#include "sndfile.h"#include "wav.h" /* wav file header structures */#include "sun.h" /* sun audio file header structures */#include "raw.h" /* raw file handling */#include "aiff.h" /* aiff file handling */#include "aifc.h" /* aifc file handling */#include "interface.h" /* low level cdrom interfacing */#include "cdda2wav.h"#include "resample.h"#include "toc.h"#include "setuid.h"#include "ringbuff.h"#include "global.h"static const char * optstring = "D:A:I:O:c:b:r:a:t:i:d:o:n:v:l:E:C:S:p:M:P:K:smweNqxRBVhFGHTJgQ";extern char *optarg;extern int optind, opterr, optopt;int main __PR((int argc, char **argv));static void RestrictPlaybackRate __PR((long newrate));static void output_indices __PR((FILE *fp, index_list *p, unsigned trackstart));static int write_info_file __PR((char *fname_baseval, unsigned int track, unsigned long SamplesDone, int numbered));static void CloseAudio __PR((char *fname_baseval, unsigned int track, int bulkflag, int channels_val, unsigned long nSamples, struct soundfile *audio_out));static void CloseAll __PR((void));static void OpenAudio __PR((char *fname, double rate, long nBitsPerSample, long channels_val, unsigned long expected_bytes, struct soundfile*audio_out));static void set_offset __PR((myringbuff *p, int offset));static int get_offset __PR((myringbuff *p));static void usage __PR((void));static void init_globals __PR((void));#if defined (__GLIBC__) || defined(_GNU_C_SOURCE) || defined(__USE_GNU) || defined(__CYGWIN32__)#define USE_GETOPT_LONG#endif#ifdef USE_GETOPT_LONG#include <getopt.h> /* for get_long_opt () */static struct option options [] = { {"device",required_argument,NULL,'D'}, {"auxdevice",required_argument,NULL,'A'}, {"interface",required_argument,NULL,'I'}, {"output-format",required_argument,NULL,'O'}, {"channels",required_argument,NULL,'c'}, {"bits-per-sample",required_argument,NULL,'b'}, {"rate",required_argument,NULL,'r'}, {"divider",required_argument,NULL,'a'}, {"track",required_argument,NULL,'t'}, {"index",required_argument,NULL,'i'}, {"duration",required_argument,NULL,'d'}, {"offset",required_argument,NULL,'o'}, {"sectors-per-request",required_argument,NULL,'n'}, {"buffers-in-ring",required_argument,NULL,'l'}, {"output-endianess",required_argument,NULL,'E'}, {"cdrom-endianess",required_argument,NULL,'C'}, {"verbose-level",required_argument,NULL,'v'}, {"sound-device",required_argument,NULL,'K'},#ifdef MD5_SIGNATURES {"md5",required_argument,NULL,'M'},#endif {"stereo",no_argument,NULL,'s'}, {"mono",no_argument,NULL,'m'}, {"wait",no_argument,NULL,'w'}, {"find-extremes",no_argument,NULL,'F'}, {"find-mono",no_argument,NULL,'G'},#ifdef ECHO_TO_SOUNDCARD {"echo",no_argument,NULL,'e'},#endif {"info-only",no_argument,NULL,'J'}, {"no-write",no_argument,NULL,'N'}, {"no-infofile",no_argument,NULL,'H'}, {"quiet",no_argument,NULL,'q'}, {"max",no_argument,NULL,'x'}, {"set-overlap",required_argument,NULL,'P'}, {"speed-select",required_argument,NULL,'S'}, {"dump-rates",no_argument,NULL,'R'}, {"bulk",no_argument,NULL,'B'}, {"deemphasize",no_argument,NULL,'T'}, {"playback-realtime",required_argument,NULL,'p'}, {"verbose-SCSI",no_argument,NULL,'V'}, {"help",no_argument,NULL,'h'}, {"gui",no_argument,NULL,'g'}, {"silent-SCSI",no_argument,NULL,'Q'}, {NULL,0,NULL,0}};#endif /* USE_GETOPT_LONG */#if defined(__CYGWIN32__) ||defined(__EMX__)#include <io.h> /* for setmode() prototype */#endif/* global variables */global_t global;/* static variables */static unsigned long nSamplesDone = 0;static int child_pid = -2;static unsigned long nSamplesToDo;static unsigned int current_track;static int bulk = 0;static void RestrictPlaybackRate( newrate ) long newrate;{ global.playback_rate = newrate; if ( global.playback_rate < 25 ) global.playback_rate = 25; /* filter out insane values */ if ( global.playback_rate > 250 ) global.playback_rate = 250; if ( global.playback_rate < 100 ) global.nsectors = (global.nsectors*global.playback_rate)/100;}long SamplesNeeded( amount, undersampling_val) long amount; long undersampling_val;{ long retval = ((undersampling_val * 2 + Halved)*amount)/2; if (Halved && (nSamplesToDo & 1)) retval += 2; return retval;}static int argc2;static int argc3;static char **argv2;static void reset_name_iterator __PR((void));static void reset_name_iterator (){ argv2 -= argc3 - argc2; argc2 = argc3;}static char *get_next_name __PR((void));static char *get_next_name (){ if (argc2 > 0) { argc2--; return (*argv2++); } else { return NULL; }}static char *cut_extension __PR(( char * fname ));static char*cut_extension (fname) char *fname;{ char *pp; pp = strrchr(fname, '.'); if (pp == NULL) { pp = fname + strlen(fname); } *pp = '\0'; return pp;}#ifdef INFOFILESstatic void output_indices(fp, p, trackstart) FILE *fp; index_list *p; unsigned trackstart;{ int ci; fprintf(fp, "Index=\t\t"); if (p == NULL) { fprintf(fp, "0\n"); return; } for (ci = 1; p != NULL; ci++, p = p->next) { int frameoff = p->frameoffset; if (p->next == NULL) fputs("\nIndex0=\t\t", fp);#if 0 else if ( ci > 8 && (ci % 8) == 1) fputs("\nIndex =\t\t", fp);#endif if (frameoff != -1) fprintf(fp, "%d ", frameoff - trackstart); else fprintf(fp, "-1 "); } fputs("\n", fp);}/* * write information at the end of the sampling process * * * uglyfied for Joerg Schillings ultra dumb line parser */static int write_info_file(fname_baseval, track, SamplesDone, numbered) char *fname_baseval; unsigned int track; unsigned long int SamplesDone; int numbered;{ FILE *info_fp; char fname[200]; char datetime[30]; time_t utc_time; struct tm *tmptr; /* write info file */ if (!strcmp(fname_baseval,"standard output")) return 0; strncpy(fname, fname_baseval, sizeof(fname) -1); fname[sizeof(fname) -1] = 0; if (numbered) sprintf(cut_extension(fname), "_%02u.inf", track); else strcpy(cut_extension(fname), ".inf"); info_fp = fopen (fname, "w"); if (!info_fp) return -1;#ifdef MD5_SIGNATURES if (global.md5blocksize) MD5Final (global.MD5_result, &global.context);#endif utc_time = time(NULL); tmptr = localtime(&utc_time); if (tmptr) { strftime(datetime, sizeof(datetime), "%x %X", tmptr); } else { strncpy(datetime, "unknown", sizeof(datetime)); } fprintf(info_fp, "#created by cdda2wav %s %s\n#\n", VERSION , datetime ); fprintf(info_fp,"CDINDEX_DISCID=\t'%s'\n" , global.cdindex_id); fprintf(info_fp,"CDDB_DISCID=\t0x%08lx\nMCN=\t\t%s\nISRC=\t\t%15.15s\n#\nAlbumtitle=\t'%s'\n" , (unsigned long) global.cddb_id , MCN , g_toc[track-1].ISRC , global.disctitle != NULL ? global.disctitle : (const unsigned char *)"" ); fprintf(info_fp, "Tracktitle=\t'%s'\n" , global.tracktitle[track-1] ? global.tracktitle[track-1] : (const unsigned char *)"" ); fprintf(info_fp, "Tracknumber=\t%u\n" , track ); fprintf(info_fp, "Trackstart=\t%d\n" , g_toc[track-1].dwStartSector ); fprintf(info_fp, "# track length in sectors (1/75 seconds each), rest samples\nTracklength=\t%ld, %d\n" , SamplesDone/588L,(int)(SamplesDone%588)); fprintf(info_fp, "Pre-emphasis=\t%s\n" , g_toc[track-1].bFlags & 1 ? "yes" : "no"); fprintf(info_fp, "Channels=\t%d\n" , g_toc[track-1].bFlags & 8 ? 4 : 2); fprintf(info_fp, "Copy_permitted=\t%s\n" , g_toc[track-1].bFlags & 2 ? "yes" : "no"); fprintf(info_fp, "Endianess=\t%s\n" , global.need_big_endian ? "big" : "little" ); fprintf(info_fp, "# index list\n"); output_indices(info_fp, global.trackindexlist[track-1], GetStartSector(track));#ifdef MD5_SIGNATURES fprintf(info_fp, "#(blocksize) checksum\nMD-5=\t\t(%d) %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" , global.md5blocksize , global.MD5_result[0] , global.MD5_result[1] , global.MD5_result[2] , global.MD5_result[3] , global.MD5_result[4] , global.MD5_result[5] , global.MD5_result[6] , global.MD5_result[7] , global.MD5_result[8] , global.MD5_result[9] , global.MD5_result[10] , global.MD5_result[11] , global.MD5_result[12] , global.MD5_result[13] , global.MD5_result[14] , global.MD5_result[15]);#endif fclose(info_fp); return 0;}#endifstatic void CloseAudio(fname_baseval, track, bulkflag, channels_val, nSamples, audio_out) char *fname_baseval; unsigned int track; int bulkflag; int channels_val; unsigned long nSamples; struct soundfile *audio_out;{ /* define length */ audio_out->ExitSound( global.audio, nSamples*global.OutSampleSize*channels_val ); close (global.audio); global.audio = -1;}static unsigned int track = 1;/* On terminating: * define size-related entries in audio file header, update and close file */static void CloseAll (){ int chld_return_status = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -