revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / vorbis.c
blob583455acebc5bdb5a881ebd478b927511708c7bd
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/vorbis.h"
28 #include <proto/exec.h>
29 #include <proto/dos.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include "endian.h"
33 #include "support.h"
35 #define NO_ERROR 0
36 #define ZERO MKBADDR(NULL)
37 #define OGG_SEEK_SET SEEK_SET
38 #define OGG_SEEK_CUR SEEK_CUR
39 #define OGG_SEEK_END SEEK_END
41 #define ID_OggS MAKE_ID('O','g','g','S')
43 BOOL VORBIS_header(CONST_APTR p) {
44 return rbe32(p) == ID_OggS;
47 static void VORBIS_close(VORBIS_STREAM *stream);
48 static LONG VORBIS_read(VORBIS_STREAM *stream, APTR buffer, ULONG offset, ULONG length);
50 static size_t ogg_read (APTR buffer, size_t size, size_t nitems, APTR file);
51 static int ogg_seek (APTR file, ogg_int64_t offset, int mode);
52 static long ogg_tell (APTR file);
54 static const ov_callbacks callbacks = {
55 ogg_read,
56 ogg_seek,
57 NULL,
58 ogg_tell
61 VORBIS_STREAM *VORBIS_open(CONST_STRPTR filename) {
62 BPTR file = ZERO;
63 VORBIS_STREAM *stream = NULL;
64 vorbis_info *vi;
65 LONG error = NO_ERROR;
67 file = Open(filename, MODE_OLDFILE);
68 if (!file) {
69 error = IoErr();
70 goto error;
73 stream = AllocVec(sizeof(*stream), MEMF_CLEAR);
74 if (!stream) {
75 error = ERROR_NO_FREE_STORE;
76 Close(file);
77 goto error;
79 stream->close = VORBIS_close;
80 stream->read = VORBIS_read;
81 stream->file = file;
83 stream->vf = AllocVec(sizeof(OggVorbis_File), MEMF_CLEAR);
84 if (!stream->vf) {
85 error = ERROR_NO_FREE_STORE;
86 goto error;
89 if (ov_open_callbacks(stream, stream->vf, NULL, 0, callbacks) < 0) {
90 error = ERROR_OBJECT_WRONG_TYPE;
91 goto error;
94 stream->bs = -1;
96 vi = ov_info(stream->vf, stream->bs);
97 if (vi->channels != 2 || vi->rate != 44100) {
98 error = ERROR_OBJECT_WRONG_TYPE;
99 goto error;
102 stream->total_samples = ov_pcm_total(stream->vf, stream->bs);
103 stream->length = stream->total_samples << 2;
105 return stream;
107 error:
108 VORBIS_close(stream);
109 SetIoErr(error);
110 return NULL;
113 static void VORBIS_close(VORBIS_STREAM *stream) {
114 if (stream) {
115 if (stream->vf) {
116 ov_clear(stream->vf);
117 FreeVec(stream->vf);
119 Close(stream->file);
120 FreeVec(stream);
124 static LONG VORBIS_read(VORBIS_STREAM *stream, APTR buffer, ULONG offset, ULONG length) {
125 LONG sample_offset = offset >> 2;
126 LONG bytes_to_read = length;
127 LONG bytes_read;
128 char *dst = buffer;
129 if (sample_offset >= stream->total_samples) {
130 memset(buffer, 0, length);
131 return length;
133 if (ov_pcm_tell(stream->vf) != sample_offset) {
134 stream->eof = FALSE;
135 if (ov_pcm_seek(stream->vf, sample_offset) < 0) {
136 return 0;
139 while (bytes_to_read > 0) {
140 if (stream->eof) {
141 memset(dst, 0, bytes_to_read);
142 dst += bytes_to_read;
143 break;
145 bytes_read = ov_read(stream->vf, dst, bytes_to_read, 0, 2, 1, &stream->bs);
146 if (bytes_read < 0) {
147 break;
149 if (bytes_read == 0) {
150 stream->eof = TRUE;
151 } else {
152 dst += bytes_read;
153 bytes_to_read -= bytes_read;
156 return (LONG)dst - (LONG)buffer;
159 static size_t ogg_read (APTR buffer, size_t size, size_t nitems, APTR handle) {
160 VORBIS_STREAM *stream = handle;
161 size_t items_read;
162 items_read = FRead(stream->file, buffer, size, nitems);
163 return items_read == -1 ? 0 : items_read;
166 static int ogg_seek (APTR handle, ogg_int64_t offset, int mode) {
167 VORBIS_STREAM *stream = handle;
168 switch (mode) {
169 case OGG_SEEK_SET:
170 mode = OFFSET_BEGINNING;
171 break;
172 case OGG_SEEK_CUR:
173 mode = OFFSET_CURRENT;
174 break;
175 case OGG_SEEK_END:
176 mode = OFFSET_END;
177 break;
178 default:
179 return -1;
181 return !ChangeFilePosition(stream->file, offset, mode) ? -1 : 0;
184 static long ogg_tell (APTR handle) {
185 VORBIS_STREAM *stream = handle;
186 return GetFilePosition(stream->file);