1 /* libSoX skeleton file format handler.
2  *
3  * Copyright 1999 Chris Bagwell And Sundry Contributors
4  *
5  * This library is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; either version 2.1 of the License, or (at
8  * your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "sox_i.h"
21 
22 #include <string.h>
23 
24 /* Private data for SKEL file */
25 typedef struct {
26   size_t remaining_samples;
27 } priv_t;
28 
29 /* Note that if any of your methods doesn't need to do anything, you
30    can instead use the relevant sox_*_nothing* method */
31 
32 /*
33  * Do anything required before you start reading samples.
34  * Read file header.
35  *      Find out sampling rate,
36  *      size and encoding of samples,
37  *      mono/stereo/quad.
38  */
startread(sox_format_t * ft)39 static int startread(sox_format_t * ft)
40 {
41   priv_t * sk = (priv_t *)ft->priv;
42   size_t samples_in_file;
43 
44   /* If you need to seek around the input file. */
45   if (!ft->seekable) {
46     lsx_fail_errno(ft, SOX_EOF, "skel inputfile must be a file");
47     return SOX_EOF;
48   }
49 
50   /*
51    * If your format is headerless and has fixed values for
52    * the following items, you can hard code them here (see cdr.c).
53    * If your format contains a header with format information
54    * then you should set it here.
55    */
56   ft->signal.rate = 44100; /* or 8000, 16000, 32000, 48000, ... */
57   ft->signal.channels = 1; /* or 2 or 3 ... */
58   ft->encoding.bits_per_sample = 8; /* or 16 ... */
59   ft->encoding.encoding = SOX_ENCODING_UNSIGNED; /* or SIGN2 ... */
60   sox_append_comment(&ft->oob.comments, "any comment in file header.");
61 
62   /* If your format doesn't have a header then samples_in_file
63    * can be determined by the file size.
64    */
65   samples_in_file = lsx_filelength(ft) / (ft->encoding.bits_per_sample >> 3);
66 
67   /* If you can detect the length of your file, record it here. */
68   ft->signal.length = samples_in_file;
69   sk->remaining_samples = samples_in_file;
70 
71   return SOX_SUCCESS;
72 }
73 
74 /*
75  * Read up to len samples of type sox_sample_t from file into buf[].
76  * Return number of samples read, or 0 if at end of file.
77  */
read_samples(sox_format_t * ft,sox_sample_t * buf,size_t len)78 static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len)
79 {
80   priv_t * UNUSED sk = (priv_t *)ft->priv;
81   size_t done;
82   unsigned char sample;
83 
84   for (done = 0; done < len; done++) {
85     if (lsx_eof(ft) || lsx_readb(ft, &sample)) /* no more samples */
86       break;
87     switch (ft->encoding.bits_per_sample) {
88     case 8:
89       switch (ft->encoding.encoding) {
90       case SOX_ENCODING_UNSIGNED:
91         *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(sample,);
92         break;
93       default:
94         lsx_fail("Undetected sample encoding in read!");
95         return 0;
96       }
97       break;
98     default:
99       lsx_fail("Undetected bad sample size in read!");
100       return 0;
101     }
102   }
103 
104   return done;
105 }
106 
107 /*
108  * Do anything required when you stop reading samples.
109  * Don't close input file!
110  */
stopread(sox_format_t UNUSED * ft)111 static int stopread(sox_format_t UNUSED * ft)
112 {
113   return SOX_SUCCESS;
114 }
115 
startwrite(sox_format_t * ft)116 static int startwrite(sox_format_t * ft)
117 {
118   priv_t * UNUSED sk = (priv_t *)ft->priv;
119 
120   /* If you have to seek around the output file. */
121   /* If header contains a length value then seeking will be
122    * required.  Instead of failing, it's sometimes nice to
123    * just set the length to max value and not fail.
124    */
125   if (!ft->seekable) {
126     lsx_fail("Output .skel file must be a file, not a pipe");
127     return SOX_EOF;
128   }
129 
130   if (ft->signal.rate != 44100)
131     lsx_fail("Output .skel file must have a sample rate of 44100Hz");
132 
133   if (ft->encoding.bits_per_sample == 0) {
134     lsx_fail("Did not specify a size for .skel output file");
135     return SOX_EOF;
136   }
137 
138   /* error check ft->encoding.encoding */
139   /* error check ft->signal.channels */
140 
141   /* Write file header, if any */
142   /* Write comment field, if any */
143 
144   return SOX_SUCCESS;
145 
146 }
147 
148 /*
149  * Write len samples of type sox_sample_t from buf[] to file.
150  * Return number of samples written.
151  */
write_samples(sox_format_t * ft,const sox_sample_t * buf,size_t len)152 static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len)
153 {
154   priv_t * sk = (priv_t *)ft->priv;
155   size_t done = 0;
156 
157   (void)sk;
158   switch (ft->encoding.bits_per_sample) {
159   case 8:
160     switch (ft->encoding.encoding) {
161     SOX_SAMPLE_LOCALS;
162     case SOX_ENCODING_UNSIGNED:
163       while (done < len && lsx_writeb(ft, SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips)) == SOX_SUCCESS)
164         ++done;
165       break;
166     default:
167       lsx_fail("Undetected bad sample encoding in write!");
168       return 0;
169     }
170     break;
171   default:
172     lsx_fail("Undetected bad sample size in write!");
173     return 0;
174   }
175   return done;
176 }
177 
stopwrite(sox_format_t UNUSED * ft)178 static int stopwrite(sox_format_t UNUSED * ft)
179 {
180   /* All samples are already written out. */
181   /* If file header needs fixing up, for example it needs the number
182      of samples in a field, seek back and write them here. */
183   return SOX_SUCCESS;
184 }
185 
seek(sox_format_t UNUSED * ft,uint64_t UNUSED offset)186 static int seek(sox_format_t UNUSED * ft, uint64_t UNUSED offset)
187 {
188   /* Seek relative to current position. */
189   return SOX_SUCCESS;
190 }
191 
LSX_FORMAT_HANDLER(skel)192 LSX_FORMAT_HANDLER(skel)
193 {
194   /* Format file suffixes */
195   static const char *names[] = {"skel",NULL };
196 
197   /* Encoding types and sizes that this handler can write */
198   static const unsigned encodings[] = {
199     SOX_ENCODING_SIGN2, 16, 0,
200     SOX_ENCODING_UNSIGNED, 8, 0,
201     0};
202 
203   /* Format descriptor
204    * If no specific processing is needed for any of
205    * the 7 functions, then the function above can be deleted
206    * and NULL used in place of the its name below.
207    */
208   static sox_format_handler_t handler = {
209     SOX_LIB_VERSION_CODE,
210     "My first SoX format!",
211     names, 0,
212     startread, read_samples, stopread,
213     startwrite, write_samples, stopwrite,
214     seek, encodings, NULL, sizeof(priv_t)
215   };
216 
217   return &handler;
218 }
219