revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / mp3_mpg123.c
blob7bfcd4430992bc68de79bdf48a2d0d523f9ddee9
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/mp3_mpg123.h"
28 #include <proto/exec.h>
29 #include <proto/dos.h>
30 #include <string.h>
31 #include <mpg123.h>
32 #include <stdio.h>
33 #include "endian.h"
34 #include "support.h"
36 #define NO_ERROR 0
37 #define ZERO MKBADDR(NULL)
38 #define MPG123_SEEK_SET SEEK_SET
39 #define MPG123_SEEK_CUR SEEK_CUR
40 #define MPG123_SEEK_END SEEK_END
42 static void MP3_close(MP3_STREAM *stream);
43 static LONG MP3_read(MP3_STREAM *stream, APTR buffer, ULONG offset, ULONG length);
45 ssize_t mpg123_r_read(void *handle, void *buffer, size_t length);
46 off_t mpg123_r_lseek(void *handle, off_t offset, int whence);
47 void mpg123_cleanup(void *handle);
49 MP3_STREAM *MP3_open(CONST_STRPTR filename) {
50 BPTR file = ZERO;
51 MP3_STREAM *stream = NULL;
52 LONG error = NO_ERROR;
54 file = Open(filename, MODE_OLDFILE);
55 if (!file) {
56 error = IoErr();
57 goto error;
60 stream = AllocVec(sizeof(*stream), MEMF_ANY|MEMF_CLEAR);
61 if (!stream) {
62 error = ERROR_NO_FREE_STORE;
63 Close(file);
64 goto error;
66 stream->close = MP3_close;
67 stream->read = MP3_read;
68 stream->file = file;
70 stream->mh = mpg123_new(NULL, NULL);
71 if (!stream->mh) {
72 error = ERROR_NO_FREE_STORE;
73 goto error;
76 if (mpg123_format_none(stream->mh) != MPG123_OK ||
77 mpg123_format(stream->mh, 44100, MPG123_STEREO,
78 MPG123_ENC_SIGNED_16) != MPG123_OK ||
79 mpg123_replace_reader_handle(stream->mh, mpg123_r_read,
80 mpg123_r_lseek, mpg123_cleanup) != MPG123_OK ||
81 mpg123_open_handle(stream->mh, stream) != MPG123_OK)
83 error = ERROR_OBJECT_WRONG_TYPE;
84 goto error;
87 stream->total_samples = mpg123_length(stream->mh);
88 if (stream->total_samples == MPG123_ERR) {
89 error = ERROR_OBJECT_WRONG_TYPE;
90 goto error;
92 stream->length = stream->total_samples << 2;
94 return stream;
96 error:
97 MP3_close(stream);
98 SetIoErr(error);
99 return NULL;
102 static void MP3_close(MP3_STREAM *stream) {
103 if (stream) {
104 mpg123_delete(stream->mh);
105 Close(stream->file);
106 FreeVec(stream);
110 static LONG MP3_read(MP3_STREAM *stream, APTR buffer, ULONG offset, ULONG length) {
111 LONG sample_offset = offset >> 2;
112 LONG samples_to_read = length >> 2;
113 LONG bytes_read;
114 LONG samples_read;
115 WORD *dst = buffer;
116 int res;
117 if (sample_offset >= stream->total_samples) {
118 memset(buffer, 0, length);
119 return length;
121 if (mpg123_tell(stream->mh) != sample_offset) {
122 LONG curr_sample_offset;
123 stream->eof = FALSE;
124 curr_sample_offset = mpg123_seek(stream->mh, sample_offset,
125 MPG123_SEEK_SET);
126 if (curr_sample_offset < 0) {
127 return 0;
128 } else if (curr_sample_offset < sample_offset) {
129 LONG seek_len, do_len;
130 seek_len = (sample_offset - curr_sample_offset) << 2;
131 do_len = length;
132 while (seek_len > 0) {
133 if (seek_len < length) do_len = seek_len;
134 res = mpg123_read(stream->mh, buffer, do_len, &bytes_read);
135 if (bytes_read > 0) {
136 seek_len -= bytes_read;
138 if (res == MPG123_DONE) {
139 stream->eof = TRUE;
140 break;
142 if (res != MPG123_OK) {
143 return 0;
146 } else if (curr_sample_offset > sample_offset) {
147 return 0;
150 while (samples_to_read) {
151 if (stream->eof) {
152 memset(dst, 0, samples_to_read << 2);
153 dst += (samples_to_read << 1);
154 break;
156 res = mpg123_read(stream->mh, (UBYTE *)dst, samples_to_read << 2, &bytes_read);
157 samples_read = bytes_read >> 2;
158 if (samples_read > 0) {
159 LONG sample;
160 for (sample = 0; sample < samples_read; sample++) {
161 wle16(dst, *dst); dst++;
162 wle16(dst, *dst); dst++;
164 samples_to_read -= samples_read;
166 if (res == MPG123_DONE) {
167 stream->eof = TRUE;
168 continue;
170 if (res != MPG123_OK && res != MPG123_NEW_FORMAT) {
171 break;
174 return (IPTR)dst - (IPTR)buffer;
177 ssize_t mpg123_r_read(void *handle, void *buffer, size_t length) {
178 MP3_STREAM *stream = handle;
179 BPTR file = stream->file;
180 return Read(file, buffer, length);
183 off_t mpg123_r_lseek(void *handle, off_t offset, int whence) {
184 MP3_STREAM *stream = handle;
185 BPTR file = stream->file;
186 LONG mode;
187 int64 res;
188 switch (whence) {
189 case MPG123_SEEK_SET:
190 mode = OFFSET_BEGINNING;
191 break;
192 case MPG123_SEEK_CUR:
193 mode = OFFSET_CURRENT;
194 break;
195 case MPG123_SEEK_END:
196 mode = OFFSET_END;
197 break;
198 default:
199 return (off_t)-1;
201 if (!ChangeFilePosition(file, offset, mode)) {
202 return (off_t)-1;
204 res = GetFilePosition(file);
205 if (res >= 0LL && res <= 0x7fffffffLL) {
206 return res;
207 } else {
208 return (off_t)-1;
212 void mpg123_cleanup(void *handle) {
213 /* do nothing */