1 /*
2 * Copyright 1993 Network Computing Devices, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name Network Computing Devices, Inc. not be
9 * used in advertising or publicity pertaining to distribution of this
10 * software without specific, written prior permission.
11 *
12 * THIS SOFTWARE IS PROVIDED 'AS-IS'. NETWORK COMPUTING DEVICES, INC.,
13 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
14 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15 * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK
16 * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
17 * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
18 * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
19 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * $NCDId: @(#)voc.c,v 1.15 1995/12/06 01:23:38 greg Exp $
23 */
24
25 #include "config.h"
26
27 #include <stdio.h>
28
29 #if defined(HAVE_STDLIB_H)
30 # include <stdlib.h>
31 #endif
32
33 #if defined(HAVE_MALLOC_H)
34 # include <malloc.h>
35 #endif
36
37
38 #include <audio/Aos.h>
39 #include <audio/voc.h>
40 #include <audio/fileutil.h>
41
42 #define Err() { VocCloseFile(vi); return NULL; }
43
44 #define ReadSize(_n) \
45 { \
46 _n = fgetc(vi->fp); \
47 _n += fgetc(vi->fp) << 8; \
48 _n += fgetc(vi->fp) << 16; \
49 }
50
51 #define WriteSize(_n) \
52 { \
53 fputc(_n, vi->fp); \
54 fputc((_n) >> 8, vi->fp); \
55 fputc((_n) >> 16, vi->fp); \
56 }
57
58 VocInfo *
VocOpenFileForReading(const char * name)59 VocOpenFileForReading(const char *name)
60 {
61 VocInfo *vi;
62 int c,
63 extended = AuFalse;
64 AuUint32 n;
65 char buf[VOC_ID_SIZE];
66
67 if (!(vi = (VocInfo *) malloc(sizeof(VocInfo))))
68 return NULL;
69
70 vi->comment = NULL;
71 vi->dataOffset = vi->writing = 0;
72 vi->tracks = 1;
73
74 if (!(vi->fp = fopen(name, AU_READ_BINARY)))
75 Err();
76
77 if (!fread(buf, VOC_ID_SIZE, 1, vi->fp) ||
78 strncmp(buf, VOC_ID, VOC_ID_SIZE) ||
79 FileReadS(vi->fp, NAS_BIG_ENDIAN) != VOC_DATA_OFFSET ||
80 FileReadS(vi->fp, NAS_BIG_ENDIAN) != VOC_VERSION ||
81 FileReadS(vi->fp, NAS_BIG_ENDIAN) != VOC_VERSION_CHK)
82 Err();
83
84 do
85 switch (c = fgetc(vi->fp))
86 {
87 case VOC_TERMINATOR:
88 break;
89 case VOC_DATA:
90 ReadSize(vi->dataSize);
91 vi->dataSize -= 2;
92
93 if (!extended)
94 {
95 vi->sampleRate = 1000000 / (256 - fgetc(vi->fp));
96 vi->compression = fgetc(vi->fp);
97 }
98 else
99 fseek(vi->fp, 2, 1);
100
101 vi->dataOffset = ftell(vi->fp);
102 fseek(vi->fp, vi->dataSize, 1);
103 break;
104 case VOC_TEXT:
105 ReadSize(n);
106 if (!(vi->comment = (char *) malloc(n)) ||
107 !fread(vi->comment, n, 1, vi->fp))
108 Err();
109 break;
110 case VOC_EXTENDED:
111 ReadSize(n);
112
113 if (n == 4)
114 {
115 extended = AuTrue;
116 n = fgetc(vi->fp);
117 n += fgetc(vi->fp) << 8;
118 vi->sampleRate = 256000000 / (65536 - n);
119 vi->compression = fgetc(vi->fp);
120 n = fgetc(vi->fp);
121
122 if (n == 0 || n == 1)
123 vi->tracks = n + 1;
124 else
125 Err(); /* an unknown mode */
126
127 vi->sampleRate /= vi->tracks;
128 }
129 else
130 Err(); /* ??? */
131 break;
132 case VOC_CONTINUE:
133 case VOC_SILENCE:
134 case VOC_MARKER:
135 case VOC_REPEAT:
136 case VOC_REPEAT_END:
137 ReadSize(n);
138 fseek(vi->fp, n, 1);
139 break;
140 default:
141 Err();
142 }
143 while (c != VOC_TERMINATOR);
144
145 if (!vi->dataOffset)
146 Err();
147
148 if (!vi->comment)
149 vi->comment = FileCommentFromFilename(name);
150
151 VocRewindFile(vi);
152 return vi;
153 }
154
155 VocInfo *
VocOpenFileForWriting(const char * name,VocInfo * vi)156 VocOpenFileForWriting(
157 const char *name,
158 VocInfo *vi
159 )
160 {
161 int n;
162
163 vi->writing = vi->dataSize = 0;
164
165 if (!(vi->fp = fopen(name, AU_WRITE_BINARY)) ||
166 !fwrite(VOC_ID, VOC_ID_SIZE, 1, vi->fp) ||
167 !FileWriteS(VOC_DATA_OFFSET, vi->fp, NAS_BIG_ENDIAN) ||
168 !FileWriteS(VOC_VERSION, vi->fp, NAS_BIG_ENDIAN) ||
169 !FileWriteS(VOC_VERSION_CHK, vi->fp, NAS_BIG_ENDIAN))
170 Err();
171
172 if ((n = strlen(vi->comment)))
173 {
174 fputc(VOC_TEXT, vi->fp);
175 n++;
176 WriteSize(n);
177
178 if (!fwrite(vi->comment, n, 1, vi->fp))
179 Err();
180 }
181
182 if (vi->tracks == 2)
183 {
184 fputc(VOC_EXTENDED, vi->fp);
185 WriteSize(4);
186 n = 65536 - (256000000 / (vi->sampleRate * 2));
187 fputc(n, vi->fp);
188 fputc(n >> 8, vi->fp);
189 fputc(0, vi->fp);
190 fputc(1, vi->fp);
191 }
192
193 fputc(VOC_DATA, vi->fp);
194 vi->dataOffset = ftell(vi->fp);
195 WriteSize(0);
196 fputc(256 - (1000000 / vi->sampleRate), vi->fp);
197 fputc(0, vi->fp);
198
199 vi->writing = 1;
200 return vi;
201 }
202
203 int
VocCloseFile(VocInfo * vi)204 VocCloseFile(VocInfo *vi)
205 {
206 int status = 0;
207
208 if (vi->fp)
209 {
210 if (vi->writing && vi->dataOffset)
211 {
212 fputc(VOC_TERMINATOR, vi->fp);
213 fseek(vi->fp, vi->dataOffset, 0);
214 vi->dataSize += 2;
215 WriteSize(vi->dataSize);
216 }
217
218 status = fclose(vi->fp);
219 }
220
221 if (vi->comment)
222 free(vi->comment);
223
224 free(vi);
225 return status;
226 }
227
228 int
VocReadFile(char * p,int n,VocInfo * vi)229 VocReadFile(
230 char *p,
231 int n,
232 VocInfo *vi
233 )
234 {
235 return fread(p, 1, n, vi->fp);
236 }
237
238 int
VocWriteFile(char * p,int n,VocInfo * vi)239 VocWriteFile(
240 char *p,
241 int n,
242 VocInfo *vi
243 )
244 {
245 int num;
246
247 num = fwrite(p, 1, n, vi->fp);
248 vi->dataSize += num;
249 return num;
250 }
251
252 int
VocRewindFile(VocInfo * vi)253 VocRewindFile(VocInfo *vi)
254 {
255 return vi->writing ? -1 : fseek(vi->fp, vi->dataOffset + 3, 0);
256 }
257
258 int
VocSeekFile(int n,VocInfo * vi)259 VocSeekFile(
260 int n,
261 VocInfo *vi
262 )
263 {
264 return vi->writing ? -1 : fseek(vi->fp, vi->dataOffset + 3 + n, 0);
265 }
266
267 int
VocTellFile(VocInfo * vi)268 VocTellFile(VocInfo *vi)
269 {
270 return vi->writing ? -1 : ftell(vi->fp) - vi->dataOffset - 3;
271 }
272
273 int
VocFlushFile(VocInfo * vi)274 VocFlushFile(VocInfo *vi)
275 {
276 return fflush(vi->fp);
277 }
278