1 /* Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors.
2  * This source code is freely redistributable and may be used for
3  * any purpose.  This copyright notice must be maintained.
4  * Guido van Rossum And Sundry Contributors are not responsible for
5  * the consequences of using this software.
6  */
7 
8 /*
9  * GSM 06.10 courtesy Communications and Operating Systems Research Group,
10  * Technische Universitaet Berlin
11  *
12  * Source code and more information on this format can be obtained from
13  * http://www.quut.com/gsm/
14  *
15  * Written 26 Jan 1995 by Andrew Pam
16  * Portions Copyright (c) 1995 Serious Cybernetics
17  *
18  * July 19, 1998 - Chris Bagwell (cbagwell@sprynet.com)
19  *   Added GSM support to SOX from patches floating around with the help
20  *   of Dima Barsky (ess2db@ee.surrey.ac.uk).
21  *
22  * Nov. 26, 1999 - Stan Brooks (stabro@megsinet.com)
23  *   Rewritten to support multiple channels
24  */
25 
26 #include "sox_i.h"
27 
28 #ifdef HAVE_GSM_GSM_H
29 #include <gsm/gsm.h>
30 #else
31 #include <gsm.h>
32 #endif
33 
34 #include <errno.h>
35 
36 #define MAXCHANS 16
37 
38 /* sizeof(gsm_frame) */
39 #define FRAMESIZE (size_t)33
40 /* samples per gsm_frame */
41 #define BLOCKSIZE 160
42 
43 /* Private data */
44 typedef struct {
45         unsigned        channels;
46         gsm_signal      *samples;
47         gsm_signal      *samplePtr;
48         gsm_signal      *sampleTop;
49         gsm_byte *frames;
50         gsm             handle[MAXCHANS];
51 } priv_t;
52 
gsmstart_rw(sox_format_t * ft,int w)53 static int gsmstart_rw(sox_format_t * ft, int w)
54 {
55         priv_t *p = (priv_t *) ft->priv;
56         unsigned ch;
57 
58         ft->encoding.encoding = SOX_ENCODING_GSM;
59         if (!ft->signal.rate)
60                 ft->signal.rate = 8000;
61 
62         if (ft->signal.channels == 0)
63             ft->signal.channels = 1;
64 
65         p->channels = ft->signal.channels;
66         if (p->channels > MAXCHANS || p->channels <= 0)
67         {
68                 lsx_fail_errno(ft,SOX_EFMT,"gsm: channels(%d) must be in 1-16", ft->signal.channels);
69                 return(SOX_EOF);
70         }
71 
72         for (ch=0; ch<p->channels; ch++) {
73                 p->handle[ch] = gsm_create();
74                 if (!p->handle[ch])
75                 {
76                         lsx_fail_errno(ft,errno,"unable to create GSM stream");
77                         return (SOX_EOF);
78                 }
79         }
80         p->frames = lsx_malloc(p->channels*FRAMESIZE);
81         p->samples = lsx_malloc(BLOCKSIZE * (p->channels+1) * sizeof(gsm_signal));
82         p->sampleTop = p->samples + BLOCKSIZE*p->channels;
83         p->samplePtr = (w)? p->samples : p->sampleTop;
84         return (SOX_SUCCESS);
85 }
86 
sox_gsmstartread(sox_format_t * ft)87 static int sox_gsmstartread(sox_format_t * ft)
88 {
89         return gsmstart_rw(ft,0);
90 }
91 
sox_gsmstartwrite(sox_format_t * ft)92 static int sox_gsmstartwrite(sox_format_t * ft)
93 {
94         return gsmstart_rw(ft,1);
95 }
96 
97 /*
98  * Read up to len samples from file.
99  * Convert to signed longs.
100  * Place in buf[].
101  * Return number of samples read.
102  */
103 
sox_gsmread(sox_format_t * ft,sox_sample_t * buf,size_t samp)104 static size_t sox_gsmread(sox_format_t * ft, sox_sample_t *buf, size_t samp)
105 {
106         size_t done = 0, r;
107         int ch, chans;
108         gsm_signal *gbuff;
109         priv_t *p = (priv_t *) ft->priv;
110 
111         chans = p->channels;
112 
113         while (done < samp)
114         {
115                 while (p->samplePtr < p->sampleTop && done < samp)
116                         buf[done++] =
117                             SOX_SIGNED_16BIT_TO_SAMPLE(*(p->samplePtr)++,);
118 
119                 if (done>=samp) break;
120 
121                 r = lsx_readbuf(ft, p->frames, p->channels * FRAMESIZE);
122                 if (r != p->channels * FRAMESIZE)
123                   break;
124 
125                 p->samplePtr = p->samples;
126                 for (ch=0; ch<chans; ch++) {
127                         int i;
128                         gsm_signal *gsp;
129 
130                         gbuff = p->sampleTop;
131                         if (gsm_decode(p->handle[ch], p->frames + ch*FRAMESIZE, gbuff) < 0)
132                         {
133                                 lsx_fail_errno(ft,errno,"error during GSM decode");
134                                 return (0);
135                         }
136 
137                         gsp = p->samples + ch;
138                         for (i=0; i<BLOCKSIZE; i++) {
139                                 *gsp = *gbuff++;
140                                 gsp += chans;
141                         }
142                 }
143         }
144 
145         return done;
146 }
147 
gsmflush(sox_format_t * ft)148 static int gsmflush(sox_format_t * ft)
149 {
150         int r, ch, chans;
151         gsm_signal *gbuff;
152         priv_t *p = (priv_t *) ft->priv;
153 
154         chans = p->channels;
155 
156         /* zero-fill samples as needed */
157         while (p->samplePtr < p->sampleTop)
158                 *(p->samplePtr)++ = 0;
159 
160         gbuff = p->sampleTop;
161         for (ch=0; ch<chans; ch++) {
162                 int i;
163                 gsm_signal *gsp;
164 
165                 gsp = p->samples + ch;
166                 for (i=0; i<BLOCKSIZE; i++) {
167                         gbuff[i] = *gsp;
168                         gsp += chans;
169                 }
170                 gsm_encode(p->handle[ch], gbuff, p->frames);
171                 r = lsx_writebuf(ft, p->frames, FRAMESIZE);
172                 if (r != FRAMESIZE)
173                 {
174                         lsx_fail_errno(ft,errno,"write error");
175                         return(SOX_EOF);
176                 }
177         }
178         p->samplePtr = p->samples;
179 
180         return (SOX_SUCCESS);
181 }
182 
sox_gsmwrite(sox_format_t * ft,const sox_sample_t * buf,size_t samp)183 static size_t sox_gsmwrite(sox_format_t * ft, const sox_sample_t *buf, size_t samp)
184 {
185         size_t done = 0;
186         priv_t *p = (priv_t *) ft->priv;
187 
188         while (done < samp)
189         {
190                 SOX_SAMPLE_LOCALS;
191                 while ((p->samplePtr < p->sampleTop) && (done < samp))
192                         *(p->samplePtr)++ =
193                             SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips);
194 
195                 if (p->samplePtr == p->sampleTop)
196                 {
197                         if(gsmflush(ft))
198                         {
199                             return 0;
200                         }
201                 }
202         }
203 
204         return done;
205 }
206 
sox_gsmstopread(sox_format_t * ft)207 static int sox_gsmstopread(sox_format_t * ft)
208 {
209         priv_t *p = (priv_t *) ft->priv;
210         unsigned ch;
211 
212         for (ch=0; ch<p->channels; ch++)
213                 gsm_destroy(p->handle[ch]);
214 
215         free(p->samples);
216         free(p->frames);
217         return (SOX_SUCCESS);
218 }
219 
sox_gsmstopwrite(sox_format_t * ft)220 static int sox_gsmstopwrite(sox_format_t * ft)
221 {
222         int rc;
223         priv_t *p = (priv_t *) ft->priv;
224 
225         if (p->samplePtr > p->samples)
226         {
227                 rc = gsmflush(ft);
228                 if (rc)
229                     return rc;
230         }
231 
232         return sox_gsmstopread(ft); /* destroy handles and free buffers */
233 }
234 
LSX_FORMAT_HANDLER(gsm)235 LSX_FORMAT_HANDLER(gsm)
236 {
237   static char const * const names[] = {"gsm", NULL};
238   static sox_rate_t   const write_rates[] = {8000, 0};
239   static unsigned const write_encodings[] = {SOX_ENCODING_GSM, 0, 0};
240   static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
241     "GSM 06.10 (full-rate) lossy speech compression", names, 0,
242     sox_gsmstartread, sox_gsmread, sox_gsmstopread,
243     sox_gsmstartwrite, sox_gsmwrite, sox_gsmstopwrite,
244     NULL, write_encodings, write_rates, sizeof(priv_t)
245   };
246   return &handler;
247 }
248