1 /*  mode_gen.c - gen 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_gen.c,v 1.53 2009/03/16 04:46:03 jason Exp $")
23 
24 static bool gen_main(int,char **);
25 static void gen_help(void);
26 
27 mode_module mode_gen = {
28   "gen",
29   "shngen",
30   "Generates CD-quality PCM WAVE data files containing silence",
31   CVSIDSTR,
32   TRUE,
33   gen_main,
34   gen_help
35 };
36 
37 #define GEN_PREFIX "silence"
38 
39 static char *gen_size = NULL;
40 
gen_help()41 static void gen_help()
42 {
43   st_info("Usage: %s [OPTIONS]\n",st_progname());
44   st_info("\n");
45   st_info("Mode-specific options:\n");
46   st_info("\n");
47   st_info("  -h      show this help screen\n");
48   st_info("  -l len  generate files containing silence of length len (*)\n");
49   st_info("\n");
50   st_info("          (*) len must be in bytes, m:ss, m:ss.ff or m:ss.nnn format\n");
51   st_info("\n");
52 }
53 
parse(int argc,char ** argv)54 static void parse(int argc,char **argv)
55 {
56   int c;
57 
58   st_ops.output_directory = CURRENT_DIR;
59   st_ops.output_prefix = GEN_PREFIX;
60 
61   while ((c = st_getopt(argc,argv,"l:")) != -1) {
62     switch (c) {
63       case 'l':
64         if (NULL == optarg)
65           st_error("missing silence length");
66         gen_size = optarg;
67         break;
68     }
69   }
70 
71   if (NULL == gen_size)
72     st_error("length must be specified");
73 }
74 
process()75 static bool process()
76 {
77   wave_info *info;
78   unsigned char header[CANONICAL_HEADER_SIZE],silence[XFER_SIZE];
79   char outfilename[FILENAME_SIZE];
80   FILE *output;
81   proc_info output_proc;
82   wlong gen_bytes,bytes_left,bytes;
83   progress_info proginfo;
84   bool success;
85 
86   success = FALSE;
87 
88   if (NULL == (info = new_wave_info(NULL))) {
89     st_error("could not allocate memory for WAVE info");
90   }
91 
92   info->rate = CD_RATE;
93 
94   gen_bytes = smrt_parse((unsigned char *)gen_size,info);
95 
96   create_output_filename("","",outfilename);
97 
98   info->channels = CD_CHANNELS;
99   info->samples_per_sec = CD_SAMPLES_PER_SEC;
100   info->avg_bytes_per_sec = CD_RATE;
101   info->block_align = CD_BLOCK_ALIGN;
102   info->bits_per_sample = CD_BITS_PER_SAMPLE;
103   info->wave_format = WAVE_FORMAT_PCM;
104   info->rate = CD_RATE;
105 
106   info->data_size = gen_bytes;
107   info->chunk_size = info->data_size + CANONICAL_HEADER_SIZE - 8;
108   info->length = info->data_size / (wlong)info->rate;
109   info->exact_length = (double)info->data_size / (double)info->rate;
110 
111   if (PROB_ODD_SIZED_DATA(info))
112     info->chunk_size++;
113 
114   make_canonical_header(header,info);
115 
116   length_to_str(info);
117 
118   bytes_left = gen_bytes;
119 
120   memset((void *)silence,0,XFER_SIZE);
121 
122   proginfo.initialized = FALSE;
123   proginfo.prefix = "Generating";
124   proginfo.clause = NULL;
125   proginfo.filename1 = NULL;
126   proginfo.filedesc1 = NULL;
127   proginfo.filename2 = outfilename;
128   proginfo.filedesc2 = info->m_ss;
129   proginfo.bytes_total = bytes_left + CANONICAL_HEADER_SIZE;
130 
131   prog_update(&proginfo);
132 
133   if (NULL == (output = open_output_stream(outfilename,&output_proc)))
134     st_error("could not open output file: [%s]",outfilename);
135 
136   if (write_n_bytes(output,header,CANONICAL_HEADER_SIZE,&proginfo) != CANONICAL_HEADER_SIZE) {
137     prog_error(&proginfo);
138     st_error("error while writing %d-byte WAVE header",CANONICAL_HEADER_SIZE);
139   }
140 
141   while (bytes_left > 0) {
142     bytes = min(bytes_left,XFER_SIZE);
143 
144     if (write_n_bytes(output,silence,bytes,&proginfo) != bytes) {
145       prog_error(&proginfo);
146       st_error("error while writing %d-byte chunk of silence",bytes);
147     }
148 
149     bytes_left -= bytes;
150   }
151 
152   if (PROB_ODD_SIZED_DATA(info) && (1 != write_padding(output,1,&proginfo))) {
153     prog_error(&proginfo);
154     st_error("error while NULL-padding odd-sized data chunk");
155   }
156 
157   success = TRUE;
158 
159   prog_success(&proginfo);
160 
161   if (CLOSE_CHILD_ERROR_OUTPUT == close_output(output,output_proc)) {
162     success = FALSE;
163   }
164 
165   return success;
166 }
167 
gen_main(int argc,char ** argv)168 static bool gen_main(int argc,char **argv)
169 {
170   parse(argc,argv);
171 
172   return process();
173 }
174