gitchangelog.sh: state inside comments that GNU sed is required
[cdimgtools:cdimgtools.git] / raw96cdconv
1 #!/usr/bin/perl -w
2 # Copyright © 2012 Géraud Meyer <graud@gmx.com>
3 #   This program is free software; you can redistribute it and/or modify
4 #   it under the terms of the GNU General Public License version 2 as
5 #   published by the Free Software Foundation.
6 #
7 #   This program is distributed in the hope that it will be useful, but
8 #   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 #   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10 #   for more details.
11 #
12 #   You should have received a copy of the GNU General Public License along
13 #   with this program.  If not, see <http://www.gnu.org/licenses/>.
14
15 =encoding utf-8
16
17 =head1 NAME
18
19 raw96cdconv - converts between different formats of CD raw images 
20
21 =head1 SYNOPSIS
22
23 B<raw96cdconv> B<--version>
24
25 B<raw96cdconv> S<[ B<-v> ]> S<[ B<-n> ]> S<[ B<-f> ]> S<[ B<-c> | B<-r> ]> S<[ B<-S> ]> S<[ B<-I<C>> I<ext> ]> S<[ I<files> ]>
26
27 =cut
28
29 use strict;
30
31 use Getopt::Long;
32 Getopt::Long::Configure('bundling', 'no_auto_abbrev', 'auto_version', 'auto_help');
33
34 $main::VERSION = "1.1";
35
36 my ($verbose, $no_act, $force, $swab, $subchan, $fullraw);
37 my $raw_sect = 2352;
38 my $raw = '.raw';
39 my $subch = '.subch';
40 my $raw96 = '';
41 die Getopt::Long::HelpMessage(128)
42         unless GetOptions(
43                 'v|verbose!'    => \$verbose,
44                 'quiet'         => sub { $verbose = 0 },
45                 'n|no-act!'     => \$no_act,
46                 'f|force!'      => \$force,
47                 'S|swab!'       => \$swab,
48                 'sector-size=i' => \$raw_sect,
49                 'iso'           => sub { $raw_sect = 2048; $raw = ".iso" },
50                 'c|subchan!'    => \$subchan,
51                 'r|fullraw!'    => \$fullraw,
52                 'D|raw=s'       => \$raw,
53                 'C|subch=s'     => \$subch,
54                 'R|raw96=s'     => \$raw96,
55                 );
56 $verbose++ if $no_act;
57
58 my $subch_sect = 96;
59 my $raw96_sect = $raw_sect + $subch_sect;
60
61 if (!@ARGV) {
62         print "Reading filenames from STDIN\n" if $verbose;
63         @ARGV = <STDIN>;
64         chomp(@ARGV);
65 }
66
67 my $rc = 0;
68 FILE: for (@ARGV) {
69         my $src = $_ .(($fullraw) ? $raw : $raw96);
70         my $in_sect = ($fullraw) ? $raw_sect : $raw96_sect;
71         my $dst = $_ .(($fullraw) ? $raw96 : (($subchan) ? $subch : $raw));
72         unless ($force or !-e $dst) {
73                 warn "Skipping '$_' because '$dst' already exists\n" if $verbose;
74                 $rc++; next FILE;
75         }
76         unless (open SRC, "<", $src) {
77                 warn "ERROR Cannot open file '$src' for reading: $!\n";
78                 $rc++; next FILE;
79         }
80         binmode SRC;
81         unless ($no_act or open DST, ">", $dst) {
82                 warn "ERROR Cannot open file '$dst' for writing: $!\n";
83                 $rc++; next FILE;
84         }
85         binmode DST unless $no_act;
86         if ($fullraw) {
87                 unless (open SUBCH, "<", $_ .$subch) {
88                         warn "ERROR Cannot open file '$_$subch' for reading: $!\n";
89                         $rc++; next FILE;
90                 }
91                 binmode SUBCH;
92         }
93         my $count = 0;
94         my $buf;
95         SECTOR: while (my $n = read SRC, $buf, $in_sect) {
96                 unless ($n == $in_sect) {
97                         warn "ERROR Partial sector of size $n/$in_sect found in '$src'\n";
98                         $rc++; last SECTOR;
99                 }
100                 if ($fullraw) {
101                         $buf = pack '(v)*', unpack('(n)*', $buf) if ($swab);
102                         print DST $buf unless $no_act;
103                         my $m = read SUBCH, $buf, $subch_sect;
104                         unless ($m == $subch_sect) {
105                                 warn "ERROR Partial sub-channel block of size $m/$subch_sect found in '$_$subch'\n";
106                                 $rc++; last SECTOR;
107                         }
108                         print DST $buf unless $no_act;
109                 } elsif ($subchan) {
110                         print DST substr($buf, $raw_sect) unless $no_act;
111                 } else {
112                         $buf = pack '(v)*', unpack('(n)*', substr($buf, 0, $raw_sect)) if ($swab);
113                         print DST substr($buf, 0, $raw_sect) unless $no_act;
114                 }
115                 $count++;
116         }
117         print "$count sectors from '$src' written in '$dst'\n" if $verbose;
118 } continue {
119         close SRC; close DST; close SUBCH if ($fullraw);
120 }
121 print "There was $rc errors.\n" if $verbose and $rc;
122 exit 1 if $rc;
123
124 __END__
125
126 =head1 DESCRIPTION
127
128 C<raw96cdconv> generates a raw file by extracting raw CD sectors (made up either
129 of audio data or of raw data sectors) from a file made up of chunks containing
130 both raw data and sub-channel data (RAW+96).  By default F<.raw> is appended to
131 the given file names to obtain the corresponding generated file name.  If no
132 filenames are given on the command line, filenames will be read via standard
133 input.
134
135 It is also possible to generate a file containing only sub-channel data or to
136 re-generate the full RAW+96 file containing both the raw and the sub-channel
137 data.  The default extension for sub-channel files is F<.subch>.
138
139 The sector size of raw data is 2352 bytes; the corresponding sub-channel data
140 is 96 bytes long, so that the full RAW+96 file is made of chunks of 2448 bytes.
141
142 C<raw96cdconv> also works with images containing only data sectors (2048 bytes
143 long) and sub-channel data.
144
145
146 =head1 OPTIONS
147
148 Options can be negated by prefixing them with "--no-" instead of "--".
149
150 =over 8
151
152 =item B<--version>
153
154 Print the version information and exit.
155
156 =item B<-v>, B<--verbose>
157
158 Verbose: print the names of the files successfully generated as well as their
159 number of sectors, print the names of the files completely skipped and at the
160 end print the number of files that caused an error.
161
162 =item B<-n>, B<--no-act>
163
164 No Action: test the reading of files and show what files would have been
165 generated.
166
167 =item B<-f>, B<--force>
168
169 Force: overwrite existing files.
170
171 =item B<-S>, B<--swab>
172
173 Swap byte: swap the byte order of the raw data; it works for both normal mode
174 (raw data extraction) and full raw data mode.  Use it with readcd(1) images
175 that contain little endian audio data.
176
177 =item B<--sector-size>
178
179 By default 2352, which corresponds to audio data (or to a raw sector of any
180 data).  Use 2048 for error corrected data sectors.
181
182 =item B<--iso>
183
184 Same as `B<--raw> .iso B<--sector-size> 2048'.
185
186 =item B<-c>, B<--subchan>
187
188 Sub-channel mode: generate a file containing only sub-channel data from the
189 RAW+96 data file.
190
191 =item B<-r>, B<--fullraw>
192
193 Full raw data mode: (re-)generate a RAW+96 file containing both raw and
194 sub-channel data from the raw file and the sub-channel data file.
195
196 =item B<-D>, B<--raw> I<ext>
197
198 =item B<-C>, B<--subch> I<ext>
199
200 =item B<-R>, B<--raw96> I<ext>
201
202 Extension: file name extensions appended to the name given on the command line;
203 the first one is for raw files (default: F<.raw>); the second one is for
204 sub-channel data files (default: F<.subch>); the third one is for RAW+96 data
205 files (default: empty extension).
206
207 =back
208
209
210 =head1 ENVIRONMENT
211
212 No environment variables are used.
213
214
215 =head1 EXAMPLES
216
217 For example, to generate both a raw file F<image.raw> and a sub-channel file
218 F<image.subch>:
219
220         raw96cdconv image
221         raw96cdconv -c image
222
223 To re-generate F<image> from F<image.raw> and F<image.subch>:
224
225         raw96cdconv -r image
226
227 To generate F<image.raw96> instead of F<image>:
228
229         raw96cdconv -R .raw96 -r image
230
231 To extract an iso image F<image.iso> from F<image> that contains both (error
232 corrected) data sectors and sub-channel data:
233
234         raw96cdconv --iso image
235
236 If F<image> contains the image of a CDDA, it is more appropriate to extract to
237 F<image.cdda>:
238
239         raw96cdconv -A .cdda image
240
241 To convert the extracted raw audio to WAV, you can use sox(1):
242
243         sox -t .cdda image.cdda image.wav
244
245 To convert the extracted 2352b/s raw data to ISO, you can use ccd2iso(1):
246
247         ccd2iso image.raw image.iso
248
249
250 =head1 BUGS
251
252 No bugs or limitations are known.
253
254 See also the CDimgtools distribution file F<BUGS>.
255
256 =head1 AUTHOR
257
258 G.raud Meyer
259
260 =head1 SEE ALSO
261
262 L<cdrdao(1)>, L<readcd(1)>, L<soxformat(7)>, L<ccd2iso(1)>
263
264 =cut