ref: 4933b58e02567cfd5842c6e7f44308ee01d466ea
dir: /src/gsm.c/
/* Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors. * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Guido van Rossum And Sundry Contributors are not responsible for * the consequences of using this software. */ /* * GSM 06.10 courtesy Communications and Operating Systems Research Group, * Technische Universitaet Berlin * * More information on this format can be obtained from * http://www.cs.tu-berlin.de/~jutta/toasox.html * * Source is available from ftp://ftp.cs.tu-berlin.de/pub/local/kbs/tubmik/gsm * * Written 26 Jan 1995 by Andrew Pam * Portions Copyright (c) 1995 Serious Cybernetics * * July 19, 1998 - Chris Bagwell (cbagwell@sprynet.com) * Added GSM support to SOX from patches floating around with the help * of Dima Barsky (ess2db@ee.surrey.ac.uk). * * Nov. 26, 1999 - Stan Brooks (stabro@megsinet.com) * Rewritten to support multiple channels */ #include "sox_i.h" #ifdef EXTERNAL_GSM #ifdef HAVE_GSM_GSM_H #include <gsm/gsm.h> #else #include <gsm.h> #endif #else #include "../libgsm/gsm.h" #endif #include <errno.h> #define MAXCHANS 16 /* sizeof(gsm_frame) */ #define FRAMESIZE (size_t)33 /* samples per gsm_frame */ #define BLOCKSIZE 160 /* Private data */ typedef struct { unsigned channels; gsm_signal *samples; gsm_signal *samplePtr; gsm_signal *sampleTop; gsm_byte *frames; gsm handle[MAXCHANS]; } priv_t; static int gsmstart_rw(sox_format_t * ft, int w) { priv_t *p = (priv_t *) ft->priv; unsigned ch; ft->encoding.encoding = SOX_ENCODING_GSM; if (!ft->signal.rate) ft->signal.rate = 8000; if (ft->signal.channels == 0) ft->signal.channels = 1; p->channels = ft->signal.channels; if (p->channels > MAXCHANS || p->channels <= 0) { lsx_fail_errno(ft,SOX_EFMT,"gsm: channels(%d) must be in 1-16", ft->signal.channels); return(SOX_EOF); } for (ch=0; ch<p->channels; ch++) { p->handle[ch] = gsm_create(); if (!p->handle[ch]) { lsx_fail_errno(ft,errno,"unable to create GSM stream"); return (SOX_EOF); } } p->frames = lsx_malloc(p->channels*FRAMESIZE); p->samples = lsx_malloc(BLOCKSIZE * (p->channels+1) * sizeof(gsm_signal)); p->sampleTop = p->samples + BLOCKSIZE*p->channels; p->samplePtr = (w)? p->samples : p->sampleTop; return (SOX_SUCCESS); } static int sox_gsmstartread(sox_format_t * ft) { return gsmstart_rw(ft,0); } static int sox_gsmstartwrite(sox_format_t * ft) { return gsmstart_rw(ft,1); } /* * Read up to len samples from file. * Convert to signed longs. * Place in buf[]. * Return number of samples read. */ static size_t sox_gsmread(sox_format_t * ft, sox_sample_t *buf, size_t samp) { size_t done = 0, r; int ch, chans; gsm_signal *gbuff; priv_t *p = (priv_t *) ft->priv; chans = p->channels; while (done < samp) { while (p->samplePtr < p->sampleTop && done < samp) buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(*(p->samplePtr)++,); if (done>=samp) break; r = lsx_readbuf(ft, p->frames, p->channels * FRAMESIZE); if (r != p->channels * FRAMESIZE) break; p->samplePtr = p->samples; for (ch=0; ch<chans; ch++) { int i; gsm_signal *gsp; gbuff = p->sampleTop; if (gsm_decode(p->handle[ch], p->frames + ch*FRAMESIZE, gbuff) < 0) { lsx_fail_errno(ft,errno,"error during GSM decode"); return (0); } gsp = p->samples + ch; for (i=0; i<BLOCKSIZE; i++) { *gsp = *gbuff++; gsp += chans; } } } return done; } static int gsmflush(sox_format_t * ft) { int r, ch, chans; gsm_signal *gbuff; priv_t *p = (priv_t *) ft->priv; chans = p->channels; /* zero-fill samples as needed */ while (p->samplePtr < p->sampleTop) *(p->samplePtr)++ = 0; gbuff = p->sampleTop; for (ch=0; ch<chans; ch++) { int i; gsm_signal *gsp; gsp = p->samples + ch; for (i=0; i<BLOCKSIZE; i++) { gbuff[i] = *gsp; gsp += chans; } gsm_encode(p->handle[ch], gbuff, p->frames); r = lsx_writebuf(ft, p->frames, FRAMESIZE); if (r != FRAMESIZE) { lsx_fail_errno(ft,errno,"write error"); return(SOX_EOF); } } p->samplePtr = p->samples; return (SOX_SUCCESS); } static size_t sox_gsmwrite(sox_format_t * ft, const sox_sample_t *buf, size_t samp) { size_t done = 0; priv_t *p = (priv_t *) ft->priv; while (done < samp) { SOX_SAMPLE_LOCALS; while ((p->samplePtr < p->sampleTop) && (done < samp)) *(p->samplePtr)++ = SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips); if (p->samplePtr == p->sampleTop) { if(gsmflush(ft)) { return 0; } } } return done; } static int sox_gsmstopread(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; unsigned ch; for (ch=0; ch<p->channels; ch++) gsm_destroy(p->handle[ch]); free(p->samples); free(p->frames); return (SOX_SUCCESS); } static int sox_gsmstopwrite(sox_format_t * ft) { int rc; priv_t *p = (priv_t *) ft->priv; if (p->samplePtr > p->samples) { rc = gsmflush(ft); if (rc) return rc; } return sox_gsmstopread(ft); /* destroy handles and free buffers */ } LSX_FORMAT_HANDLER(gsm) { static char const * const names[] = {"gsm", NULL}; static sox_rate_t const write_rates[] = {8000, 0}; static unsigned const write_encodings[] = {SOX_ENCODING_GSM, 0, 0}; static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, "GSM 06.10 (full-rate) lossy speech compression", names, 0, sox_gsmstartread, sox_gsmread, sox_gsmstopread, sox_gsmstartwrite, sox_gsmwrite, sox_gsmstopwrite, NULL, write_encodings, write_rates, sizeof(priv_t) }; return &handler; }