1 /*  mode_cue.c - cue sheet mode module
2  *  Copyright (C) 2000-2009  Jason Jordan <shnutils@freeshell.org>
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU General Public License
6  *  as published by the Free Software Foundation; either version 2
7  *  of the License, or (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, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include <string.h>
20 #include "mode.h"
21 
22 CVSID("$Id: mode_cue.c,v 1.48 2009/03/17 17:23:05 jason Exp $")
23 
24 static bool cue_main(int,char **);
25 static void cue_help(void);
26 
27 mode_module mode_cue = {
28   "cue",
29   "shncue",
30   "Generates a CUE sheet or split points from a set of files",
31   CVSIDSTR,
32   FALSE,
33   cue_main,
34   cue_help
35 };
36 
37 enum {
38   TYPE_UNKNOWN,
39   TYPE_CUESHEET,
40   TYPE_SPLITPOINTS
41 };
42 
43 static int output_type = TYPE_UNKNOWN;
44 
45 static double total_data_size = 0.0;
46 static int numfiles = 0;
47 
48 static wave_info *totals = NULL;
49 
cue_help()50 static void cue_help()
51 {
52   st_info("Usage: %s [OPTIONS] [files]\n",st_progname());
53   st_info("\n");
54   st_info("Mode-specific options:\n");
55   st_info("\n");
56   st_info("  -c      generate CUE sheet (default)\n");
57   st_info("  -h      show this help screen\n");
58   st_info("  -s      generate split points in explicit byte-offset format\n");
59   st_info("\n");
60 }
61 
parse(int argc,char ** argv,int * first_arg)62 static void parse(int argc,char **argv,int *first_arg)
63 {
64   int c;
65 
66   output_type = TYPE_CUESHEET;
67 
68   while ((c = st_getopt(argc,argv,"cs")) != -1) {
69     switch (c) {
70       case 'c':
71         output_type = TYPE_CUESHEET;
72         break;
73       case 's':
74         output_type = TYPE_SPLITPOINTS;
75         break;
76     }
77   }
78 
79   *first_arg = optind;
80 }
81 
verify_wave_info(wave_info * info)82 static void verify_wave_info(wave_info *info)
83 {
84   if ((TYPE_CUESHEET == output_type) && PROB_NOT_CD(info)) {
85     st_error("file is not CD-quality: [%s]",info->filename);
86   }
87 
88   if (0 == totals->wave_format && 0 == totals->channels &&
89       0 == totals->samples_per_sec && 0 == totals->avg_bytes_per_sec &&
90       0 == totals->bits_per_sample && 0 == totals->block_align) {
91     totals->wave_format = info->wave_format;
92     totals->channels = info->channels;
93     totals->samples_per_sec = info->samples_per_sec;
94     totals->avg_bytes_per_sec = info->avg_bytes_per_sec;
95     totals->bits_per_sample = info->bits_per_sample;
96     totals->block_align = info->block_align;
97     totals->problems = info->problems;
98     return;
99   }
100 
101   if (info->wave_format != totals->wave_format)
102     st_error("WAVE format differs among these files");
103 
104   if (info->channels != totals->channels)
105     st_error("number of channels differs among these files");
106 
107   if (info->samples_per_sec != totals->samples_per_sec)
108     st_error("samples per second differs among these files");
109 
110   if (info->avg_bytes_per_sec != totals->avg_bytes_per_sec)
111     st_error("average bytes per second differs among these files");
112 
113   if (info->bits_per_sample != totals->bits_per_sample)
114     st_error("bits per sample differs among these files");
115 
116   if (info->block_align != totals->block_align) {
117     st_warning("block align differs among these files");
118   }
119 }
120 
output_init()121 static void output_init()
122 {
123   if (NULL == (totals = new_wave_info(NULL)))
124     st_error("could not allocate memory for totals");
125 
126   if (output_type == TYPE_CUESHEET) {
127     st_output("FILE \"joined.wav\" WAVE\n");
128   }
129 }
130 
output_track(char * filename)131 static bool output_track(char *filename)
132 {
133   wave_info *info;
134   wlong curr_data_size = 0;
135   char *p;
136 
137   if (NULL == (info = new_wave_info(filename)))
138     return FALSE;
139 
140   verify_wave_info(info);
141 
142   numfiles++;
143 
144   curr_data_size = info->data_size;
145 
146   if (output_type == TYPE_CUESHEET) {
147     info->data_size = (wlong)total_data_size;
148     info->length = info->data_size / info->rate;
149     length_to_str(info);
150     if ((p = strstr(info->m_ss,".")))
151       *p = ':';
152     st_output("  TRACK %02d AUDIO\n",numfiles);
153     st_output("    INDEX 01 %s\n",info->m_ss);
154   }
155   else if (output_type == TYPE_SPLITPOINTS) {
156     if (total_data_size > 0.0)
157       st_output("%0.0f\n",total_data_size);
158   }
159 
160   total_data_size += (double)curr_data_size;
161 
162   return TRUE;
163 }
164 
output_end()165 static void output_end()
166 {
167   if (TYPE_CUESHEET == output_type && numfiles < 1) {
168     st_error("need one or more files in order to generate CUE sheet");
169   }
170 
171   if (TYPE_SPLITPOINTS == output_type && numfiles < 2) {
172     st_error("need two or more files in order to generate split points");
173   }
174 }
175 
process(int argc,char ** argv,int start)176 static bool process(int argc,char **argv,int start)
177 {
178   char *filename;
179   bool success;
180 
181   success = TRUE;
182 
183   output_init();
184 
185   input_init(start,argc,argv);
186 
187   while ((filename = input_get_filename())) {
188     success = (output_track(filename) && success);
189   }
190 
191   output_end();
192 
193   return success;
194 }
195 
cue_main(int argc,char ** argv)196 static bool cue_main(int argc,char **argv)
197 {
198   int first_arg;
199 
200   parse(argc,argv,&first_arg);
201 
202   return process(argc,argv,first_arg);
203 }
204