diff options
Diffstat (limited to 'apps/codecs/demac/demac.c')
-rw-r--r-- | apps/codecs/demac/demac.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/apps/codecs/demac/demac.c b/apps/codecs/demac/demac.c new file mode 100644 index 0000000000..da132ff248 --- /dev/null +++ b/apps/codecs/demac/demac.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | |||
3 | demac - A Monkey's Audio decoder | ||
4 | |||
5 | $Id:$ | ||
6 | |||
7 | Copyright (C) Dave Chapman 2007 | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA | ||
22 | |||
23 | */ | ||
24 | |||
25 | /* | ||
26 | |||
27 | This example is intended to demonstrate how the decoder can be used in | ||
28 | embedded devices - there is no usage of dynamic memory (i.e. no | ||
29 | malloc/free) and small buffer sizes are chosen to minimise both the | ||
30 | memory usage and decoding latency. | ||
31 | |||
32 | This implementation requires the following memory and supports decoding of all APE files up to 24-bit Stereo. | ||
33 | |||
34 | 32768 - data from the input stream to be presented to the decoder in one contiguous chunk. | ||
35 | 18432 - decoding buffer (left channel) | ||
36 | 18432 - decoding buffer (right channel) | ||
37 | |||
38 | 17408+5120+2240 - buffers used for filter histories (compression levels 2000-5000) | ||
39 | |||
40 | In addition, this example uses a static 27648 byte buffer as temporary | ||
41 | storage for outputting the data to a WAV file but that could be | ||
42 | avoided by writing the decoded data one sample at a time. | ||
43 | |||
44 | */ | ||
45 | |||
46 | #include <stdio.h> | ||
47 | #include <inttypes.h> | ||
48 | #include <stdlib.h> | ||
49 | #include <sys/types.h> | ||
50 | #include <sys/stat.h> | ||
51 | #include <fcntl.h> | ||
52 | #include <unistd.h> | ||
53 | #include <string.h> | ||
54 | |||
55 | #include "demac.h" | ||
56 | #include "wavwrite.h" | ||
57 | |||
58 | #ifndef __WIN32__ | ||
59 | #define O_BINARY 0 | ||
60 | #endif | ||
61 | |||
62 | #define CALC_CRC 1 | ||
63 | |||
64 | #define BLOCKS_PER_LOOP 4608 | ||
65 | #define MAX_CHANNELS 2 | ||
66 | #define MAX_BYTESPERSAMPLE 3 | ||
67 | |||
68 | #define INPUT_CHUNKSIZE (32*1024) | ||
69 | |||
70 | #ifndef MIN | ||
71 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
72 | #endif | ||
73 | |||
74 | |||
75 | /* 4608*2*3 = 27648 bytes */ | ||
76 | static unsigned char wavbuffer[BLOCKS_PER_LOOP*MAX_CHANNELS*MAX_BYTESPERSAMPLE]; | ||
77 | |||
78 | /* 4608*4 = 18432 bytes per channel */ | ||
79 | static int32_t decoded0[BLOCKS_PER_LOOP]; | ||
80 | static int32_t decoded1[BLOCKS_PER_LOOP]; | ||
81 | |||
82 | /* We assume that 32KB of compressed data is enough to extract up to | ||
83 | 27648 bytes of decompressed data. */ | ||
84 | |||
85 | static unsigned char inbuffer[INPUT_CHUNKSIZE]; | ||
86 | |||
87 | int ape_decode(char* infile, char* outfile) | ||
88 | { | ||
89 | int fd; | ||
90 | int fdwav; | ||
91 | int currentframe; | ||
92 | int nblocks; | ||
93 | int bytesconsumed; | ||
94 | struct ape_ctx_t ape_ctx; | ||
95 | int i, n; | ||
96 | unsigned char* p; | ||
97 | int bytesinbuffer; | ||
98 | int blockstodecode; | ||
99 | int res; | ||
100 | int firstbyte; | ||
101 | int16_t sample16; | ||
102 | int32_t sample32; | ||
103 | uint32_t frame_crc; | ||
104 | int crc_errors = 0; | ||
105 | |||
106 | fd = open(infile,O_RDONLY|O_BINARY); | ||
107 | if (fd < 0) return -1; | ||
108 | |||
109 | /* Read the file headers to populate the ape_ctx struct */ | ||
110 | if (ape_parseheader(fd,&ape_ctx) < 0) { | ||
111 | printf("Cannot read header\n"); | ||
112 | close(fd); | ||
113 | return -1; | ||
114 | } | ||
115 | |||
116 | if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) { | ||
117 | printf("Unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0); | ||
118 | close(fd); | ||
119 | return -2; | ||
120 | } | ||
121 | |||
122 | //ape_dumpinfo(&ape_ctx); | ||
123 | |||
124 | printf("Decoding file - v%.2f, compression level %d\n",ape_ctx.fileversion/1000.0,ape_ctx.compressiontype); | ||
125 | |||
126 | /* Open the WAV file and write a canonical 44-byte WAV header | ||
127 | based on the audio format information in the ape_ctx struct. | ||
128 | |||
129 | NOTE: This example doesn't write the original WAV header and | ||
130 | tail data which are (optionally) stored in the APE file. | ||
131 | */ | ||
132 | fdwav = open_wav(&ape_ctx,outfile); | ||
133 | |||
134 | currentframe = 0; | ||
135 | |||
136 | /* Initialise the buffer */ | ||
137 | lseek(fd, ape_ctx.firstframe, SEEK_SET); | ||
138 | bytesinbuffer = read(fd, inbuffer, INPUT_CHUNKSIZE); | ||
139 | firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ | ||
140 | |||
141 | /* The main decoding loop - we decode the frames a small chunk at a time */ | ||
142 | while (currentframe < ape_ctx.totalframes) | ||
143 | { | ||
144 | /* Calculate how many blocks there are in this frame */ | ||
145 | if (currentframe == (ape_ctx.totalframes - 1)) | ||
146 | nblocks = ape_ctx.finalframeblocks; | ||
147 | else | ||
148 | nblocks = ape_ctx.blocksperframe; | ||
149 | |||
150 | ape_ctx.currentframeblocks = nblocks; | ||
151 | |||
152 | /* Initialise the frame decoder */ | ||
153 | init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed); | ||
154 | |||
155 | /* Update buffer */ | ||
156 | memmove(inbuffer,inbuffer + bytesconsumed, bytesinbuffer - bytesconsumed); | ||
157 | bytesinbuffer -= bytesconsumed; | ||
158 | |||
159 | n = read(fd, inbuffer + bytesinbuffer, INPUT_CHUNKSIZE - bytesinbuffer); | ||
160 | bytesinbuffer += n; | ||
161 | |||
162 | #if CALC_CRC | ||
163 | frame_crc = ape_initcrc(); | ||
164 | #endif | ||
165 | |||
166 | /* Decode the frame a chunk at a time */ | ||
167 | while (nblocks > 0) | ||
168 | { | ||
169 | blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); | ||
170 | |||
171 | if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte, | ||
172 | &bytesconsumed, | ||
173 | decoded0, decoded1, | ||
174 | blockstodecode)) < 0) | ||
175 | { | ||
176 | /* Frame decoding error, abort */ | ||
177 | close(fd); | ||
178 | return res; | ||
179 | } | ||
180 | |||
181 | /* Convert the output samples to WAV format and write to output file */ | ||
182 | p = wavbuffer; | ||
183 | if (ape_ctx.bps == 16) { | ||
184 | for (i = 0 ; i < blockstodecode ; i++) | ||
185 | { | ||
186 | sample16 = decoded0[i]; | ||
187 | *(p++) = sample16 & 0xff; | ||
188 | *(p++) = (sample16&0xff00) >> 8; | ||
189 | |||
190 | if (ape_ctx.channels == 2) { | ||
191 | sample16 = decoded1[i]; | ||
192 | *(p++) = sample16 & 0xff; | ||
193 | *(p++) = (sample16&0xff00) >> 8; | ||
194 | } | ||
195 | } | ||
196 | } else if (ape_ctx.bps == 24) { | ||
197 | for (i = 0 ; i < blockstodecode ; i++) | ||
198 | { | ||
199 | sample32 = decoded0[i]; | ||
200 | *(p++) = sample32 & 0xff; | ||
201 | *(p++) = (sample32&0xff00) >> 8; | ||
202 | *(p++) = (sample32&0xff0000) >> 16; | ||
203 | |||
204 | if (ape_ctx.channels == 2) { | ||
205 | sample32 = decoded1[i]; | ||
206 | *(p++) = sample32 & 0xff; | ||
207 | *(p++) = (sample32&0xff00) >> 8; | ||
208 | *(p++) = (sample32&0xff0000) >> 16; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | #if CALC_CRC | ||
214 | frame_crc = ape_updatecrc(wavbuffer, p - wavbuffer, frame_crc); | ||
215 | #endif | ||
216 | write(fdwav,wavbuffer,p - wavbuffer); | ||
217 | |||
218 | /* Update the buffer */ | ||
219 | memmove(inbuffer,inbuffer + bytesconsumed, bytesinbuffer - bytesconsumed); | ||
220 | bytesinbuffer -= bytesconsumed; | ||
221 | |||
222 | n = read(fd, inbuffer + bytesinbuffer, INPUT_CHUNKSIZE - bytesinbuffer); | ||
223 | bytesinbuffer += n; | ||
224 | |||
225 | /* Decrement the block count */ | ||
226 | nblocks -= blockstodecode; | ||
227 | } | ||
228 | |||
229 | #if CALC_CRC | ||
230 | frame_crc = ape_finishcrc(frame_crc); | ||
231 | |||
232 | if (ape_ctx.CRC != frame_crc) | ||
233 | { | ||
234 | fprintf(stderr,"CRC error in frame %d\n",currentframe); | ||
235 | crc_errors++; | ||
236 | } | ||
237 | #endif | ||
238 | |||
239 | currentframe++; | ||
240 | } | ||
241 | |||
242 | close(fd); | ||
243 | close(fdwav); | ||
244 | |||
245 | if (crc_errors > 0) | ||
246 | return -1; | ||
247 | else | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | int main(int argc, char* argv[]) | ||
252 | { | ||
253 | int res; | ||
254 | |||
255 | if (argc != 3) { | ||
256 | fprintf(stderr,"Usage: demac infile.ape outfile.wav\n"); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | res = ape_decode(argv[1], argv[2]); | ||
261 | |||
262 | if (res < 0) | ||
263 | { | ||
264 | fprintf(stderr,"DECODING ERROR %d, ABORTING\n", res); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | fprintf(stderr,"DECODED OK - NO CRC ERRORS.\n"); | ||
269 | } | ||
270 | |||
271 | return 0; | ||
272 | } | ||