revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / mp3_mpega.c
blobca791445c656bf9686aa967bdfed239ab57ac66c
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_mpega.h"
28 #include <proto/exec.h>
29 #include <proto/dos.h>
30 #include <proto/mpega.h>
31 #include <string.h>
32 #include "endian.h"
33 #include "support.h"
35 #define NO_ERROR 0
37 static const MPEGA_CTRL mpa_ctrl = {
38 NULL,
39 { FALSE, { 1, 2, 44100 }, { 1, 2, 44100 } },
40 { FALSE, { 1, 2, 44100 }, { 1, 2, 44100 } },
45 static void MP3_close(MP3_STREAM *stream);
46 static LONG MP3_read(MP3_STREAM *stream, APTR buffer, ULONG offset, ULONG length);
48 MP3_STREAM *MP3_open(CONST_STRPTR filename) {
49 MP3_STREAM *stream = NULL;
50 LONG error = NO_ERROR;
52 stream = AllocVec(sizeof(*stream), MEMF_CLEAR);
53 if (!stream) {
54 error = ERROR_NO_FREE_STORE;
55 goto error;
57 stream->close = MP3_close;
58 stream->read = MP3_read;
60 stream->stream = MPEGA_open((STRPTR)filename, (MPEGA_CTRL *)&mpa_ctrl);
61 if (!stream->stream) {
62 error = ERROR_OBJECT_NOT_FOUND;
63 goto error;
66 if (stream->stream->dec_frequency != 44100 ||
67 stream->stream->dec_channels != 2)
69 error = ERROR_OBJECT_WRONG_TYPE;
70 goto error;
73 stream->pcm[0] = AllocVec(MPEGA_PCM_SIZE * sizeof(WORD), MEMF_ANY);
74 stream->pcm[1] = AllocVec(MPEGA_PCM_SIZE * sizeof(WORD), MEMF_ANY);
75 if (!stream->pcm[0] || !stream->pcm[1]) {
76 error = ERROR_NO_FREE_STORE;
77 goto error;
80 stream->length = ((UQUAD)stream->stream->ms_duration * (44100ULL * 4ULL)) / 1000ULL;
82 return stream;
84 error:
85 MP3_close(stream);
86 SetIoErr(error);
87 return NULL;
90 static void MP3_close(MP3_STREAM *stream) {
91 if (stream) {
92 if (stream->stream) MPEGA_close(stream->stream);
93 FreeVec(stream->pcm[0]);
94 FreeVec(stream->pcm[1]);
95 FreeVec(stream);
99 static LONG MP3_read(MP3_STREAM *stream, APTR buffer, ULONG offset, ULONG length) {
100 LONG sample_offset = offset >> 2;
101 LONG samples_to_read = length >> 2;
102 LONG samples_to_skip;
103 LONG samples_read;
104 LONG sample;
105 WORD *dst = buffer;
106 if (sample_offset >= stream->first_sample_in_pcm &&
107 sample_offset < (stream->first_sample_in_pcm + stream->samples_in_pcm))
109 samples_to_skip = sample_offset - stream->first_sample_in_pcm;
110 samples_read = stream->samples_in_pcm;
111 sample_offset = stream->first_sample_in_pcm + samples_read;
112 if (samples_read > samples_to_skip) {
113 if (samples_read > (samples_to_skip + samples_to_read)) {
114 samples_read = samples_to_skip + samples_to_read;
116 for (sample = samples_to_skip; sample < samples_read; sample++) {
117 wle16(dst, stream->pcm[0][sample]); dst++;
118 wle16(dst, stream->pcm[1][sample]); dst++;
120 samples_read -= samples_to_skip;
121 samples_to_skip = 0;
122 samples_to_read -= samples_read;
123 } else {
124 samples_to_skip -= samples_read;
127 if (stream->sample_offset != -1 && sample_offset >= stream->sample_offset) {
128 samples_to_skip = sample_offset - stream->sample_offset;
129 sample_offset = stream->sample_offset;
130 } else {
131 stream->sample_offset = -1;
132 stream->eof = FALSE;
133 if (MPEGA_seek(stream->stream, 0) < 0) {
134 return (LONG)dst - (LONG)buffer;
136 samples_to_skip = sample_offset;
137 stream->sample_offset = sample_offset = 0;
139 while (samples_to_read) {
140 if (stream->eof) {
141 memset(dst, 0, samples_to_read << 2);
142 dst += (samples_to_read << 1);
143 break;
145 stream->first_sample_in_pcm = 0;
146 stream->samples_in_pcm = 0;
147 samples_read = MPEGA_decode_frame(stream->stream, stream->pcm);
148 if (samples_read < 0) {
149 if (samples_read == MPEGA_ERR_EOF) {
150 stream->eof = TRUE;
151 continue;
153 stream->sample_offset = -1;
154 break;
156 stream->first_sample_in_pcm = sample_offset;
157 stream->samples_in_pcm = samples_read;
158 sample_offset += samples_read;
159 stream->sample_offset = sample_offset;
160 if (samples_read > samples_to_skip) {
161 if (samples_read > (samples_to_skip + samples_to_read)) {
162 samples_read = samples_to_skip + samples_to_read;
164 for (sample = samples_to_skip; sample < samples_read; sample++) {
165 wle16(dst, stream->pcm[0][sample]); dst++;
166 wle16(dst, stream->pcm[1][sample]); dst++;
168 samples_read -= samples_to_skip;
169 samples_to_skip = 0;
170 samples_to_read -= samples_read;
171 } else {
172 samples_to_skip -= samples_read;
175 return (LONG)dst - (LONG)buffer;