Updating built in Io code to use += instead of x = x + y
[io/quag.git] / addons / PortAudio / source / new / IoMP3Decoder.c
blob8fa1cb61d75eb7b211c367f35efbd0977f0302e0
1 /* copyright: Steve Dekorte, 2002
2 * All rights reserved. See _BSDLicense.txt.
4 * user clones MP3Decoder and implements input and output methods
5 * and then calls run.
6 * input should return a buffer, output will have a buffer argument.
7 */
9 #include "IoMP3Decoder.h"
10 #include "List.h"
11 #include "IoState.h"
12 #include "IoNumber.h"
13 #include "IoSeq.h"
14 #include <limits.h>
16 #define DATA(self) ((IoMP3DecoderData *)IoObject_dataPointer(self))
18 IoTag *IoMP3Decoder_newTag(void *state)
20 IoTag *tag = IoTag_newWithName_("MP3Decoder");
21 IoTag_state_(tag, state);
22 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoMP3Decoder_rawClone);
23 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoMP3Decoder_mark);
24 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoMP3Decoder_free);
25 return tag;
28 IoMP3Decoder *IoMP3Decoder_proto(void *state)
30 IoObject *self = IoObject_new(state);
31 IoObject_tag_(self, IoMP3Decoder_newTag(state));
33 IoObject_setDataPointer_(self, calloc(1, sizeof(IoMP3DecoderData)));
35 //DATA(self)->outSound = 0x0;
36 DATA(self)->willProcessMessage = IoMessage_newWithName_label_(state, IOSYMBOL("willProcess"), IOSYMBOL("[MP3Decoder]"));
37 DATA(self)->didProcessMessage = IoMessage_newWithName_label_(state, IOSYMBOL("didProcess"), IOSYMBOL("[MP3Decoder]"));
38 DATA(self)->inputBuffer = IoSeq_new(state);
39 DATA(self)->outputBuffer = IoSeq_new(state);
40 DATA(self)->tmpInputBa = UArray_new();
42 IoState_registerProtoWithFunc_(state, self, IoMP3Decoder_proto);
45 IoMethodTable methodTable[] = {
46 {"start", IoMP3Decoder_start},
47 {"stop", IoMP3Decoder_stop},
48 {"inputBuffer", IoMP3Decoder_inputBuffer},
49 {"outputBuffer", IoMP3Decoder_outputBuffer},
51 {NULL, NULL},
53 IoObject_addMethodTable_(self, methodTable);
55 return self;
58 IoMP3Decoder *IoMP3Decoder_rawClone(IoMP3Decoder *proto)
60 IoObject *self = IoObject_rawClonePrimitive(proto);
61 IoObject_setDataPointer_(self, calloc(1, sizeof(IoMP3DecoderData)));
63 DATA(self)->willProcessMessage = DATA(proto)->willProcessMessage;
64 DATA(self)->didProcessMessage = DATA(proto)->didProcessMessage;
65 DATA(self)->inputBuffer = IOCLONE(DATA(proto)->inputBuffer);
66 DATA(self)->outputBuffer = IOCLONE(DATA(proto)->outputBuffer);
67 DATA(self)->tmpInputBa = UArray_new();
69 IoState_addValue_(IOSTATE, self);
70 return self;
73 IoMP3Decoder *IoMP3Decoder_new(void *state)
75 IoObject *proto = IoState_protoWithInitFunction_(state, IoMP3Decoder_proto);
76 return IOCLONE(proto);
79 /* ----------------------------------------------------------- */
81 void IoMP3Decoder_free(IoMP3Decoder *self)
83 UArray_free(DATA(self)->tmpInputBa);
84 free(IoObject_dataPointer(self));
87 void IoMP3Decoder_mark(IoMP3Decoder *self)
89 IoObject_shouldMark(DATA(self)->inputBuffer);
90 IoObject_shouldMark(DATA(self)->outputBuffer);
91 IoObject_shouldMark(DATA(self)->willProcessMessage);
92 IoObject_shouldMark(DATA(self)->didProcessMessage);
95 /* ----------------------------------------------------------- */
97 /* (re)fill the stream buffer which is to be decoded. */
99 static enum mad_flow IoMP3Decoder_inputCallback(void *data, struct mad_stream *stream)
101 IoMP3Decoder *self = data;
102 struct mad_decoder *decoder = &(DATA(self)->decoder);
104 IoMessage_locals_performOn_(DATA(self)->willProcessMessage, self, self);
106 if (DATA(self)->isRunning)
108 UArray *ba = IoSeq_rawUArray(DATA(self)->inputBuffer);
110 UArray_removeRange(ba, 0, DATA(self)->lastInputPos);
113 size_t size = UArray_size(ba);
114 UArray_setSize_(ba, size + MAD_BUFFER_GUARD);
115 memset(UArray_bytes(ba) + size, 0x0, MAD_BUFFER_GUARD);
116 UArray_setSize_(ba, size);
119 if (UArray_size(ba) == 0)
121 return MAD_FLOW_CONTINUE;
124 DATA(self)->lastInputPos = UArray_size(ba);
126 mad_stream_buffer(stream, UArray_bytes(ba), UArray_size(ba));
129 return DATA(self)->isRunning ? MAD_FLOW_CONTINUE : MAD_FLOW_STOP;
132 // This is the output callback function. It is called after each frame of
133 // MPEG audio data has been completely decoded. The purpose of this callback
134 // is to output (or play) the decoded PCM audio.
136 static enum mad_flow IoMP3Decoder_outputCallback(void *data,
137 struct mad_header const *header,
138 struct mad_pcm *pcm)
140 IoMP3Decoder *self = data;
141 UArray *ba = IoSeq_rawUArray(DATA(self)->outputBuffer);
142 unsigned int oldSize = UArray_size(ba);
143 unsigned int newSize = oldSize + (pcm->length * 2 * sizeof(float));
145 UArray_setSize_(ba, newSize);
147 if (!DATA(self)->isRunning)
149 return MAD_FLOW_STOP;
152 // MAD data is in 4 byte signed ints
153 // and on separated (not interleaved channels)
154 // so we interleave them here
157 float *out = (float *)(UArray_bytes(ba) + oldSize);
158 unsigned int nsamples = pcm->length;
160 mad_fixed_t const *left = pcm->samples[0];
161 mad_fixed_t const *right = pcm->samples[1];
163 if (pcm->channels == 2)
165 // this would be much faster as a vector op
166 while (nsamples --)
168 *out = ((float)(*left)) / INT_MAX;
169 out ++;
170 *out = ((float)(*right)) / INT_MAX;
171 out ++;
172 left ++;
173 right ++;
176 else
178 while (nsamples --)
180 float f = ((float)(*left)) / INT_MAX;
181 *out = f;
182 out ++;
183 *out = f;
184 out ++;
185 left ++;
190 IoMessage_locals_performOn_(DATA(self)->didProcessMessage, self, self);
192 return DATA(self)->isRunning ? MAD_FLOW_CONTINUE : MAD_FLOW_STOP;
196 * This is the error callback function. It is called whenever a decoding
197 * error occurs. The error is indicated by stream->error; the list of
198 * possible MAD_ERROR_* errors can be found in the mad.h (or
199 * libmad/stream.h) header file.
202 static enum mad_flow IoMP3Decoder_errorCallback(void *data,
203 struct mad_stream *stream,
204 struct mad_frame *frame)
206 //IoMP3Decoder *self = data;
208 fprintf(stderr, "lbmad error %i (%s)\n", stream->error, mad_stream_errorstr(stream));
211 IoState_error_(IOSTATE, 0x0, "MP3Decoder %s", mad_stream_errorstr(stream));
213 DATA(self)->isRunning = 0;
214 return MAD_FLOW_BREAK;
216 return MAD_FLOW_CONTINUE;
219 IoObject *IoMP3Decoder_start(IoMP3Decoder *self, IoObject *locals, IoMessage *m)
221 int result;
222 DATA(self)->isRunning = 1;
223 DATA(self)->lastInputPos = 0;
225 mad_decoder_init(&(DATA(self)->decoder), (void *)self,
226 IoMP3Decoder_inputCallback,
227 0 /* header */,
228 0 /* filter */,
229 IoMP3Decoder_outputCallback,
230 IoMP3Decoder_errorCallback,
231 0 /* message */);
233 /* start decoding */
235 result = mad_decoder_run(&(DATA(self)->decoder), MAD_DECODER_MODE_SYNC);
237 mad_decoder_finish(&(DATA(self)->decoder));
239 /* release the decoder */
241 return IONUMBER(result);
244 IoObject *IoMP3Decoder_inputBuffer(IoMP3Decoder *self, IoObject *locals, IoMessage *m)
246 return DATA(self)->inputBuffer;
249 IoObject *IoMP3Decoder_outputBuffer(IoMP3Decoder *self, IoObject *locals, IoMessage *m)
251 return DATA(self)->outputBuffer;
254 IoObject *IoMP3Decoder_stop(IoMP3Decoder *self, IoObject *locals, IoMessage *m)
256 DATA(self)->isRunning = 0;
257 DATA(self)->lastInputPos = 0;
258 return self;
261 IoObject *IoMP3Decoder_isRunning(IoMP3Decoder *self, IoObject *locals, IoMessage *m)
263 return IOBOOL(self, DATA(self)->isRunning);