revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / wave.c
blob3da3bf4340cb0a4170ba07bb718efdc108d58c96
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "audio/wave.h"
28 #include <libraries/iffparse.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <string.h>
32 #include "endian.h"
33 #include "support.h"
35 #define NO_ERROR 0
36 #define ZERO MKBADDR(NULL)
38 #pragma pack(1)
40 typedef struct {
41 ULONG id;
42 ULONG size;
43 ULONG type;
44 } riff_header_t;
46 typedef struct {
47 ULONG id;
48 ULONG size;
49 } riff_chunk_t;
51 #define ID_RIFF MAKE_ID('R','I','F','F')
52 #define ID_WAVE MAKE_ID('W','A','V','E')
53 #define ID_fmt MAKE_ID('f','m','t',' ')
54 #define ID_data MAKE_ID('d','a','t','a')
56 typedef struct {
57 UWORD format;
58 UWORD channels;
59 ULONG frequency;
60 ULONG bytespersec;
61 UWORD blockalign;
62 UWORD bitspersample;
63 UWORD extrasize;
64 } wave_fmt_t;
66 #define WAVE_FORMAT_PCM 0x0001
68 #pragma pack()
70 BOOL WAVE_header(CONST_APTR p) {
71 const riff_header_t *header = p;
72 return rbe32(&header->id) == ID_RIFF && rbe32(&header->type) == ID_WAVE;
75 static void WAVE_close(WAVE_STREAM *stream);
76 static LONG WAVE_read(WAVE_STREAM *stream, APTR buffer, ULONG offset, ULONG length);
78 WAVE_STREAM *WAVE_open(CONST_STRPTR filename) {
79 BPTR file = ZERO;
80 WAVE_STREAM *stream = NULL;
81 riff_header_t header;
82 riff_chunk_t chunk;
83 wave_fmt_t fmt;
84 LONG done = FALSE;
86 SetIoErr(NO_ERROR);
88 file = Open(filename, MODE_OLDFILE);
89 if (!file) {
90 goto error;
93 stream = AllocVec(sizeof(*stream), MEMF_CLEAR);
94 if (!stream) {
95 SetIoErr(ERROR_NO_FREE_STORE);
96 Close(file);
97 goto error;
99 stream->close = WAVE_close;
100 stream->read = WAVE_read;
101 stream->file = file;
103 if (FRead(file, &header, 1, sizeof(header)) != sizeof(header)) {
104 goto error;
106 if (rbe32(&header.id) != ID_RIFF || rbe32(&header.type) != ID_WAVE) {
107 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
108 goto error;
111 while (!done) {
112 if (FRead(file, &chunk, 1, sizeof(chunk)) != sizeof(chunk)) {
113 goto error;
115 wbe32(&chunk.id, chunk.id);
116 wle32(&chunk.size, chunk.size);
117 switch (chunk.id) {
118 case ID_fmt:
119 if (chunk.size != 16 && chunk.size != 18) {
120 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
121 goto error;
123 if (FRead(file, &fmt, 1, chunk.size) != chunk.size) {
124 goto error;
126 if (rle16(&fmt.format) != WAVE_FORMAT_PCM ||
127 rle16(&fmt.channels) != 2 ||
128 rle32(&fmt.frequency) != 44100 ||
129 rle16(&fmt.bitspersample) != 16)
131 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
132 goto error;
134 break;
135 case ID_data:
136 stream->offset = GetFilePosition(file);
137 stream->length = chunk.size;
138 if ((LONG)stream->offset == -1 && IoErr()) {
139 goto error;
141 done = TRUE;
142 break;
143 default:
144 if (!ChangeFilePosition(file, (chunk.size+1)&~1, OFFSET_CURRENT)) {
145 goto error;
147 break;
151 return stream;
153 error:
154 WAVE_close(stream);
155 return NULL;
158 static void WAVE_close(WAVE_STREAM *stream) {
159 if (stream) {
160 Close(stream->file);
161 FreeVec(stream);
165 static LONG WAVE_read(WAVE_STREAM *stream, APTR buffer, ULONG offset, ULONG length) {
166 BPTR file = stream->file;
167 LONG read_length;
168 LONG bytes_read;
169 if (offset >= stream->length) {
170 memset(buffer, 0, length);
171 return length;
173 if (!ChangeFilePosition(file, stream->offset + offset, OFFSET_BEGINNING)) {
174 return 0;
176 if ((offset + length) > stream->length) {
177 read_length = stream->length;
178 } else {
179 read_length = length;
181 bytes_read = FRead(file, buffer, 1, read_length);
182 if (bytes_read < 0) {
183 return 0;
185 memset((uint8 *)buffer + bytes_read, 0, length - bytes_read);
186 return length;