1 /* libSoX text format file.  Tom Littlejohn, March 93.
2  *
3  * Reads/writes sound files as text.
4  *
5  * Copyright 1998-2006 Chris Bagwell and SoX Contributors
6  * This source code is freely redistributable and may be used for
7  * any purpose.  This copyright notice must be maintained.
8  * Lance Norskog And Sundry Contributors are not responsible for
9  * the consequences of using this software.
10  */
11 
12 #include "sox_i.h"
13 #include <string.h>
14 
15 #define LINEWIDTH (size_t)256
16 
17 /* Private data for dat file */
18 typedef struct {
19     double timevalue, deltat;
20     int buffered;
21     char prevline[LINEWIDTH];
22 } priv_t;
23 
sox_datstartread(sox_format_t * ft)24 static int sox_datstartread(sox_format_t * ft)
25 {
26     char inpstr[LINEWIDTH];
27     long rate;
28     int chan;
29     int status;
30     char sc;
31 
32     /* Read lines until EOF or first non-comment line */
33     while ((status = lsx_reads(ft, inpstr, LINEWIDTH-1)) != SOX_EOF) {
34       inpstr[LINEWIDTH-1] = 0;
35       if ((sscanf(inpstr," %c", &sc) != 0) && (sc != ';')) break;
36       if (sscanf(inpstr," ; Sample Rate %ld", &rate)) {
37         ft->signal.rate=rate;
38       } else if (sscanf(inpstr," ; Channels %d", &chan)) {
39         ft->signal.channels=chan;
40       }
41     }
42     /* Hold a copy of the last line we read (first non-comment) */
43     if (status != SOX_EOF) {
44       strncpy(((priv_t *)ft->priv)->prevline, inpstr, (size_t)LINEWIDTH);
45       ((priv_t *)ft->priv)->buffered = 1;
46     } else {
47       ((priv_t *)ft->priv)->buffered = 0;
48     }
49 
50     /* Default channels to 1 if not found */
51     if (ft->signal.channels == 0)
52        ft->signal.channels = 1;
53 
54     ft->encoding.encoding = SOX_ENCODING_FLOAT_TEXT;
55 
56     return (SOX_SUCCESS);
57 }
58 
sox_datstartwrite(sox_format_t * ft)59 static int sox_datstartwrite(sox_format_t * ft)
60 {
61     priv_t * dat = (priv_t *) ft->priv;
62     char s[LINEWIDTH];
63 
64     dat->timevalue = 0.0;
65     dat->deltat = 1.0 / (double)ft->signal.rate;
66     /* Write format comments to start of file */
67     sprintf(s,"; Sample Rate %ld\015\n", (long)ft->signal.rate);
68     lsx_writes(ft, s);
69     sprintf(s,"; Channels %d\015\n", (int)ft->signal.channels);
70     lsx_writes(ft, s);
71 
72     return (SOX_SUCCESS);
73 }
74 
sox_datread(sox_format_t * ft,sox_sample_t * buf,size_t nsamp)75 static size_t sox_datread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp)
76 {
77     char inpstr[LINEWIDTH];
78     int  inpPtr = 0;
79     int  inpPtrInc = 0;
80     double sampval = 0.0;
81     int retc = 0;
82     char sc = 0;
83     size_t done = 0;
84     size_t i=0;
85 
86     /* Always read a complete set of channels */
87     nsamp -= (nsamp % ft->signal.channels);
88 
89     while (done < nsamp) {
90 
91       /* Read a line or grab the buffered first line */
92       if (((priv_t *)ft->priv)->buffered) {
93         strncpy(inpstr, ((priv_t *)ft->priv)->prevline, (size_t)LINEWIDTH);
94         inpstr[LINEWIDTH-1] = 0;
95         ((priv_t *)ft->priv)->buffered=0;
96       } else {
97         lsx_reads(ft, inpstr, LINEWIDTH-1);
98         inpstr[LINEWIDTH-1] = 0;
99         if (lsx_eof(ft)) return (done);
100       }
101 
102       /* Skip over comments - ie. 0 or more whitespace, then ';' */
103       if ((sscanf(inpstr," %c", &sc) != 0) && (sc==';')) continue;
104 
105       /* Read a complete set of channels */
106       sscanf(inpstr," %*s%n", &inpPtr);
107       for (i=0; i<ft->signal.channels; i++) {
108         SOX_SAMPLE_LOCALS;
109         retc = sscanf(&inpstr[inpPtr]," %lg%n", &sampval, &inpPtrInc);
110         inpPtr += inpPtrInc;
111         if (retc != 1) {
112           lsx_fail_errno(ft,SOX_EOF,"Unable to read sample.");
113           return 0;
114         }
115         *buf++ = SOX_FLOAT_64BIT_TO_SAMPLE(sampval, ft->clips);
116         done++;
117       }
118     }
119 
120     return (done);
121 }
122 
sox_datwrite(sox_format_t * ft,const sox_sample_t * buf,size_t nsamp)123 static size_t sox_datwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp)
124 {
125     priv_t * dat = (priv_t *) ft->priv;
126     size_t done = 0;
127     double sampval=0.0;
128     char s[LINEWIDTH];
129     size_t i=0;
130 
131     /* Always write a complete set of channels */
132     nsamp -= (nsamp % ft->signal.channels);
133 
134     /* Write time, then sample values, then CRLF newline */
135     while(done < nsamp) {
136       sprintf(s," %15.8g ",dat->timevalue);
137       lsx_writes(ft, s);
138       for (i=0; i<ft->signal.channels; i++) {
139         sampval = SOX_SAMPLE_TO_FLOAT_64BIT(*buf++, ft->clips);
140         sprintf(s," %15.11g", sampval);
141         lsx_writes(ft, s);
142         done++;
143       }
144       sprintf(s," \r\n");
145       lsx_writes(ft, s);
146       dat->timevalue += dat->deltat;
147     }
148     return done;
149 }
150 
LSX_FORMAT_HANDLER(dat)151 LSX_FORMAT_HANDLER(dat)
152 {
153   static char const * const names[] = {"dat", NULL};
154   static unsigned const write_encodings[] = {SOX_ENCODING_FLOAT_TEXT, 0, 0};
155   static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
156     "Textual representation of the sampled audio", names, 0,
157     sox_datstartread, sox_datread, NULL,
158     sox_datstartwrite, sox_datwrite, NULL,
159     NULL, write_encodings, NULL, sizeof(priv_t)
160   };
161   return &handler;
162 }
163