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