1 /*******************************************************************************
2 * Goggles Audio Player Library *
3 ********************************************************************************
4 * Copyright (C) 2010-2021 by Sander Jansen. All Rights Reserved *
5 * --- *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see http://www.gnu.org/licenses. *
18 ********************************************************************************/
19 #include "ap_defs.h"
20 #include "ap_event_private.h"
21 #include "ap_packet.h"
22 #include "ap_input_plugin.h"
23 #include "ap_reader_plugin.h"
24
25
26 namespace ap {
27
28
29 #define DEFINE_CHUNK(b1,b2,b3,b4) ((b4<<24) | (b3<<16) | (b2<<8) | (b1))
30
31
32 class AIFFReader : public ReaderPlugin {
33 protected:
34 FXlong input_start;
35 protected:
36 ReadStatus parse();
37 public:
38 enum Chunk {
39 FORM = DEFINE_CHUNK('F','O','R','M'),
40 AIFF = DEFINE_CHUNK('A','I','F','F'),
41 COMM = DEFINE_CHUNK('C','O','M','M'),
42 SSND = DEFINE_CHUNK('S','S','N','D'),
43 };
44
45 public:
46 AIFFReader(InputContext*);
47 FXbool init(InputPlugin*) override;
48 ReadStatus process(Packet*) override;
49
format() const50 FXuchar format() const override { return Format::AIFF; };
51
52 FXbool can_seek() const override;
53 FXbool seek(FXlong) override;
54 virtual ~AIFFReader();
55 };
56
57
AIFFReader(InputContext * ctx)58 AIFFReader::AIFFReader(InputContext * ctx) : ReaderPlugin(ctx), input_start(0) {
59 }
60
~AIFFReader()61 AIFFReader::~AIFFReader(){
62 }
63
init(InputPlugin * plugin)64 FXbool AIFFReader::init(InputPlugin*plugin) {
65 ReaderPlugin::init(plugin);
66 input_start=0;
67 return true;
68 }
69
can_seek() const70 FXbool AIFFReader::can_seek() const {
71 return true;
72 }
73
74
seek(FXlong pos)75 FXbool AIFFReader::seek(FXlong pos){
76 FXlong offset=input_start + (FXCLAMP(0,pos,stream_length) * af.framesize());
77 input->position(offset,FXIO::Begin);
78 return true;
79 }
80
process(Packet * packet)81 ReadStatus AIFFReader::process(Packet*packet) {
82
83 if (!(flags&FLAG_PARSED)) {
84 if (parse()!=ReadOk)
85 return ReadError;
86 }
87
88 FXint nbytes = (packet->space() / af.framesize()) * af.framesize();
89 FXint nread = input->read(packet->ptr(),nbytes);
90 if (nread<0) {
91 packet->unref();
92 return ReadError;
93 }
94 else if (nread==0){
95 packet->unref();
96 return ReadDone;
97 }
98
99 packet->af = af;
100 packet->wroteBytes(nread);
101 packet->stream_position = static_cast<FXint>( (input->position()-input_start-nread) / af.framesize() );
102 packet->stream_length = stream_length;
103 if (input->eof())
104 packet->flags=FLAG_EOS;
105 else
106 packet->flags=0;
107
108 context->post_packet(packet);
109
110 return ReadOk;
111 }
112
113
114
115
116 /* Kindly borrowed from FLAC
117 *
118 * flac - Command-line FLAC encoder/decoder
119 * Copyright (C) 2000-2009 Josh Coalson
120 * Copyright (C) 2011-2013 Xiph.Org Foundation
121 * This program is free software; you can redistribute it and/or
122 * modify it under the terms of the GNU General Public License
123 * as published by the Free Software Foundation; either version 2
124 * of the License, or (at your option) any later version.
125 */
parse_extended(FXuint & val,const FXuchar buf[10])126 static FXbool parse_extended(FXuint & val,const FXuchar buf[10])
127 /* Read an IEEE 754 80-bit (aka SANE) extended floating point value from 'f',
128 * convert it into an integral value and store in 'val'. Return false if only
129 * between 1 and 9 bytes remain in 'f', if 0 bytes remain in 'f', or if the
130 * value is negative, between zero and one, or too large to be represented by
131 * 'val'; return true otherwise.
132 */
133 {
134 unsigned int i;
135 FXulong p = 0;
136 FXshort e;
137 FXshort shift;
138 val = 0;
139
140 e = ((FXushort)(buf[0])<<8 | (FXushort)(buf[1]))-0x3FFF;
141 shift = 63-e;
142 if((buf[0]>>7)==1U || e<0 || e>63) {
143 return false;
144 }
145
146 for(i = 0; i < 8; ++i)
147 p |= (FXulong)(buf[i+2])<<(56U-i*8);
148
149 val = (FXuint)((p>>shift)+(p>>(shift-1) & 0x1));
150 return true;
151 }
152
153
154
parse()155 ReadStatus AIFFReader::parse() {
156 FXuint chunkid;
157 FXuint chunksize;
158 FXuint formsize;
159
160 FXshort channels;
161 FXuint nsamples;
162 FXshort samplesize;
163 FXuchar extended[10];
164 FXuint rate;
165
166 FXbool got_comm = false;
167 FXbool got_ssnd = false;
168
169
170 GM_DEBUG_PRINT("[aiff] parsing aiff header\n");
171
172 // formchunk
173 if (input->read(&chunkid,4)!=4 || chunkid!=FORM){
174 GM_DEBUG_PRINT("[aiff] no FORM tag found\n");
175 return ReadError;
176 }
177
178 // formsize
179 if (!input->read_uint32_be(formsize)){
180 return ReadError;
181 }
182
183 // formchunk
184 if (input->read(&chunkid,4)!=4 || chunkid!=AIFF){
185 GM_DEBUG_PRINT("[aiff] no AIFF tag found\n");
186 return ReadError;
187 }
188
189 while(formsize>0) {
190
191 // get the chunk id
192 if (input->read(&chunkid,4)!=4){
193 return ReadError;
194 }
195
196 // chunk size
197 if (!input->read_uint32_be(chunksize)){
198 return ReadError;
199 }
200
201 // COMM chunk
202 if (chunkid==COMM) {
203 if (got_comm) return ReadError;
204
205 if (!input->read_int16_be(channels))
206 return ReadError;
207
208 if (!input->read_uint32_be(nsamples))
209 return ReadError;
210
211 if (!input->read_int16_be(samplesize))
212 return ReadError;
213
214 if (input->read(&extended,10)!=10 || !parse_extended(rate,extended))
215 return ReadError;
216
217 if (nsamples==0) return ReadError;
218
219 af.set(Format::Signed|Format::Big,samplesize,samplesize>>3,rate,channels);
220 got_comm=true;
221 if (got_ssnd) break;
222 }
223
224 /// SSND chunk
225 else if (chunkid==SSND) {
226
227 if (got_ssnd || (input->serial() && got_comm==false)) {
228 GM_DEBUG_PRINT("[aiff] multiple ssnd or ssnd before comm in serial stream\n");
229 return ReadError;
230 }
231
232 got_ssnd = true;
233
234 FXuint offset;
235 FXuint blocksize;
236
237 if (!input->read_uint32_be(offset))
238 return ReadError;
239
240 if (!input->read_uint32_be(blocksize))
241 return ReadError;
242
243 if (blocksize!=0) {
244 GM_DEBUG_PRINT("[aiff] blocksize %u not supported\n",blocksize);
245 return ReadError;
246 }
247
248 input_start = input->position() + offset;
249
250 // Stop scanning
251 if (got_comm==true) break;
252 }
253 else {
254 input->position(chunksize,FXIO::Current);
255 }
256 formsize-=chunksize;
257 }
258
259 if (got_ssnd && got_comm) {
260 stream_length = nsamples;
261 flags|=FLAG_PARSED;
262 GM_DEBUG_STREAM_LENGTH("aiff",stream_length,af.rate);
263 context->post_configuration(new ConfigureEvent(af,Codec::PCM));
264 return ReadOk;
265 }
266 return ReadError;
267 }
268
269
ap_aiff_reader(InputContext * ctx)270 ReaderPlugin * ap_aiff_reader(InputContext * ctx) {
271 return new AIFFReader(ctx);
272 }
273 }
274