1 /*
2   Copyright (C) 2005, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
16 */
17 
18 /* Simple program to show using libcdio's version of the CD-DA paranoia.
19    library.  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #define __CDIO_CONFIG_H__ 1
23 #endif
24 
25 #include <iostream>
26 #include <cstdlib>
27 #include <fstream>
28 #include <iomanip>
29 using namespace std;
30 
31 extern "C"{
32   #ifdef HAVE_STDIO_H
33   #include <stdio.h>
34   #endif
35   #ifdef HAVE_STDLIB_H
36   #include <stdlib.h>
37   #endif
38 
39   #include <cdio/paranoia.h>
40   #include <cdio/cd_types.h>
41 }
42 
43 
44 int
main(int argc,const char * argv[])45 main(int argc, const char *argv[])
46 {
47   cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */
48   char **ppsz_cd_drives;  /* List of all drives with a loaded CDDA in it. */
49 
50   /* See if we can find a device with a loaded CD-DA in it. */
51   ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
52 
53   if (ppsz_cd_drives) {
54     /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in
55        the list. */
56     d = cdda_identify(*ppsz_cd_drives, 1, NULL);
57   } else {
58     cerr << "Unable to access to a CD-ROM drive with audio CD in it";
59     return -1;
60   }
61 
62   /* Don't need a list of CD's with CD-DA's any more. */
63   cdio_free_device_list(ppsz_cd_drives);
64 
65   if ( !d ) {
66     cerr << "Unable to identify audio CD disc.\n";
67     return -1;
68   }
69 
70   /* We'll set for verbose paranoia messages. */
71   cdda_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT);
72 
73   if ( 0 != cdda_open(d) ) {
74     cerr << "Unable to open disc.\n";
75     return -1;
76   }
77 
78   /* Okay now set up to read up to the first 300 frames of the first
79      audio track of the Audio CD. */
80   {
81     cdrom_paranoia_t *p = paranoia_init(d);
82     lsn_t i_first_lsn = cdda_disc_firstsector(d);
83 
84     if ( -1 == i_first_lsn ) {
85       printf("Trouble getting starting LSN\n");
86     } else {
87       lsn_t   i_cursor;
88       track_t i_track    = cdda_sector_gettrack(d, i_first_lsn);
89       lsn_t   i_last_lsn = cdda_track_lastsector(d, i_track);
90 
91       /* For demo purposes we'll read only 300 frames (about 4
92 	 seconds).  We don't want this to take too long. On the other
93 	 hand, I suppose it should be something close to a real test.
94        */
95       if ( i_last_lsn - i_first_lsn > 300) i_last_lsn = i_first_lsn + 299;
96 
97       printf("Reading track %d from LSN %ld to LSN %ld\n", i_track,
98 	     (long int) i_first_lsn, (long int) i_last_lsn);
99 
100       /* Set reading mode for full paranoia, but allow skipping sectors. */
101       paranoia_modeset(p, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
102 
103       paranoia_seek(p, i_first_lsn, SEEK_SET);
104       //Get the track size in bytes and conver it to string
105       unsigned int byte_count =
106 	( i_last_lsn - i_first_lsn + 1 ) * CDIO_CD_FRAMESIZE_RAW;
107 
108       // Open the output file
109       ofstream outfile ("track01.wav",
110 			ofstream::binary | ofstream::app | ofstream::out);
111 
112       // Write format header specification
113       const int waweChunkLength   = byte_count + 44 - 8;
114       const int fmtChunkLength    = 16;
115       const int compressionCode   = 1;
116       const int numberOfChannels  = 2;
117       const int sampleRate        = 44100;  // Hz
118       const int blockAlign        = sampleRate*2*2;
119       const int significantBps    = 4;
120       const int extraFormatBytes  = 16;
121 
122 #define writestr(str) outfile.write(str, sizeof(str)-1)
123       writestr("RIFF");
124       outfile.write((char*)&waweChunkLength, 4);
125       writestr("WAVEfmt ");
126       outfile.write((char*) &fmtChunkLength, 4);
127       outfile.write((char*) &compressionCode, 2);
128       outfile.write((char*) &numberOfChannels, 2);
129       outfile.write((char*) &sampleRate, 4);
130       outfile.write((char*) &blockAlign, 4);
131       outfile.write((char*) &significantBps, 2);
132       outfile.write((char*) &extraFormatBytes, 2);
133       writestr("data");
134       outfile.write((char*) &byte_count,4);
135 
136       for ( i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor ++) {
137 	/* read a sector */
138 	int16_t *p_readbuf=paranoia_read(p, NULL);
139 	char *psz_err=cdda_errors(d);
140 	char *psz_mes=cdda_messages(d);
141 
142 	if (psz_mes || psz_err)
143 	  cerr << psz_err << psz_mes;
144 
145 	if (psz_err) free(psz_err);
146 	if (psz_mes) free(psz_mes);
147 	if( !p_readbuf ) {
148 	  cerr << "paranoia read error. Stopping.\n";
149 	  break;
150 	}
151 
152 	char *temp= (char*) p_readbuf;
153 	outfile.write(temp, CDIO_CD_FRAMESIZE_RAW);
154 
155       }
156     }
157     paranoia_free(p);
158   }
159 
160   cdda_close(d);
161 
162   exit(0);
163 }
164