diff options
author | Björn Stenberg <bjorn@haxx.se> | 2008-10-10 13:12:28 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2008-10-10 13:12:28 +0000 |
commit | e76c69f3e4b9075db979145a60157d8cd968f537 (patch) | |
tree | 84ac8d57c687d1fdd10d8f205aa83a048edfd875 /firmware | |
parent | 98fa3913f9618a09269e9ab39abb9a53274f5676 (diff) | |
download | rockbox-e76c69f3e4b9075db979145a60157d8cd968f537.tar.gz rockbox-e76c69f3e4b9075db979145a60157d8cd968f537.zip |
Moved id3.c, mpeg.c and replaygain.c from firmware/ to apps/. This is the first step in separating the generic metadata code and the id3-specific code.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18760 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/SOURCES | 3 | ||||
-rw-r--r-- | firmware/id3.c | 1353 | ||||
-rw-r--r-- | firmware/mpeg.c | 2872 | ||||
-rw-r--r-- | firmware/replaygain.c | 457 |
4 files changed, 0 insertions, 4685 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 6717ccaf93..4ac32bf853 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -2,7 +2,6 @@ ata_idle_notify.c | |||
2 | events.c | 2 | events.c |
3 | backlight.c | 3 | backlight.c |
4 | buffer.c | 4 | buffer.c |
5 | id3.c | ||
6 | powermgmt.c | 5 | powermgmt.c |
7 | system.c | 6 | system.c |
8 | usb.c | 7 | usb.c |
@@ -189,7 +188,6 @@ sound.c | |||
189 | #ifndef BOOTLOADER | 188 | #ifndef BOOTLOADER |
190 | general.c | 189 | general.c |
191 | pcm_sampr.c | 190 | pcm_sampr.c |
192 | replaygain.c | ||
193 | pcm.c | 191 | pcm.c |
194 | #ifdef HAVE_RECORDING | 192 | #ifdef HAVE_RECORDING |
195 | enc_base.c | 193 | enc_base.c |
@@ -202,7 +200,6 @@ pcm_record.c | |||
202 | #else /* !SWCODEC */ | 200 | #else /* !SWCODEC */ |
203 | 201 | ||
204 | #ifndef BOOTLOADER | 202 | #ifndef BOOTLOADER |
205 | mpeg.c | ||
206 | #ifndef SIMULATOR | 203 | #ifndef SIMULATOR |
207 | drivers/mas.c | 204 | drivers/mas.c |
208 | #endif /* SIMULATOR */ | 205 | #endif /* SIMULATOR */ |
diff --git a/firmware/id3.c b/firmware/id3.c deleted file mode 100644 index c1541e30df..0000000000 --- a/firmware/id3.c +++ /dev/null | |||
@@ -1,1353 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Daniel Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | /* | ||
22 | * Parts of this code has been stolen from the Ample project and was written | ||
23 | * by David H�deman. It has since been extended and enhanced pretty much by | ||
24 | * all sorts of friendly Rockbox people. | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach | ||
29 | */ | ||
30 | |||
31 | #include <stdio.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <errno.h> | ||
35 | #include <stdbool.h> | ||
36 | #include <stddef.h> | ||
37 | #include <ctype.h> | ||
38 | #include "config.h" | ||
39 | #include "file.h" | ||
40 | #include "logf.h" | ||
41 | |||
42 | #include "id3.h" | ||
43 | #include "mp3data.h" | ||
44 | #include "system.h" | ||
45 | #include "replaygain.h" | ||
46 | #include "rbunicode.h" | ||
47 | |||
48 | /** Database of audio formats **/ | ||
49 | const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | ||
50 | { | ||
51 | /* Unknown file format */ | ||
52 | [AFMT_UNKNOWN] = | ||
53 | AFMT_ENTRY("???", NULL, NULL, NULL ), | ||
54 | |||
55 | /* MPEG Audio layer 1 */ | ||
56 | [AFMT_MPA_L1] = | ||
57 | AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ), | ||
58 | /* MPEG Audio layer 2 */ | ||
59 | [AFMT_MPA_L2] = | ||
60 | AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ), | ||
61 | /* MPEG Audio layer 3 */ | ||
62 | [AFMT_MPA_L3] = | ||
63 | AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ), | ||
64 | |||
65 | #if CONFIG_CODEC == SWCODEC | ||
66 | /* Audio Interchange File Format */ | ||
67 | [AFMT_AIFF] = | ||
68 | AFMT_ENTRY("AIFF", "aiff", "aiff_enc", "aiff\0aif\0"), | ||
69 | /* Uncompressed PCM in a WAV file */ | ||
70 | [AFMT_PCM_WAV] = | ||
71 | AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ), | ||
72 | /* Ogg Vorbis */ | ||
73 | [AFMT_OGG_VORBIS] = | ||
74 | AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ), | ||
75 | /* FLAC */ | ||
76 | [AFMT_FLAC] = | ||
77 | AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ), | ||
78 | /* Musepack */ | ||
79 | [AFMT_MPC] = | ||
80 | AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ), | ||
81 | /* A/52 (aka AC3) audio */ | ||
82 | [AFMT_A52] = | ||
83 | AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ), | ||
84 | /* WavPack */ | ||
85 | [AFMT_WAVPACK] = | ||
86 | AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ), | ||
87 | /* Apple Lossless Audio Codec */ | ||
88 | [AFMT_ALAC] = | ||
89 | AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0m4b\0" ), | ||
90 | /* Advanced Audio Coding in M4A container */ | ||
91 | [AFMT_AAC] = | ||
92 | AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ), | ||
93 | /* Shorten */ | ||
94 | [AFMT_SHN] = | ||
95 | AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ), | ||
96 | /* SID File Format */ | ||
97 | [AFMT_SID] = | ||
98 | AFMT_ENTRY("SID", "sid", NULL, "sid\0" ), | ||
99 | /* ADX File Format */ | ||
100 | [AFMT_ADX] = | ||
101 | AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ), | ||
102 | /* NESM (NES Sound Format) */ | ||
103 | [AFMT_NSF] = | ||
104 | AFMT_ENTRY("NSF", "nsf", NULL, "nsf\0nsfe\0" ), | ||
105 | /* Speex File Format */ | ||
106 | [AFMT_SPEEX] = | ||
107 | AFMT_ENTRY("Speex","speex", NULL, "spx\0" ), | ||
108 | /* SPC700 Save State */ | ||
109 | [AFMT_SPC] = | ||
110 | AFMT_ENTRY("SPC", "spc", NULL, "spc\0" ), | ||
111 | /* APE (Monkey's Audio) */ | ||
112 | [AFMT_APE] = | ||
113 | AFMT_ENTRY("APE", "ape", NULL, "ape\0mac\0" ), | ||
114 | /* WMA (WMAV1/V2 in ASF) */ | ||
115 | [AFMT_WMA] = | ||
116 | AFMT_ENTRY("WMA", "wma", NULL, "wma\0wmv\0asf\0" ), | ||
117 | /* Amiga MOD File */ | ||
118 | [AFMT_MOD] = | ||
119 | AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ), | ||
120 | /* Amiga SAP File */ | ||
121 | [AFMT_SAP] = | ||
122 | AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ), | ||
123 | #endif | ||
124 | }; | ||
125 | |||
126 | #if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) | ||
127 | /* get REC_FORMAT_* corresponding AFMT_* */ | ||
128 | const int rec_format_afmt[REC_NUM_FORMATS] = | ||
129 | { | ||
130 | /* give AFMT_UNKNOWN by default */ | ||
131 | [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN, | ||
132 | /* add new entries below this line */ | ||
133 | [REC_FORMAT_AIFF] = AFMT_AIFF, | ||
134 | [REC_FORMAT_MPA_L3] = AFMT_MPA_L3, | ||
135 | [REC_FORMAT_WAVPACK] = AFMT_WAVPACK, | ||
136 | [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV, | ||
137 | }; | ||
138 | |||
139 | /* get AFMT_* corresponding REC_FORMAT_* */ | ||
140 | const int afmt_rec_format[AFMT_NUM_CODECS] = | ||
141 | { | ||
142 | /* give -1 by default */ | ||
143 | [0 ... AFMT_NUM_CODECS-1] = -1, | ||
144 | /* add new entries below this line */ | ||
145 | [AFMT_AIFF] = REC_FORMAT_AIFF, | ||
146 | [AFMT_MPA_L3] = REC_FORMAT_MPA_L3, | ||
147 | [AFMT_WAVPACK] = REC_FORMAT_WAVPACK, | ||
148 | [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV, | ||
149 | }; | ||
150 | #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ | ||
151 | /****/ | ||
152 | |||
153 | static unsigned long unsync(unsigned long b0, | ||
154 | unsigned long b1, | ||
155 | unsigned long b2, | ||
156 | unsigned long b3) | ||
157 | { | ||
158 | return (((long)(b0 & 0x7F) << (3*7)) | | ||
159 | ((long)(b1 & 0x7F) << (2*7)) | | ||
160 | ((long)(b2 & 0x7F) << (1*7)) | | ||
161 | ((long)(b3 & 0x7F) << (0*7))); | ||
162 | } | ||
163 | |||
164 | static const char* const genres[] = { | ||
165 | "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", | ||
166 | "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", | ||
167 | "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", | ||
168 | "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", | ||
169 | "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", | ||
170 | "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", | ||
171 | "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", | ||
172 | "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", | ||
173 | "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", | ||
174 | "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", | ||
175 | "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", | ||
176 | "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", | ||
177 | "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", | ||
178 | |||
179 | /* winamp extensions */ | ||
180 | "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", | ||
181 | "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", | ||
182 | "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", | ||
183 | "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", | ||
184 | "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", | ||
185 | "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", | ||
186 | "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", | ||
187 | "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", | ||
188 | "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", | ||
189 | "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", | ||
190 | "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", | ||
191 | "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop", | ||
192 | "Synthpop" | ||
193 | }; | ||
194 | |||
195 | char* id3_get_num_genre(unsigned int genre_num) | ||
196 | { | ||
197 | if (genre_num < sizeof(genres)/sizeof(char*)) | ||
198 | return (char*)genres[genre_num]; | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | /* True if the string is from the "genres" array */ | ||
203 | static bool id3_is_genre_string(const char *string) | ||
204 | { | ||
205 | return ( string >= genres[0] && | ||
206 | string <= genres[sizeof(genres)/sizeof(char*) - 1] ); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | HOW TO ADD ADDITIONAL ID3 VERSION 2 TAGS | ||
211 | Code and comments by Thomas Paul Diffenbach | ||
212 | |||
213 | To add another ID3v2 Tag, do the following: | ||
214 | 1. add a char* named for the tag to struct mp3entry in id3.h, | ||
215 | (I (tpd) prefer to use char* rather than ints, even for what seems like | ||
216 | numerical values, for cases where a number won't do, e.g., | ||
217 | YEAR: "circa 1765", "1790/1977" (composed/performed), "28 Feb 1969" | ||
218 | TRACK: "1/12", "1 of 12", GENRE: "Freeform genre name" | ||
219 | Text is more flexible, and as the main use of id3 data is to | ||
220 | display it, converting it to an int just means reconverting to | ||
221 | display it, at a runtime cost.) | ||
222 | |||
223 | 2. If any special processing beyond copying the tag value from the Id3 | ||
224 | block to the struct mp3entry is rrequired (such as converting to an | ||
225 | int), write a function to perform this special processing. | ||
226 | |||
227 | This function's prototype must match that of | ||
228 | typedef tagPostProcessFunc, that is it must be: | ||
229 | int func( struct mp3entry*, char* tag, int bufferpos ) | ||
230 | the first argument is a pointer to the current mp3entry structure the | ||
231 | second argument is a pointer to the null terminated string value of the | ||
232 | tag found the third argument is the offset of the next free byte in the | ||
233 | mp3entry's buffer your function should return the corrected offset; if | ||
234 | you don't lengthen or shorten the tag string, you can return the third | ||
235 | argument unchanged. | ||
236 | |||
237 | Unless you have a good reason no to, make the function static. | ||
238 | TO JUST COPY THE TAG NO SPECIAL PROCESSING FUNCTION IS NEEDED. | ||
239 | |||
240 | 3. add one or more entries to the tagList array, using the format: | ||
241 | char* ID3 Tag symbolic name -- see the ID3 specification for these, | ||
242 | sizeof() that name minus 1, | ||
243 | offsetof( struct mp3entry, variable_name_in_struct_mp3entry ), | ||
244 | pointer to your special processing function or NULL | ||
245 | if you need no special processing | ||
246 | flag indicating if this tag is binary or textual | ||
247 | Many ID3 symbolic names come in more than one form. You can add both | ||
248 | forms, each referencing the same variable in struct mp3entry. | ||
249 | If both forms are present, the last found will be used. | ||
250 | Note that the offset can be zero, in which case no entry will be set | ||
251 | in the mp3entry struct; the frame is still read into the buffer and | ||
252 | the special processing function is called (several times, if there | ||
253 | are several frames with the same name). | ||
254 | |||
255 | 4. Alternately, use the TAG_LIST_ENTRY macro with | ||
256 | ID3 tag symbolic name, | ||
257 | variable in struct mp3entry, | ||
258 | special processing function address | ||
259 | |||
260 | 5. Add code to wps-display.c function get_tag to assign a printf-like | ||
261 | format specifier for the tag */ | ||
262 | |||
263 | /* Structure for ID3 Tag extraction information */ | ||
264 | struct tag_resolver { | ||
265 | const char* tag; | ||
266 | int tag_length; | ||
267 | size_t offset; | ||
268 | int (*ppFunc)(struct mp3entry*, char* tag, int bufferpos); | ||
269 | bool binary; | ||
270 | }; | ||
271 | |||
272 | static bool global_ff_found; | ||
273 | |||
274 | static int unsynchronize(char* tag, int len, bool *ff_found) | ||
275 | { | ||
276 | int i; | ||
277 | unsigned char c; | ||
278 | unsigned char *rp, *wp; | ||
279 | |||
280 | wp = rp = (unsigned char *)tag; | ||
281 | |||
282 | rp = (unsigned char *)tag; | ||
283 | for(i = 0;i < len;i++) { | ||
284 | /* Read the next byte and write it back, but don't increment the | ||
285 | write pointer */ | ||
286 | c = *rp++; | ||
287 | *wp = c; | ||
288 | if(*ff_found) { | ||
289 | /* Increment the write pointer if it isn't an unsynch pattern */ | ||
290 | if(c != 0) | ||
291 | wp++; | ||
292 | *ff_found = false; | ||
293 | } else { | ||
294 | if(c == 0xff) | ||
295 | *ff_found = true; | ||
296 | wp++; | ||
297 | } | ||
298 | } | ||
299 | return (long)wp - (long)tag; | ||
300 | } | ||
301 | |||
302 | static int unsynchronize_frame(char* tag, int len) | ||
303 | { | ||
304 | bool ff_found = false; | ||
305 | |||
306 | return unsynchronize(tag, len, &ff_found); | ||
307 | } | ||
308 | |||
309 | static int read_unsynched(int fd, void *buf, int len) | ||
310 | { | ||
311 | int i; | ||
312 | int rc; | ||
313 | int remaining = len; | ||
314 | char *wp; | ||
315 | char *rp; | ||
316 | |||
317 | wp = buf; | ||
318 | |||
319 | while(remaining) { | ||
320 | rp = wp; | ||
321 | rc = read(fd, rp, remaining); | ||
322 | if(rc <= 0) | ||
323 | return rc; | ||
324 | |||
325 | i = unsynchronize(wp, remaining, &global_ff_found); | ||
326 | remaining -= i; | ||
327 | wp += i; | ||
328 | } | ||
329 | |||
330 | return len; | ||
331 | } | ||
332 | |||
333 | static int skip_unsynched(int fd, int len) | ||
334 | { | ||
335 | int rc; | ||
336 | int remaining = len; | ||
337 | int rlen; | ||
338 | char buf[32]; | ||
339 | |||
340 | while(remaining) { | ||
341 | rlen = MIN(sizeof(buf), (unsigned int)remaining); | ||
342 | rc = read(fd, buf, rlen); | ||
343 | if(rc <= 0) | ||
344 | return rc; | ||
345 | |||
346 | remaining -= unsynchronize(buf, rlen, &global_ff_found); | ||
347 | } | ||
348 | |||
349 | return len; | ||
350 | } | ||
351 | |||
352 | /* parse numeric value from string */ | ||
353 | static int parsetracknum( struct mp3entry* entry, char* tag, int bufferpos ) | ||
354 | { | ||
355 | entry->tracknum = atoi( tag ); | ||
356 | return bufferpos; | ||
357 | } | ||
358 | |||
359 | /* parse numeric value from string */ | ||
360 | static int parsediscnum( struct mp3entry* entry, char* tag, int bufferpos ) | ||
361 | { | ||
362 | entry->discnum = atoi( tag ); | ||
363 | return bufferpos; | ||
364 | } | ||
365 | |||
366 | /* parse numeric value from string */ | ||
367 | static int parseyearnum( struct mp3entry* entry, char* tag, int bufferpos ) | ||
368 | { | ||
369 | entry->year = atoi( tag ); | ||
370 | return bufferpos; | ||
371 | } | ||
372 | |||
373 | /* parse numeric genre from string, version 2.2 and 2.3 */ | ||
374 | static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos ) | ||
375 | { | ||
376 | if(entry->id3version >= ID3_VER_2_4) { | ||
377 | /* In version 2.4 and up, there are no parentheses, and the genre frame | ||
378 | is a list of strings, either numbers or text. */ | ||
379 | |||
380 | /* Is it a number? */ | ||
381 | if(isdigit(tag[0])) { | ||
382 | entry->genre_string = id3_get_num_genre(atoi( tag )); | ||
383 | return tag - entry->id3v2buf; | ||
384 | } else { | ||
385 | entry->genre_string = tag; | ||
386 | return bufferpos; | ||
387 | } | ||
388 | } else { | ||
389 | if( tag[0] == '(' && tag[1] != '(' ) { | ||
390 | entry->genre_string = id3_get_num_genre(atoi( tag + 1 )); | ||
391 | return tag - entry->id3v2buf; | ||
392 | } | ||
393 | else { | ||
394 | entry->genre_string = tag; | ||
395 | return bufferpos; | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | |||
400 | #if CONFIG_CODEC == SWCODEC | ||
401 | /* parse user defined text, looking for replaygain information. */ | ||
402 | static int parseuser( struct mp3entry* entry, char* tag, int bufferpos ) | ||
403 | { | ||
404 | char* value = NULL; | ||
405 | int desc_len = strlen(tag); | ||
406 | int value_len = 0; | ||
407 | |||
408 | if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) { | ||
409 | /* At least part of the value was read, so we can safely try to | ||
410 | * parse it | ||
411 | */ | ||
412 | value = tag + desc_len + 1; | ||
413 | value_len = parse_replaygain(tag, value, entry, tag, | ||
414 | bufferpos - (tag - entry->id3v2buf)); | ||
415 | } | ||
416 | |||
417 | return tag - entry->id3v2buf + value_len; | ||
418 | } | ||
419 | |||
420 | /* parse RVA2 binary data and convert to replaygain information. */ | ||
421 | static int parserva2( struct mp3entry* entry, char* tag, int bufferpos ) | ||
422 | { | ||
423 | int desc_len = strlen(tag); | ||
424 | int start_pos = tag - entry->id3v2buf; | ||
425 | int end_pos = start_pos + desc_len + 5; | ||
426 | int value_len = 0; | ||
427 | unsigned char* value = tag + desc_len + 1; | ||
428 | |||
429 | /* Only parse RVA2 replaygain tags if tag version == 2.4 and channel | ||
430 | * type is master volume. | ||
431 | */ | ||
432 | if (entry->id3version == ID3_VER_2_4 && end_pos < bufferpos | ||
433 | && *value++ == 1) { | ||
434 | long gain = 0; | ||
435 | long peak = 0; | ||
436 | long peakbits; | ||
437 | long peakbytes; | ||
438 | bool album = false; | ||
439 | |||
440 | /* The RVA2 specification is unclear on some things (id string and | ||
441 | * peak volume), but this matches how Quod Libet use them. | ||
442 | */ | ||
443 | |||
444 | gain = (int16_t) ((value[0] << 8) | value[1]); | ||
445 | value += 2; | ||
446 | peakbits = *value++; | ||
447 | peakbytes = (peakbits + 7) / 8; | ||
448 | |||
449 | /* Only use the topmost 24 bits for peak volume */ | ||
450 | if (peakbytes > 3) { | ||
451 | peakbytes = 3; | ||
452 | } | ||
453 | |||
454 | /* Make sure the peak bits were read */ | ||
455 | if (end_pos + peakbytes < bufferpos) { | ||
456 | long shift = ((8 - (peakbits & 7)) & 7) + (3 - peakbytes) * 8; | ||
457 | |||
458 | for ( ; peakbytes; peakbytes--) { | ||
459 | peak <<= 8; | ||
460 | peak += *value++; | ||
461 | } | ||
462 | |||
463 | peak <<= shift; | ||
464 | |||
465 | if (peakbits > 24) { | ||
466 | peak += *value >> (8 - shift); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | if (strcasecmp(tag, "album") == 0) { | ||
471 | album = true; | ||
472 | } else if (strcasecmp(tag, "track") != 0) { | ||
473 | /* Only accept non-track values if we don't have any previous | ||
474 | * value. | ||
475 | */ | ||
476 | if (entry->track_gain != 0) { | ||
477 | return start_pos; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | value_len = parse_replaygain_int(album, gain, peak * 2, entry, | ||
482 | tag, sizeof(entry->id3v2buf) - start_pos); | ||
483 | } | ||
484 | |||
485 | return start_pos + value_len; | ||
486 | } | ||
487 | #endif | ||
488 | |||
489 | static int parsembtid( struct mp3entry* entry, char* tag, int bufferpos ) | ||
490 | { | ||
491 | char* value = NULL; | ||
492 | int desc_len = strlen(tag); | ||
493 | /*DEBUGF("MBID len: %d\n", desc_len);*/ | ||
494 | int value_len = 0; | ||
495 | |||
496 | if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) | ||
497 | { | ||
498 | value = tag + desc_len + 1; | ||
499 | |||
500 | if (strcasecmp(tag, "http://musicbrainz.org") == 0) | ||
501 | { | ||
502 | /* Musicbrainz track IDs are always 36 chars long plus null */ | ||
503 | value_len = 37; | ||
504 | |||
505 | entry->mb_track_id = value; | ||
506 | |||
507 | /*DEBUGF("ENTRY: %s LEN: %d\n", entry->mb_track_id, strlen(entry->mb_track_id));*/ | ||
508 | } | ||
509 | } | ||
510 | |||
511 | return tag - entry->id3v2buf + value_len; | ||
512 | } | ||
513 | |||
514 | static const struct tag_resolver taglist[] = { | ||
515 | { "TPE1", 4, offsetof(struct mp3entry, artist), NULL, false }, | ||
516 | { "TP1", 3, offsetof(struct mp3entry, artist), NULL, false }, | ||
517 | { "TIT2", 4, offsetof(struct mp3entry, title), NULL, false }, | ||
518 | { "TT2", 3, offsetof(struct mp3entry, title), NULL, false }, | ||
519 | { "TALB", 4, offsetof(struct mp3entry, album), NULL, false }, | ||
520 | { "TAL", 3, offsetof(struct mp3entry, album), NULL, false }, | ||
521 | { "TRK", 3, offsetof(struct mp3entry, track_string), &parsetracknum, false }, | ||
522 | { "TPOS", 4, offsetof(struct mp3entry, disc_string), &parsediscnum, false }, | ||
523 | { "TRCK", 4, offsetof(struct mp3entry, track_string), &parsetracknum, false }, | ||
524 | { "TDRC", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false }, | ||
525 | { "TYER", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false }, | ||
526 | { "TYE", 3, offsetof(struct mp3entry, year_string), &parseyearnum, false }, | ||
527 | { "TCOM", 4, offsetof(struct mp3entry, composer), NULL, false }, | ||
528 | { "TPE2", 4, offsetof(struct mp3entry, albumartist), NULL, false }, | ||
529 | { "TP2", 3, offsetof(struct mp3entry, albumartist), NULL, false }, | ||
530 | { "TIT1", 4, offsetof(struct mp3entry, grouping), NULL, false }, | ||
531 | { "TT1", 3, offsetof(struct mp3entry, grouping), NULL, false }, | ||
532 | { "COMM", 4, offsetof(struct mp3entry, comment), NULL, false }, | ||
533 | { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false }, | ||
534 | { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false }, | ||
535 | #if CONFIG_CODEC == SWCODEC | ||
536 | { "TXXX", 4, 0, &parseuser, false }, | ||
537 | { "RVA2", 4, 0, &parserva2, true }, | ||
538 | #endif | ||
539 | { "UFID", 4, 0, &parsembtid, false }, | ||
540 | }; | ||
541 | |||
542 | #define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0]))) | ||
543 | |||
544 | /* Get the length of an ID3 string in the given encoding. Returns the length | ||
545 | * in bytes, including end nil, or -1 if the encoding is unknown. | ||
546 | */ | ||
547 | static int unicode_len(char encoding, const void* string) | ||
548 | { | ||
549 | int len = 0; | ||
550 | |||
551 | if (encoding == 0x01 || encoding == 0x02) { | ||
552 | char first; | ||
553 | const char *s = string; | ||
554 | /* string might be unaligned, so using short* can crash on ARM and SH1 */ | ||
555 | do { | ||
556 | first = *s++; | ||
557 | } while ((first | *s++) != 0); | ||
558 | |||
559 | len = s - (const char*) string; | ||
560 | } else { | ||
561 | len = strlen((char*) string) + 1; | ||
562 | } | ||
563 | |||
564 | return len; | ||
565 | } | ||
566 | |||
567 | /* Checks to see if the passed in string is a 16-bit wide Unicode v2 | ||
568 | string. If it is, we convert it to a UTF-8 string. If it's not unicode, | ||
569 | we convert from the default codepage */ | ||
570 | static int unicode_munge(char* string, char* utf8buf, int *len) { | ||
571 | long tmp; | ||
572 | bool le = false; | ||
573 | int i = 0; | ||
574 | unsigned char *str = (unsigned char *)string; | ||
575 | int templen = 0; | ||
576 | unsigned char* utf8 = (unsigned char *)utf8buf; | ||
577 | |||
578 | switch (str[0]) { | ||
579 | case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */ | ||
580 | str++; | ||
581 | (*len)--; | ||
582 | utf8 = iso_decode(str, utf8, -1, *len); | ||
583 | *utf8 = 0; | ||
584 | *len = (unsigned long)utf8 - (unsigned long)utf8buf; | ||
585 | break; | ||
586 | |||
587 | case 0x01: /* Unicode with or without BOM */ | ||
588 | case 0x02: | ||
589 | (*len)--; | ||
590 | str++; | ||
591 | |||
592 | /* Handle frames with more than one string | ||
593 | (needed for TXXX frames).*/ | ||
594 | do { | ||
595 | tmp = bytes2int(0, 0, str[0], str[1]); | ||
596 | |||
597 | /* Now check if there is a BOM | ||
598 | (zero-width non-breaking space, 0xfeff) | ||
599 | and if it is in little or big endian format */ | ||
600 | if(tmp == 0xfffe) { /* Little endian? */ | ||
601 | le = true; | ||
602 | str += 2; | ||
603 | (*len)-=2; | ||
604 | } else if(tmp == 0xfeff) { /* Big endian? */ | ||
605 | str += 2; | ||
606 | (*len)-=2; | ||
607 | } else | ||
608 | /* If there is no BOM (which is a specification violation), | ||
609 | let's try to guess it. If one of the bytes is 0x00, it is | ||
610 | probably the most significant one. */ | ||
611 | if(str[1] == 0) | ||
612 | le = true; | ||
613 | |||
614 | do { | ||
615 | if(le) | ||
616 | utf8 = utf16LEdecode(str, utf8, 1); | ||
617 | else | ||
618 | utf8 = utf16BEdecode(str, utf8, 1); | ||
619 | |||
620 | str+=2; | ||
621 | i += 2; | ||
622 | } while((str[0] || str[1]) && (i < *len)); | ||
623 | |||
624 | *utf8++ = 0; /* Terminate the string */ | ||
625 | templen += (strlen(&utf8buf[templen]) + 1); | ||
626 | str += 2; | ||
627 | i+=2; | ||
628 | } while(i < *len); | ||
629 | *len = templen - 1; | ||
630 | break; | ||
631 | |||
632 | case 0x03: /* UTF-8 encoded string */ | ||
633 | for(i=0; i < *len; i++) | ||
634 | utf8[i] = str[i+1]; | ||
635 | (*len)--; | ||
636 | break; | ||
637 | |||
638 | default: /* Plain old string */ | ||
639 | utf8 = iso_decode(str, utf8, -1, *len); | ||
640 | *utf8 = 0; | ||
641 | *len = (unsigned long)utf8 - (unsigned long)utf8buf; | ||
642 | break; | ||
643 | } | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | /* | ||
648 | * Sets the title of an MP3 entry based on its ID3v1 tag. | ||
649 | * | ||
650 | * Arguments: file - the MP3 file to scen for a ID3v1 tag | ||
651 | * entry - the entry to set the title in | ||
652 | * | ||
653 | * Returns: true if a title was found and created, else false | ||
654 | */ | ||
655 | static bool setid3v1title(int fd, struct mp3entry *entry) | ||
656 | { | ||
657 | unsigned char buffer[128]; | ||
658 | static const char offsets[] = {3, 33, 63, 97, 93, 125, 127}; | ||
659 | int i, j; | ||
660 | unsigned char* utf8; | ||
661 | |||
662 | if (-1 == lseek(fd, -128, SEEK_END)) | ||
663 | return false; | ||
664 | |||
665 | if (read(fd, buffer, sizeof buffer) != sizeof buffer) | ||
666 | return false; | ||
667 | |||
668 | if (strncmp((char *)buffer, "TAG", 3)) | ||
669 | return false; | ||
670 | |||
671 | entry->id3v1len = 128; | ||
672 | entry->id3version = ID3_VER_1_0; | ||
673 | |||
674 | for (i=0; i < (int)sizeof offsets; i++) { | ||
675 | unsigned char* ptr = (unsigned char *)buffer + offsets[i]; | ||
676 | |||
677 | switch(i) { | ||
678 | case 0: | ||
679 | case 1: | ||
680 | case 2: | ||
681 | /* kill trailing space in strings */ | ||
682 | for (j=29; j && (ptr[j]==0 || ptr[j]==' '); j--) | ||
683 | ptr[j] = 0; | ||
684 | /* convert string to utf8 */ | ||
685 | utf8 = (unsigned char *)entry->id3v1buf[i]; | ||
686 | utf8 = iso_decode(ptr, utf8, -1, 30); | ||
687 | /* make sure string is terminated */ | ||
688 | *utf8 = 0; | ||
689 | break; | ||
690 | |||
691 | case 3: | ||
692 | /* kill trailing space in strings */ | ||
693 | for (j=27; j && (ptr[j]==0 || ptr[j]==' '); j--) | ||
694 | ptr[j] = 0; | ||
695 | /* convert string to utf8 */ | ||
696 | utf8 = (unsigned char *)entry->id3v1buf[3]; | ||
697 | utf8 = iso_decode(ptr, utf8, -1, 28); | ||
698 | /* make sure string is terminated */ | ||
699 | *utf8 = 0; | ||
700 | break; | ||
701 | |||
702 | case 4: | ||
703 | ptr[4] = 0; | ||
704 | entry->year = atoi((char *)ptr); | ||
705 | break; | ||
706 | |||
707 | case 5: | ||
708 | /* id3v1.1 uses last two bytes of comment field for track | ||
709 | number: first must be 0 and second is track num */ | ||
710 | if (!ptr[0] && ptr[1]) { | ||
711 | entry->tracknum = ptr[1]; | ||
712 | entry->id3version = ID3_VER_1_1; | ||
713 | } | ||
714 | break; | ||
715 | |||
716 | case 6: | ||
717 | /* genre */ | ||
718 | entry->genre_string = id3_get_num_genre(ptr[0]); | ||
719 | break; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | entry->title = entry->id3v1buf[0]; | ||
724 | entry->artist = entry->id3v1buf[1]; | ||
725 | entry->album = entry->id3v1buf[2]; | ||
726 | entry->comment = entry->id3v1buf[3]; | ||
727 | |||
728 | return true; | ||
729 | } | ||
730 | |||
731 | |||
732 | /* | ||
733 | * Sets the title of an MP3 entry based on its ID3v2 tag. | ||
734 | * | ||
735 | * Arguments: file - the MP3 file to scan for a ID3v2 tag | ||
736 | * entry - the entry to set the title in | ||
737 | * | ||
738 | * Returns: true if a title was found and created, else false | ||
739 | */ | ||
740 | static void setid3v2title(int fd, struct mp3entry *entry) | ||
741 | { | ||
742 | int minframesize; | ||
743 | int size; | ||
744 | long bufferpos = 0, totframelen, framelen; | ||
745 | char header[10]; | ||
746 | char tmp[4]; | ||
747 | unsigned char version; | ||
748 | char *buffer = entry->id3v2buf; | ||
749 | int bytesread = 0; | ||
750 | int buffersize = sizeof(entry->id3v2buf); | ||
751 | unsigned char global_flags; | ||
752 | int flags; | ||
753 | int skip; | ||
754 | bool global_unsynch = false; | ||
755 | bool unsynch = false; | ||
756 | int i, j; | ||
757 | int rc; | ||
758 | |||
759 | global_ff_found = false; | ||
760 | |||
761 | /* Bail out if the tag is shorter than 10 bytes */ | ||
762 | if(entry->id3v2len < 10) | ||
763 | return; | ||
764 | |||
765 | /* Read the ID3 tag version from the header */ | ||
766 | lseek(fd, 0, SEEK_SET); | ||
767 | if(10 != read(fd, header, 10)) | ||
768 | return; | ||
769 | |||
770 | /* Get the total ID3 tag size */ | ||
771 | size = entry->id3v2len - 10; | ||
772 | |||
773 | version = header[3]; | ||
774 | switch ( version ) { | ||
775 | case 2: | ||
776 | version = ID3_VER_2_2; | ||
777 | minframesize = 8; | ||
778 | break; | ||
779 | |||
780 | case 3: | ||
781 | version = ID3_VER_2_3; | ||
782 | minframesize = 12; | ||
783 | break; | ||
784 | |||
785 | case 4: | ||
786 | version = ID3_VER_2_4; | ||
787 | minframesize = 12; | ||
788 | break; | ||
789 | |||
790 | default: | ||
791 | /* unsupported id3 version */ | ||
792 | return; | ||
793 | } | ||
794 | entry->id3version = version; | ||
795 | entry->tracknum = entry->year = entry->discnum = 0; | ||
796 | entry->title = entry->artist = entry->album = NULL; /* FIXME incomplete */ | ||
797 | |||
798 | global_flags = header[5]; | ||
799 | |||
800 | /* Skip the extended header if it is present */ | ||
801 | if(global_flags & 0x40) { | ||
802 | if(version == ID3_VER_2_3) { | ||
803 | if(10 != read(fd, header, 10)) | ||
804 | return; | ||
805 | /* The 2.3 extended header size doesn't include the header size | ||
806 | field itself. Also, it is not unsynched. */ | ||
807 | framelen = | ||
808 | bytes2int(header[0], header[1], header[2], header[3]) + 4; | ||
809 | |||
810 | /* Skip the rest of the header */ | ||
811 | lseek(fd, framelen - 10, SEEK_CUR); | ||
812 | } | ||
813 | |||
814 | if(version >= ID3_VER_2_4) { | ||
815 | if(4 != read(fd, header, 4)) | ||
816 | return; | ||
817 | |||
818 | /* The 2.4 extended header size does include the entire header, | ||
819 | so here we can just skip it. This header is unsynched. */ | ||
820 | framelen = unsync(header[0], header[1], | ||
821 | header[2], header[3]); | ||
822 | |||
823 | lseek(fd, framelen - 4, SEEK_CUR); | ||
824 | } | ||
825 | } | ||
826 | |||
827 | /* Is unsynchronization applied? */ | ||
828 | if(global_flags & 0x80) { | ||
829 | global_unsynch = true; | ||
830 | } | ||
831 | |||
832 | /* | ||
833 | * We must have at least minframesize bytes left for the | ||
834 | * remaining frames to be interesting | ||
835 | */ | ||
836 | while (size >= minframesize && bufferpos < buffersize - 1) { | ||
837 | flags = 0; | ||
838 | |||
839 | /* Read frame header and check length */ | ||
840 | if(version >= ID3_VER_2_3) { | ||
841 | if(global_unsynch && version <= ID3_VER_2_3) | ||
842 | rc = read_unsynched(fd, header, 10); | ||
843 | else | ||
844 | rc = read(fd, header, 10); | ||
845 | if(rc != 10) | ||
846 | return; | ||
847 | /* Adjust for the 10 bytes we read */ | ||
848 | size -= 10; | ||
849 | |||
850 | flags = bytes2int(0, 0, header[8], header[9]); | ||
851 | |||
852 | if (version >= ID3_VER_2_4) { | ||
853 | framelen = unsync(header[4], header[5], | ||
854 | header[6], header[7]); | ||
855 | } else { | ||
856 | /* version .3 files don't use synchsafe ints for | ||
857 | * size */ | ||
858 | framelen = bytes2int(header[4], header[5], | ||
859 | header[6], header[7]); | ||
860 | } | ||
861 | } else { | ||
862 | if(6 != read(fd, header, 6)) | ||
863 | return; | ||
864 | /* Adjust for the 6 bytes we read */ | ||
865 | size -= 6; | ||
866 | |||
867 | framelen = bytes2int(0, header[3], header[4], header[5]); | ||
868 | } | ||
869 | |||
870 | logf("framelen = %ld", framelen); | ||
871 | if(framelen == 0){ | ||
872 | if (header[0] == 0 && header[1] == 0 && header[2] == 0) | ||
873 | return; | ||
874 | else | ||
875 | continue; | ||
876 | } | ||
877 | |||
878 | unsynch = false; | ||
879 | |||
880 | if(flags) | ||
881 | { | ||
882 | skip = 0; | ||
883 | |||
884 | if (version >= ID3_VER_2_4) { | ||
885 | if(flags & 0x0040) { /* Grouping identity */ | ||
886 | lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */ | ||
887 | framelen--; | ||
888 | } | ||
889 | } else { | ||
890 | if(flags & 0x0020) { /* Grouping identity */ | ||
891 | lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */ | ||
892 | framelen--; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | if(flags & 0x000c) /* Compression or encryption */ | ||
897 | { | ||
898 | /* Skip it */ | ||
899 | size -= framelen; | ||
900 | lseek(fd, framelen, SEEK_CUR); | ||
901 | continue; | ||
902 | } | ||
903 | |||
904 | if(flags & 0x0002) /* Unsynchronization */ | ||
905 | unsynch = true; | ||
906 | |||
907 | if (version >= ID3_VER_2_4) { | ||
908 | if(flags & 0x0001) { /* Data length indicator */ | ||
909 | if(4 != read(fd, tmp, 4)) | ||
910 | return; | ||
911 | |||
912 | /* We don't need the data length */ | ||
913 | framelen -= 4; | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | /* Keep track of the remaining frame size */ | ||
919 | totframelen = framelen; | ||
920 | |||
921 | /* If the frame is larger than the remaining buffer space we try | ||
922 | to read as much as would fit in the buffer */ | ||
923 | if(framelen >= buffersize - bufferpos) | ||
924 | framelen = buffersize - bufferpos - 1; | ||
925 | |||
926 | logf("id3v2 frame: %.4s", header); | ||
927 | |||
928 | /* Check for certain frame headers | ||
929 | |||
930 | 'size' is the amount of frame bytes remaining. We decrement it by | ||
931 | the amount of bytes we read. If we fail to read as many bytes as | ||
932 | we expect, we assume that we can't read from this file, and bail | ||
933 | out. | ||
934 | |||
935 | For each frame. we will iterate over the list of supported tags, | ||
936 | and read the tag into entry's buffer. All tags will be kept as | ||
937 | strings, for cases where a number won't do, e.g., YEAR: "circa | ||
938 | 1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK: | ||
939 | "1/12", "1 of 12", GENRE: "Freeform genre name" Text is more | ||
940 | flexible, and as the main use of id3 data is to display it, | ||
941 | converting it to an int just means reconverting to display it, at a | ||
942 | runtime cost. | ||
943 | |||
944 | For tags that the current code does convert to ints, a post | ||
945 | processing function will be called via a pointer to function. */ | ||
946 | |||
947 | for (i=0; i<TAGLIST_SIZE; i++) { | ||
948 | const struct tag_resolver* tr = &taglist[i]; | ||
949 | char** ptag = tr->offset ? (char**) (((char*)entry) + tr->offset) | ||
950 | : NULL; | ||
951 | char* tag; | ||
952 | |||
953 | /* Only ID3_VER_2_2 uses frames with three-character names. */ | ||
954 | if (((version == ID3_VER_2_2) && (tr->tag_length != 3)) | ||
955 | || ((version > ID3_VER_2_2) && (tr->tag_length != 4))) { | ||
956 | continue; | ||
957 | } | ||
958 | |||
959 | /* Note that parser functions sometimes set *ptag to NULL, so | ||
960 | * the "!*ptag" check here doesn't always have the desired | ||
961 | * effect. Should the parser functions (parsegenre in | ||
962 | * particular) be updated to handle the case of being called | ||
963 | * multiple times, or should the "*ptag" check be removed? | ||
964 | */ | ||
965 | if( (!ptag || !*ptag) && !memcmp( header, tr->tag, tr->tag_length ) ) { | ||
966 | |||
967 | /* found a tag matching one in tagList, and not yet filled */ | ||
968 | tag = buffer + bufferpos; | ||
969 | |||
970 | if(global_unsynch && version <= ID3_VER_2_3) | ||
971 | bytesread = read_unsynched(fd, tag, framelen); | ||
972 | else | ||
973 | bytesread = read(fd, tag, framelen); | ||
974 | |||
975 | if( bytesread != framelen ) | ||
976 | return; | ||
977 | |||
978 | size -= bytesread; | ||
979 | |||
980 | if(unsynch || (global_unsynch && version >= ID3_VER_2_4)) | ||
981 | bytesread = unsynchronize_frame(tag, bytesread); | ||
982 | |||
983 | /* the COMM frame has a 3 char field to hold an ISO-639-1 | ||
984 | * language string and an optional short description; | ||
985 | * remove them so unicode_munge can work correctly | ||
986 | */ | ||
987 | |||
988 | if(!memcmp( header, "COMM", 4 )) { | ||
989 | int offset; | ||
990 | /* ignore comments with iTunes 7 soundcheck/gapless data */ | ||
991 | if(!strncmp(tag+4, "iTun", 4)) | ||
992 | break; | ||
993 | offset = 3 + unicode_len(*tag, tag + 4); | ||
994 | if(bytesread > offset) { | ||
995 | bytesread -= offset; | ||
996 | memmove(tag + 1, tag + 1 + offset, bytesread - 1); | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | /* Attempt to parse Unicode string only if the tag contents | ||
1001 | aren't binary */ | ||
1002 | if(!tr->binary) { | ||
1003 | /* UTF-8 could potentially be 3 times larger */ | ||
1004 | /* so we need to create a new buffer */ | ||
1005 | char utf8buf[(3 * bytesread) + 1]; | ||
1006 | |||
1007 | unicode_munge( tag, utf8buf, &bytesread ); | ||
1008 | |||
1009 | if(bytesread >= buffersize - bufferpos) | ||
1010 | bytesread = buffersize - bufferpos - 1; | ||
1011 | |||
1012 | for (j = 0; j < bytesread; j++) | ||
1013 | tag[j] = utf8buf[j]; | ||
1014 | |||
1015 | /* remove trailing spaces */ | ||
1016 | while ( bytesread > 0 && isspace(tag[bytesread-1])) | ||
1017 | bytesread--; | ||
1018 | } | ||
1019 | |||
1020 | tag[bytesread] = 0; | ||
1021 | bufferpos += bytesread + 1; | ||
1022 | |||
1023 | if (ptag) | ||
1024 | *ptag = tag; | ||
1025 | |||
1026 | if( tr->ppFunc ) | ||
1027 | bufferpos = tr->ppFunc(entry, tag, bufferpos); | ||
1028 | |||
1029 | /* Seek to the next frame */ | ||
1030 | if(framelen < totframelen) | ||
1031 | lseek(fd, totframelen - framelen, SEEK_CUR); | ||
1032 | break; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | if( i == TAGLIST_SIZE ) { | ||
1037 | /* no tag in tagList was found, or it was a repeat. | ||
1038 | skip it using the total size */ | ||
1039 | |||
1040 | if(global_unsynch && version <= ID3_VER_2_3) { | ||
1041 | size -= skip_unsynched(fd, totframelen); | ||
1042 | } else { | ||
1043 | size -= totframelen; | ||
1044 | if( lseek(fd, totframelen, SEEK_CUR) == -1 ) | ||
1045 | return; | ||
1046 | } | ||
1047 | } | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | /* | ||
1052 | * Calculates the size of the ID3v2 tag. | ||
1053 | * | ||
1054 | * Arguments: file - the file to search for a tag. | ||
1055 | * | ||
1056 | * Returns: the size of the tag or 0 if none was found | ||
1057 | */ | ||
1058 | int getid3v2len(int fd) | ||
1059 | { | ||
1060 | char buf[6]; | ||
1061 | int offset; | ||
1062 | |||
1063 | /* Make sure file has a ID3 tag */ | ||
1064 | if((-1 == lseek(fd, 0, SEEK_SET)) || | ||
1065 | (read(fd, buf, 6) != 6) || | ||
1066 | (strncmp(buf, "ID3", strlen("ID3")) != 0)) | ||
1067 | offset = 0; | ||
1068 | |||
1069 | /* Now check what the ID3v2 size field says */ | ||
1070 | else | ||
1071 | if(read(fd, buf, 4) != 4) | ||
1072 | offset = 0; | ||
1073 | else | ||
1074 | offset = unsync(buf[0], buf[1], buf[2], buf[3]) + 10; | ||
1075 | |||
1076 | logf("ID3V2 Length: 0x%x", offset); | ||
1077 | return offset; | ||
1078 | } | ||
1079 | |||
1080 | /* | ||
1081 | * Calculates the length (in milliseconds) of an MP3 file. | ||
1082 | * | ||
1083 | * Modified to only use integers. | ||
1084 | * | ||
1085 | * Arguments: file - the file to calculate the length upon | ||
1086 | * entry - the entry to update with the length | ||
1087 | * | ||
1088 | * Returns: the song length in milliseconds, | ||
1089 | * 0 means that it couldn't be calculated | ||
1090 | */ | ||
1091 | static int getsonglength(int fd, struct mp3entry *entry) | ||
1092 | { | ||
1093 | unsigned long filetime = 0; | ||
1094 | struct mp3info info; | ||
1095 | long bytecount; | ||
1096 | |||
1097 | /* Start searching after ID3v2 header */ | ||
1098 | if(-1 == lseek(fd, entry->id3v2len, SEEK_SET)) | ||
1099 | return 0; | ||
1100 | |||
1101 | bytecount = get_mp3file_info(fd, &info); | ||
1102 | |||
1103 | logf("Space between ID3V2 tag and first audio frame: 0x%lx bytes", | ||
1104 | bytecount); | ||
1105 | |||
1106 | if(bytecount < 0) | ||
1107 | return -1; | ||
1108 | |||
1109 | bytecount += entry->id3v2len; | ||
1110 | |||
1111 | /* Validate byte count, in case the file has been edited without | ||
1112 | * updating the header. | ||
1113 | */ | ||
1114 | if (info.byte_count) | ||
1115 | { | ||
1116 | const unsigned long expected = entry->filesize - entry->id3v1len | ||
1117 | - entry->id3v2len; | ||
1118 | const unsigned long diff = MAX(10240, info.byte_count / 20); | ||
1119 | |||
1120 | if ((info.byte_count > expected + diff) | ||
1121 | || (info.byte_count < expected - diff)) | ||
1122 | { | ||
1123 | logf("Note: info.byte_count differs from expected value by " | ||
1124 | "%ld bytes", labs((long) (expected - info.byte_count))); | ||
1125 | info.byte_count = 0; | ||
1126 | info.frame_count = 0; | ||
1127 | info.file_time = 0; | ||
1128 | info.enc_padding = 0; | ||
1129 | |||
1130 | /* Even if the bitrate was based on "known bad" values, it | ||
1131 | * should still be better for VBR files than using the bitrate | ||
1132 | * of the first audio frame. | ||
1133 | */ | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | entry->bitrate = info.bitrate; | ||
1138 | entry->frequency = info.frequency; | ||
1139 | entry->version = info.version; | ||
1140 | entry->layer = info.layer; | ||
1141 | switch(entry->layer) { | ||
1142 | #if CONFIG_CODEC==SWCODEC | ||
1143 | case 0: | ||
1144 | entry->codectype=AFMT_MPA_L1; | ||
1145 | break; | ||
1146 | #endif | ||
1147 | case 1: | ||
1148 | entry->codectype=AFMT_MPA_L2; | ||
1149 | break; | ||
1150 | case 2: | ||
1151 | entry->codectype=AFMT_MPA_L3; | ||
1152 | break; | ||
1153 | } | ||
1154 | |||
1155 | /* If the file time hasn't been established, this may be a fixed | ||
1156 | rate MP3, so just use the default formula */ | ||
1157 | |||
1158 | filetime = info.file_time; | ||
1159 | |||
1160 | if(filetime == 0) | ||
1161 | { | ||
1162 | /* Prevent a division by zero */ | ||
1163 | if (info.bitrate < 8) | ||
1164 | filetime = 0; | ||
1165 | else | ||
1166 | filetime = (entry->filesize - bytecount) / (info.bitrate / 8); | ||
1167 | /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8 | ||
1168 | * instead of filesize * 8 is exact, because mpeg audio bitrates are | ||
1169 | * always multiples of 8, and it avoids overflows. */ | ||
1170 | } | ||
1171 | |||
1172 | entry->frame_count = info.frame_count; | ||
1173 | |||
1174 | entry->vbr = info.is_vbr; | ||
1175 | entry->has_toc = info.has_toc; | ||
1176 | |||
1177 | #if CONFIG_CODEC==SWCODEC | ||
1178 | entry->lead_trim = info.enc_delay; | ||
1179 | entry->tail_trim = info.enc_padding; | ||
1180 | #endif | ||
1181 | |||
1182 | memcpy(entry->toc, info.toc, sizeof(info.toc)); | ||
1183 | |||
1184 | entry->vbr_header_pos = info.vbr_header_pos; | ||
1185 | |||
1186 | /* Update the seek point for the first playable frame */ | ||
1187 | entry->first_frame_offset = bytecount; | ||
1188 | logf("First frame is at %lx", entry->first_frame_offset); | ||
1189 | |||
1190 | return filetime; | ||
1191 | } | ||
1192 | |||
1193 | /* | ||
1194 | * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc) | ||
1195 | * about an MP3 file and updates it's entry accordingly. | ||
1196 | * | ||
1197 | Note, that this returns true for successful, false for error! */ | ||
1198 | bool get_mp3_metadata(int fd, struct mp3entry *entry, const char *filename) | ||
1199 | { | ||
1200 | #if CONFIG_CODEC != SWCODEC | ||
1201 | memset(entry, 0, sizeof(struct mp3entry)); | ||
1202 | #endif | ||
1203 | |||
1204 | strncpy(entry->path, filename, sizeof(entry->path)); | ||
1205 | |||
1206 | entry->title = NULL; | ||
1207 | entry->filesize = filesize(fd); | ||
1208 | entry->id3v2len = getid3v2len(fd); | ||
1209 | entry->tracknum = 0; | ||
1210 | entry->discnum = 0; | ||
1211 | |||
1212 | if (entry->id3v2len) | ||
1213 | setid3v2title(fd, entry); | ||
1214 | int len = getsonglength(fd, entry); | ||
1215 | if (len < 0) | ||
1216 | return false; | ||
1217 | entry->length = len; | ||
1218 | |||
1219 | /* Subtract the meta information from the file size to get | ||
1220 | the true size of the MP3 stream */ | ||
1221 | entry->filesize -= entry->first_frame_offset; | ||
1222 | |||
1223 | /* only seek to end of file if no id3v2 tags were found */ | ||
1224 | if (!entry->id3v2len) { | ||
1225 | setid3v1title(fd, entry); | ||
1226 | } | ||
1227 | |||
1228 | if(!entry->length || (entry->filesize < 8 )) | ||
1229 | /* no song length or less than 8 bytes is hereby considered to be an | ||
1230 | invalid mp3 and won't be played by us! */ | ||
1231 | return false; | ||
1232 | |||
1233 | return true; | ||
1234 | } | ||
1235 | |||
1236 | /* Note, that this returns false for successful, true for error! */ | ||
1237 | bool mp3info(struct mp3entry *entry, const char *filename) | ||
1238 | { | ||
1239 | int fd; | ||
1240 | bool result; | ||
1241 | |||
1242 | fd = open(filename, O_RDONLY); | ||
1243 | if (fd < 0) | ||
1244 | return true; | ||
1245 | |||
1246 | result = !get_mp3_metadata(fd, entry, filename); | ||
1247 | |||
1248 | close(fd); | ||
1249 | |||
1250 | return result; | ||
1251 | } | ||
1252 | |||
1253 | void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig) | ||
1254 | { | ||
1255 | long offset; | ||
1256 | if (orig > dest) | ||
1257 | offset = - ((size_t)orig - (size_t)dest); | ||
1258 | else | ||
1259 | offset = (size_t)dest - (size_t)orig; | ||
1260 | |||
1261 | if (entry->title) | ||
1262 | entry->title += offset; | ||
1263 | if (entry->artist) | ||
1264 | entry->artist += offset; | ||
1265 | if (entry->album) | ||
1266 | entry->album += offset; | ||
1267 | if (entry->genre_string && !id3_is_genre_string(entry->genre_string)) | ||
1268 | /* Don't adjust that if it points to an entry of the "genres" array */ | ||
1269 | entry->genre_string += offset; | ||
1270 | if (entry->track_string) | ||
1271 | entry->track_string += offset; | ||
1272 | if (entry->disc_string) | ||
1273 | entry->disc_string += offset; | ||
1274 | if (entry->year_string) | ||
1275 | entry->year_string += offset; | ||
1276 | if (entry->composer) | ||
1277 | entry->composer += offset; | ||
1278 | if (entry->comment) | ||
1279 | entry->comment += offset; | ||
1280 | if (entry->albumartist) | ||
1281 | entry->albumartist += offset; | ||
1282 | if (entry->grouping) | ||
1283 | entry->grouping += offset; | ||
1284 | #if CONFIG_CODEC == SWCODEC | ||
1285 | if (entry->track_gain_string) | ||
1286 | entry->track_gain_string += offset; | ||
1287 | if (entry->album_gain_string) | ||
1288 | entry->album_gain_string += offset; | ||
1289 | #endif | ||
1290 | if (entry->mb_track_id) | ||
1291 | entry->mb_track_id += offset; | ||
1292 | } | ||
1293 | |||
1294 | void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig) | ||
1295 | { | ||
1296 | memcpy(dest, orig, sizeof(struct mp3entry)); | ||
1297 | adjust_mp3entry(dest, dest, orig); | ||
1298 | } | ||
1299 | |||
1300 | #ifdef DEBUG_STANDALONE | ||
1301 | |||
1302 | char *secs2str(int ms) | ||
1303 | { | ||
1304 | static char buffer[32]; | ||
1305 | int secs = ms/1000; | ||
1306 | ms %= 1000; | ||
1307 | snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100); | ||
1308 | return buffer; | ||
1309 | } | ||
1310 | |||
1311 | int main(int argc, char **argv) | ||
1312 | { | ||
1313 | int i; | ||
1314 | for(i=1; i<argc; i++) { | ||
1315 | struct mp3entry mp3; | ||
1316 | mp3.album = "Bogus"; | ||
1317 | if(mp3info(&mp3, argv[i], false)) { | ||
1318 | printf("Failed to get %s\n", argv[i]); | ||
1319 | return 0; | ||
1320 | } | ||
1321 | |||
1322 | printf("****** File: %s\n" | ||
1323 | " Title: %s\n" | ||
1324 | " Artist: %s\n" | ||
1325 | " Album: %s\n" | ||
1326 | " Genre: %s (%d) \n" | ||
1327 | " Composer: %s\n" | ||
1328 | " Year: %s (%d)\n" | ||
1329 | " Track: %s (%d)\n" | ||
1330 | " Length: %s / %d s\n" | ||
1331 | " Bitrate: %d\n" | ||
1332 | " Frequency: %d\n", | ||
1333 | argv[i], | ||
1334 | mp3.title?mp3.title:"<blank>", | ||
1335 | mp3.artist?mp3.artist:"<blank>", | ||
1336 | mp3.album?mp3.album:"<blank>", | ||
1337 | mp3.genre_string?mp3.genre_string:"<blank>", | ||
1338 | mp3.genre, | ||
1339 | mp3.composer?mp3.composer:"<blank>", | ||
1340 | mp3.year_string?mp3.year_string:"<blank>", | ||
1341 | mp3.year, | ||
1342 | mp3.track_string?mp3.track_string:"<blank>", | ||
1343 | mp3.tracknum, | ||
1344 | secs2str(mp3.length), | ||
1345 | mp3.length/1000, | ||
1346 | mp3.bitrate, | ||
1347 | mp3.frequency); | ||
1348 | } | ||
1349 | |||
1350 | return 0; | ||
1351 | } | ||
1352 | |||
1353 | #endif | ||
diff --git a/firmware/mpeg.c b/firmware/mpeg.c deleted file mode 100644 index 2503ba11e0..0000000000 --- a/firmware/mpeg.c +++ /dev/null | |||
@@ -1,2872 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdbool.h> | ||
22 | #include <stdlib.h> | ||
23 | #include "config.h" | ||
24 | |||
25 | #if CONFIG_CODEC != SWCODEC | ||
26 | |||
27 | #include "debug.h" | ||
28 | #include "panic.h" | ||
29 | #include "id3.h" | ||
30 | #include "mpeg.h" | ||
31 | #include "audio.h" | ||
32 | #include "ata.h" | ||
33 | #include "string.h" | ||
34 | #include <kernel.h> | ||
35 | #include "thread.h" | ||
36 | #include "errno.h" | ||
37 | #include "mp3data.h" | ||
38 | #include "buffer.h" | ||
39 | #include "mp3_playback.h" | ||
40 | #include "sound.h" | ||
41 | #include "bitswap.h" | ||
42 | #include "events.h" | ||
43 | #ifndef SIMULATOR | ||
44 | #include "i2c.h" | ||
45 | #include "mas.h" | ||
46 | #include "dac.h" | ||
47 | #include "system.h" | ||
48 | #include "usb.h" | ||
49 | #include "file.h" | ||
50 | #include "hwcompat.h" | ||
51 | #endif /* !SIMULATOR */ | ||
52 | #ifdef HAVE_LCD_BITMAP | ||
53 | #include "lcd.h" | ||
54 | #endif | ||
55 | |||
56 | #ifndef SIMULATOR | ||
57 | extern unsigned long mas_version_code; | ||
58 | #endif | ||
59 | |||
60 | #if CONFIG_CODEC == MAS3587F | ||
61 | extern enum /* from mp3_playback.c */ | ||
62 | { | ||
63 | MPEG_DECODER, | ||
64 | MPEG_ENCODER | ||
65 | } mpeg_mode; | ||
66 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
67 | |||
68 | extern char* playlist_peek(int steps); | ||
69 | extern bool playlist_check(int steps); | ||
70 | extern int playlist_next(int steps); | ||
71 | extern int playlist_amount(void); | ||
72 | extern int playlist_update_resume_info(const struct mp3entry* id3); | ||
73 | |||
74 | #define MPEG_PLAY 1 | ||
75 | #define MPEG_STOP 2 | ||
76 | #define MPEG_PAUSE 3 | ||
77 | #define MPEG_RESUME 4 | ||
78 | #define MPEG_NEXT 5 | ||
79 | #define MPEG_PREV 6 | ||
80 | #define MPEG_FF_REWIND 7 | ||
81 | #define MPEG_FLUSH_RELOAD 8 | ||
82 | #define MPEG_RECORD 9 | ||
83 | #define MPEG_INIT_RECORDING 10 | ||
84 | #define MPEG_INIT_PLAYBACK 11 | ||
85 | #define MPEG_NEW_FILE 12 | ||
86 | #define MPEG_PAUSE_RECORDING 13 | ||
87 | #define MPEG_RESUME_RECORDING 14 | ||
88 | #define MPEG_NEED_DATA 100 | ||
89 | #define MPEG_TRACK_CHANGE 101 | ||
90 | #define MPEG_SAVE_DATA 102 | ||
91 | #define MPEG_STOP_DONE 103 | ||
92 | #define MPEG_PRERECORDING_TICK 104 | ||
93 | |||
94 | /* indicator for MPEG_NEED_DATA */ | ||
95 | #define GENERATE_UNBUFFER_EVENTS 1 | ||
96 | |||
97 | /* list of tracks in memory */ | ||
98 | #define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ | ||
99 | #define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) | ||
100 | |||
101 | struct trackdata | ||
102 | { | ||
103 | struct mp3entry id3; | ||
104 | int mempos; | ||
105 | int load_ahead_index; | ||
106 | }; | ||
107 | |||
108 | static struct trackdata trackdata[MAX_TRACK_ENTRIES]; | ||
109 | |||
110 | static unsigned int current_track_counter = 0; | ||
111 | static unsigned int last_track_counter = 0; | ||
112 | |||
113 | /* Play time of the previous track */ | ||
114 | unsigned long prev_track_elapsed; | ||
115 | |||
116 | #ifndef SIMULATOR | ||
117 | static int track_read_idx = 0; | ||
118 | static int track_write_idx = 0; | ||
119 | #endif /* !SIMULATOR */ | ||
120 | |||
121 | /* Cuesheet callback */ | ||
122 | static bool (*cuesheet_callback)(const char *filename) = NULL; | ||
123 | |||
124 | static const char mpeg_thread_name[] = "mpeg"; | ||
125 | static unsigned int mpeg_errno; | ||
126 | |||
127 | static bool playing = false; /* We are playing an MP3 stream */ | ||
128 | static bool is_playing = false; /* We are (attempting to) playing MP3 files */ | ||
129 | static bool paused; /* playback is paused */ | ||
130 | |||
131 | #ifdef SIMULATOR | ||
132 | static char mpeg_stack[DEFAULT_STACK_SIZE]; | ||
133 | static struct mp3entry taginfo; | ||
134 | |||
135 | #else /* !SIMULATOR */ | ||
136 | static struct event_queue mpeg_queue; | ||
137 | static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | ||
138 | |||
139 | static int audiobuflen; | ||
140 | static int audiobuf_write; | ||
141 | static int audiobuf_swapwrite; | ||
142 | static int audiobuf_read; | ||
143 | |||
144 | static int mpeg_file; | ||
145 | |||
146 | static bool play_pending; /* We are about to start playing */ | ||
147 | static bool play_pending_track_change; /* When starting play we're starting a new file */ | ||
148 | static bool filling; /* We are filling the buffer with data from disk */ | ||
149 | static bool dma_underrun; /* True when the DMA has stopped because of | ||
150 | slow disk reading (read error, shaking) */ | ||
151 | static bool mpeg_stop_done; | ||
152 | |||
153 | static int last_dma_tick = 0; | ||
154 | static int last_dma_chunk_size; | ||
155 | |||
156 | static long low_watermark; /* Dynamic low watermark level */ | ||
157 | static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ | ||
158 | static long lowest_watermark_level; /* Debug value to observe the buffer | ||
159 | usage */ | ||
160 | #if CONFIG_CODEC == MAS3587F | ||
161 | static char recording_filename[MAX_PATH]; /* argument to thread */ | ||
162 | static char delayed_filename[MAX_PATH]; /* internal copy of above */ | ||
163 | |||
164 | static char xing_buffer[MAX_XING_HEADER_SIZE]; | ||
165 | |||
166 | static bool init_recording_done; | ||
167 | static bool init_playback_done; | ||
168 | static bool prerecording; /* True if prerecording is enabled */ | ||
169 | static bool is_prerecording; /* True if we are prerecording */ | ||
170 | static bool is_recording; /* We are recording */ | ||
171 | |||
172 | static enum { | ||
173 | NOT_SAVING = 0, /* reasons to save data, sorted by importance */ | ||
174 | BUFFER_FULL, | ||
175 | NEW_FILE, | ||
176 | STOP_RECORDING | ||
177 | } saving_status; | ||
178 | |||
179 | static int rec_frequency_index; /* For create_xing_header() calls */ | ||
180 | static int rec_version_index; /* For create_xing_header() calls */ | ||
181 | |||
182 | struct prerecord_info { | ||
183 | int mempos; | ||
184 | unsigned long framecount; | ||
185 | }; | ||
186 | |||
187 | static struct prerecord_info prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; | ||
188 | static int prerecord_index; /* Current index in the prerecord buffer */ | ||
189 | static int prerecording_max_seconds; /* Max number of seconds to store */ | ||
190 | static int prerecord_count; /* Number of seconds in the prerecord buffer */ | ||
191 | static int prerecord_timeout; /* The tick count of the next prerecord data | ||
192 | store */ | ||
193 | |||
194 | unsigned long record_start_time; /* Value of current_tick when recording | ||
195 | was started */ | ||
196 | unsigned long pause_start_time; /* Value of current_tick when pause was | ||
197 | started */ | ||
198 | static unsigned long last_rec_time; | ||
199 | static unsigned long num_rec_bytes; | ||
200 | static unsigned long last_rec_bytes; | ||
201 | static unsigned long frame_count_start; | ||
202 | static unsigned long frame_count_end; | ||
203 | static unsigned long saved_header = 0; | ||
204 | |||
205 | /* Shadow MAS registers */ | ||
206 | unsigned long shadow_encoder_control = 0; | ||
207 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
208 | |||
209 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
210 | unsigned long shadow_io_control_main = 0; | ||
211 | unsigned long shadow_soft_mute = 0; | ||
212 | unsigned shadow_codec_reg0; | ||
213 | #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
214 | |||
215 | #ifdef HAVE_RECORDING | ||
216 | static const unsigned char empty_id3_header[] = | ||
217 | { | ||
218 | 'I', 'D', '3', 0x03, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */ | ||
220 | }; | ||
221 | #endif /* HAVE_RECORDING */ | ||
222 | |||
223 | |||
224 | static int get_unplayed_space(void); | ||
225 | static int get_playable_space(void); | ||
226 | static int get_unswapped_space(void); | ||
227 | #endif /* !SIMULATOR */ | ||
228 | |||
229 | #if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) | ||
230 | static void init_recording(void); | ||
231 | static void prepend_header(void); | ||
232 | static void update_header(void); | ||
233 | static void start_prerecording(void); | ||
234 | static void start_recording(void); | ||
235 | static void stop_recording(void); | ||
236 | static int get_unsaved_space(void); | ||
237 | static void pause_recording(void); | ||
238 | static void resume_recording(void); | ||
239 | #endif /* (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) */ | ||
240 | |||
241 | |||
242 | #ifndef SIMULATOR | ||
243 | static int num_tracks_in_memory(void) | ||
244 | { | ||
245 | return (track_write_idx - track_read_idx) & MAX_TRACK_ENTRIES_MASK; | ||
246 | } | ||
247 | |||
248 | #ifdef DEBUG_TAGS | ||
249 | static void debug_tags(void) | ||
250 | { | ||
251 | int i; | ||
252 | |||
253 | for(i = 0;i < MAX_TRACK_ENTRIES;i++) | ||
254 | { | ||
255 | DEBUGF("%d - %s\n", i, trackdata[i].id3.path); | ||
256 | } | ||
257 | DEBUGF("read: %d, write :%d\n", track_read_idx, track_write_idx); | ||
258 | DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory()); | ||
259 | } | ||
260 | #else /* !DEBUG_TAGS */ | ||
261 | #define debug_tags() | ||
262 | #endif /* !DEBUG_TAGS */ | ||
263 | |||
264 | static void remove_current_tag(void) | ||
265 | { | ||
266 | if(num_tracks_in_memory() > 0) | ||
267 | { | ||
268 | /* First move the index, so nobody tries to access the tag */ | ||
269 | track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
270 | debug_tags(); | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | DEBUGF("remove_current_tag: no tracks to remove\n"); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | static void remove_all_non_current_tags(void) | ||
279 | { | ||
280 | track_write_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
281 | debug_tags(); | ||
282 | } | ||
283 | |||
284 | static void remove_all_tags(void) | ||
285 | { | ||
286 | track_write_idx = track_read_idx; | ||
287 | |||
288 | debug_tags(); | ||
289 | } | ||
290 | |||
291 | static struct trackdata *get_trackdata(int offset) | ||
292 | { | ||
293 | if(offset >= num_tracks_in_memory()) | ||
294 | return NULL; | ||
295 | else | ||
296 | return &trackdata[(track_read_idx + offset) & MAX_TRACK_ENTRIES_MASK]; | ||
297 | } | ||
298 | #endif /* !SIMULATOR */ | ||
299 | |||
300 | /***********************************************************************/ | ||
301 | /* audio event handling */ | ||
302 | |||
303 | #define MAX_EVENT_HANDLERS 10 | ||
304 | struct event_handlers_table | ||
305 | { | ||
306 | AUDIO_EVENT_HANDLER handler; | ||
307 | unsigned short mask; | ||
308 | }; | ||
309 | static struct event_handlers_table event_handlers[MAX_EVENT_HANDLERS]; | ||
310 | static int event_handlers_count = 0; | ||
311 | |||
312 | void audio_register_event_handler(AUDIO_EVENT_HANDLER handler, unsigned short mask) | ||
313 | { | ||
314 | if (event_handlers_count < MAX_EVENT_HANDLERS) | ||
315 | { | ||
316 | event_handlers[event_handlers_count].handler = handler; | ||
317 | event_handlers[event_handlers_count].mask = mask; | ||
318 | event_handlers_count++; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | /* dispatch calls each handler in the order registered and returns after some | ||
323 | handler actually handles the event (the event is assumed to no longer be valid | ||
324 | after this, due to the handler changing some condition); returns true if someone | ||
325 | handled the event, which is expected to cause the caller to skip its own handling | ||
326 | of the event */ | ||
327 | #ifndef SIMULATOR | ||
328 | static bool audio_dispatch_event(unsigned short event, unsigned long data) | ||
329 | { | ||
330 | int i = 0; | ||
331 | for(i=0; i < event_handlers_count; i++) | ||
332 | { | ||
333 | if ( event_handlers[i].mask & event ) | ||
334 | { | ||
335 | int rc = event_handlers[i].handler(event, data); | ||
336 | if ( rc == AUDIO_EVENT_RC_HANDLED ) | ||
337 | return true; | ||
338 | } | ||
339 | } | ||
340 | return false; | ||
341 | } | ||
342 | #endif | ||
343 | |||
344 | /***********************************************************************/ | ||
345 | |||
346 | static void set_elapsed(struct mp3entry* id3) | ||
347 | { | ||
348 | if ( id3->vbr ) { | ||
349 | if ( id3->has_toc ) { | ||
350 | /* calculate elapsed time using TOC */ | ||
351 | int i; | ||
352 | unsigned int remainder, plen, relpos, nextpos; | ||
353 | |||
354 | /* find wich percent we're at */ | ||
355 | for (i=0; i<100; i++ ) | ||
356 | { | ||
357 | if ( id3->offset < id3->toc[i] * (id3->filesize / 256) ) | ||
358 | { | ||
359 | break; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | i--; | ||
364 | if (i < 0) | ||
365 | i = 0; | ||
366 | |||
367 | relpos = id3->toc[i]; | ||
368 | |||
369 | if (i < 99) | ||
370 | { | ||
371 | nextpos = id3->toc[i+1]; | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | nextpos = 256; | ||
376 | } | ||
377 | |||
378 | remainder = id3->offset - (relpos * (id3->filesize / 256)); | ||
379 | |||
380 | /* set time for this percent (divide before multiply to prevent | ||
381 | overflow on long files. loss of precision is negligible on | ||
382 | short files) */ | ||
383 | id3->elapsed = i * (id3->length / 100); | ||
384 | |||
385 | /* calculate remainder time */ | ||
386 | plen = (nextpos - relpos) * (id3->filesize / 256); | ||
387 | id3->elapsed += (((remainder * 100) / plen) * | ||
388 | (id3->length / 10000)); | ||
389 | } | ||
390 | else { | ||
391 | /* no TOC exists. set a rough estimate using average bitrate */ | ||
392 | int tpk = id3->length / (id3->filesize / 1024); | ||
393 | id3->elapsed = id3->offset / 1024 * tpk; | ||
394 | } | ||
395 | } | ||
396 | else | ||
397 | /* constant bitrate, use exact calculation */ | ||
398 | id3->elapsed = id3->offset / (id3->bitrate / 8); | ||
399 | } | ||
400 | |||
401 | int audio_get_file_pos(void) | ||
402 | { | ||
403 | int pos = -1; | ||
404 | struct mp3entry *id3 = audio_current_track(); | ||
405 | |||
406 | if (id3->vbr) | ||
407 | { | ||
408 | if (id3->has_toc) | ||
409 | { | ||
410 | /* Use the TOC to find the new position */ | ||
411 | unsigned int percent, remainder; | ||
412 | int curtoc, nexttoc, plen; | ||
413 | |||
414 | percent = (id3->elapsed*100)/id3->length; | ||
415 | if (percent > 99) | ||
416 | percent = 99; | ||
417 | |||
418 | curtoc = id3->toc[percent]; | ||
419 | |||
420 | if (percent < 99) | ||
421 | nexttoc = id3->toc[percent+1]; | ||
422 | else | ||
423 | nexttoc = 256; | ||
424 | |||
425 | pos = (id3->filesize/256)*curtoc; | ||
426 | |||
427 | /* Use the remainder to get a more accurate position */ | ||
428 | remainder = (id3->elapsed*100)%id3->length; | ||
429 | remainder = (remainder*100)/id3->length; | ||
430 | plen = (nexttoc - curtoc)*(id3->filesize/256); | ||
431 | pos += (plen/100)*remainder; | ||
432 | } | ||
433 | else | ||
434 | { | ||
435 | /* No TOC exists, estimate the new position */ | ||
436 | pos = (id3->filesize / (id3->length / 1000)) * | ||
437 | (id3->elapsed / 1000); | ||
438 | } | ||
439 | } | ||
440 | else if (id3->bitrate) | ||
441 | pos = id3->elapsed * (id3->bitrate / 8); | ||
442 | else | ||
443 | { | ||
444 | return -1; | ||
445 | } | ||
446 | |||
447 | if (pos >= (int)(id3->filesize - id3->id3v1len)) | ||
448 | { | ||
449 | /* Don't seek right to the end of the file so that we can | ||
450 | transition properly to the next song */ | ||
451 | pos = id3->filesize - id3->id3v1len - 1; | ||
452 | } | ||
453 | else if (pos < (int)id3->first_frame_offset) | ||
454 | { | ||
455 | /* skip past id3v2 tag and other leading garbage */ | ||
456 | pos = id3->first_frame_offset; | ||
457 | } | ||
458 | return pos; | ||
459 | } | ||
460 | |||
461 | unsigned long mpeg_get_last_header(void) | ||
462 | { | ||
463 | #ifdef SIMULATOR | ||
464 | return 0; | ||
465 | #else /* !SIMULATOR */ | ||
466 | unsigned long tmp[2]; | ||
467 | |||
468 | /* Read the frame data from the MAS and reconstruct it with the | ||
469 | frame sync and all */ | ||
470 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_STATUS_1, tmp, 2); | ||
471 | return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff); | ||
472 | #endif /* !SIMULATOR */ | ||
473 | } | ||
474 | |||
475 | void audio_set_cuesheet_callback(bool (*handler)(const char *filename)) | ||
476 | { | ||
477 | cuesheet_callback = handler; | ||
478 | } | ||
479 | |||
480 | #ifndef SIMULATOR | ||
481 | /* Send callback events to notify about removing old tracks. */ | ||
482 | static void generate_unbuffer_events(void) | ||
483 | { | ||
484 | int i; | ||
485 | int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory(); | ||
486 | int cur_idx = track_write_idx; | ||
487 | |||
488 | for (i = 0; i < numentries; i++) | ||
489 | { | ||
490 | /* Send an event to notify that track has finished. */ | ||
491 | send_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3); | ||
492 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | /* Send callback events to notify about new tracks. */ | ||
497 | static void generate_postbuffer_events(void) | ||
498 | { | ||
499 | int i; | ||
500 | int numentries = num_tracks_in_memory(); | ||
501 | int cur_idx = track_read_idx; | ||
502 | |||
503 | for (i = 0; i < numentries; i++) | ||
504 | { | ||
505 | send_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3); | ||
506 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | static void recalculate_watermark(int bitrate) | ||
511 | { | ||
512 | int bytes_per_sec; | ||
513 | int time = ata_spinup_time; | ||
514 | |||
515 | /* A bitrate of 0 probably means empty VBR header. We play safe | ||
516 | and set a high threshold */ | ||
517 | if(bitrate == 0) | ||
518 | bitrate = 320; | ||
519 | |||
520 | bytes_per_sec = bitrate * 1000 / 8; | ||
521 | |||
522 | if(time) | ||
523 | { | ||
524 | /* No drive spins up faster than 3.5s */ | ||
525 | if(time < 350) | ||
526 | time = 350; | ||
527 | |||
528 | time = time * 3; | ||
529 | low_watermark = ((low_watermark_margin * HZ + time) * | ||
530 | bytes_per_sec) / HZ; | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | low_watermark = MPEG_LOW_WATER; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | #ifdef HAVE_DISK_STORAGE | ||
539 | void audio_set_buffer_margin(int seconds) | ||
540 | { | ||
541 | low_watermark_margin = seconds; | ||
542 | } | ||
543 | #endif | ||
544 | |||
545 | void audio_get_debugdata(struct audio_debug *dbgdata) | ||
546 | { | ||
547 | dbgdata->audiobuflen = audiobuflen; | ||
548 | dbgdata->audiobuf_write = audiobuf_write; | ||
549 | dbgdata->audiobuf_swapwrite = audiobuf_swapwrite; | ||
550 | dbgdata->audiobuf_read = audiobuf_read; | ||
551 | |||
552 | dbgdata->last_dma_chunk_size = last_dma_chunk_size; | ||
553 | |||
554 | #if CONFIG_CPU == SH7034 | ||
555 | dbgdata->dma_on = (SCR0 & 0x80) != 0; | ||
556 | #endif | ||
557 | dbgdata->playing = playing; | ||
558 | dbgdata->play_pending = play_pending; | ||
559 | dbgdata->is_playing = is_playing; | ||
560 | dbgdata->filling = filling; | ||
561 | dbgdata->dma_underrun = dma_underrun; | ||
562 | |||
563 | dbgdata->unplayed_space = get_unplayed_space(); | ||
564 | dbgdata->playable_space = get_playable_space(); | ||
565 | dbgdata->unswapped_space = get_unswapped_space(); | ||
566 | |||
567 | dbgdata->low_watermark_level = low_watermark; | ||
568 | dbgdata->lowest_watermark_level = lowest_watermark_level; | ||
569 | } | ||
570 | |||
571 | #ifdef DEBUG | ||
572 | static void dbg_timer_start(void) | ||
573 | { | ||
574 | /* We are using timer 2 */ | ||
575 | |||
576 | TSTR &= ~0x04; /* Stop the timer */ | ||
577 | TSNC &= ~0x04; /* No synchronization */ | ||
578 | TMDR &= ~0x44; /* Operate normally */ | ||
579 | |||
580 | TCNT2 = 0; /* Start counting at 0 */ | ||
581 | TCR2 = 0x03; /* Sysclock/8 */ | ||
582 | |||
583 | TSTR |= 0x04; /* Start timer 2 */ | ||
584 | } | ||
585 | |||
586 | static int dbg_cnt2us(unsigned int cnt) | ||
587 | { | ||
588 | return (cnt * 10000) / (FREQ/800); | ||
589 | } | ||
590 | #endif /* DEBUG */ | ||
591 | |||
592 | static int get_unplayed_space(void) | ||
593 | { | ||
594 | int space = audiobuf_write - audiobuf_read; | ||
595 | if (space < 0) | ||
596 | space += audiobuflen; | ||
597 | return space; | ||
598 | } | ||
599 | |||
600 | static int get_playable_space(void) | ||
601 | { | ||
602 | int space = audiobuf_swapwrite - audiobuf_read; | ||
603 | if (space < 0) | ||
604 | space += audiobuflen; | ||
605 | return space; | ||
606 | } | ||
607 | |||
608 | static int get_unplayed_space_current_song(void) | ||
609 | { | ||
610 | int space; | ||
611 | |||
612 | if (num_tracks_in_memory() > 1) | ||
613 | { | ||
614 | space = get_trackdata(1)->mempos - audiobuf_read; | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | space = audiobuf_write - audiobuf_read; | ||
619 | } | ||
620 | |||
621 | if (space < 0) | ||
622 | space += audiobuflen; | ||
623 | |||
624 | return space; | ||
625 | } | ||
626 | |||
627 | static int get_unswapped_space(void) | ||
628 | { | ||
629 | int space = audiobuf_write - audiobuf_swapwrite; | ||
630 | if (space < 0) | ||
631 | space += audiobuflen; | ||
632 | return space; | ||
633 | } | ||
634 | |||
635 | #if CONFIG_CODEC == MAS3587F | ||
636 | static int get_unsaved_space(void) | ||
637 | { | ||
638 | int space = audiobuf_write - audiobuf_read; | ||
639 | if (space < 0) | ||
640 | space += audiobuflen; | ||
641 | return space; | ||
642 | } | ||
643 | |||
644 | static void drain_dma_buffer(void) | ||
645 | { | ||
646 | while (PBDRH & 0x40) | ||
647 | { | ||
648 | xor_b(0x08, &PADRH); | ||
649 | |||
650 | while (PBDRH & 0x80); | ||
651 | |||
652 | xor_b(0x08, &PADRH); | ||
653 | |||
654 | while (!(PBDRH & 0x80)); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | #ifdef DEBUG | ||
659 | static long timing_info_index = 0; | ||
660 | static long timing_info[1024]; | ||
661 | #endif /* DEBUG */ | ||
662 | |||
663 | void rec_tick (void) __attribute__ ((section (".icode"))); | ||
664 | void rec_tick(void) | ||
665 | { | ||
666 | int i; | ||
667 | int delay; | ||
668 | char data; | ||
669 | |||
670 | if(is_recording && (PBDRH & 0x40)) | ||
671 | { | ||
672 | #ifdef DEBUG | ||
673 | timing_info[timing_info_index++] = current_tick; | ||
674 | TCNT2 = 0; | ||
675 | #endif /* DEBUG */ | ||
676 | /* Note: Although this loop is run in interrupt context, further | ||
677 | * optimisation will do no good. The MAS would then deliver bad | ||
678 | * frames occasionally, as observed in extended experiments. */ | ||
679 | i = 0; | ||
680 | while (PBDRH & 0x40) /* We try to read as long as EOD is high */ | ||
681 | { | ||
682 | xor_b(0x08, &PADRH); /* Set PR active, independent of polarity */ | ||
683 | |||
684 | delay = 100; | ||
685 | while (PBDRH & 0x80) /* Wait until /RTW becomes active */ | ||
686 | { | ||
687 | if (--delay <= 0) /* Bail out if we have to wait too long */ | ||
688 | { /* i.e. the MAS doesn't want to talk to us */ | ||
689 | xor_b(0x08, &PADRH); /* Set PR inactive */ | ||
690 | goto transfer_end; /* and get out of here */ | ||
691 | } | ||
692 | } | ||
693 | |||
694 | data = *(unsigned char *)0x04000000; /* read data byte */ | ||
695 | |||
696 | xor_b(0x08, &PADRH); /* Set PR inactive */ | ||
697 | |||
698 | audiobuf[audiobuf_write++] = data; | ||
699 | |||
700 | if (audiobuf_write >= audiobuflen) | ||
701 | audiobuf_write = 0; | ||
702 | |||
703 | i++; | ||
704 | } | ||
705 | transfer_end: | ||
706 | |||
707 | #ifdef DEBUG | ||
708 | timing_info[timing_info_index++] = TCNT2 + (i << 16); | ||
709 | timing_info_index &= 0x3ff; | ||
710 | #endif /* DEBUG */ | ||
711 | |||
712 | num_rec_bytes += i; | ||
713 | |||
714 | if(is_prerecording) | ||
715 | { | ||
716 | if(TIME_AFTER(current_tick, prerecord_timeout)) | ||
717 | { | ||
718 | prerecord_timeout = current_tick + HZ; | ||
719 | queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); | ||
720 | } | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | /* Signal to save the data if we are running out of buffer | ||
725 | space */ | ||
726 | if (audiobuflen - get_unsaved_space() < MPEG_RECORDING_LOW_WATER | ||
727 | && saving_status == NOT_SAVING) | ||
728 | { | ||
729 | saving_status = BUFFER_FULL; | ||
730 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
736 | |||
737 | void playback_tick(void) | ||
738 | { | ||
739 | struct trackdata *ptd = get_trackdata(0); | ||
740 | if(ptd) | ||
741 | { | ||
742 | ptd->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; | ||
743 | last_dma_tick = current_tick; | ||
744 | audio_dispatch_event(AUDIO_EVENT_POS_REPORT, | ||
745 | (unsigned long)ptd->id3.elapsed); | ||
746 | } | ||
747 | } | ||
748 | |||
749 | static void reset_mp3_buffer(void) | ||
750 | { | ||
751 | audiobuf_read = 0; | ||
752 | audiobuf_write = 0; | ||
753 | audiobuf_swapwrite = 0; | ||
754 | lowest_watermark_level = audiobuflen; | ||
755 | } | ||
756 | |||
757 | /* DMA transfer end interrupt callback */ | ||
758 | static void transfer_end(unsigned char** ppbuf, size_t* psize) | ||
759 | { | ||
760 | if(playing && !paused) | ||
761 | { | ||
762 | int unplayed_space_left; | ||
763 | int space_until_end_of_buffer; | ||
764 | int track_offset = 1; | ||
765 | struct trackdata *track; | ||
766 | |||
767 | audiobuf_read += last_dma_chunk_size; | ||
768 | if(audiobuf_read >= audiobuflen) | ||
769 | audiobuf_read = 0; | ||
770 | |||
771 | /* First, check if we are on a track boundary */ | ||
772 | if (num_tracks_in_memory() > 1) | ||
773 | { | ||
774 | if (audiobuf_read == get_trackdata(track_offset)->mempos) | ||
775 | { | ||
776 | if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) | ||
777 | { | ||
778 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
779 | track_offset++; | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | |||
784 | unplayed_space_left = get_unplayed_space(); | ||
785 | |||
786 | space_until_end_of_buffer = audiobuflen - audiobuf_read; | ||
787 | |||
788 | if(!filling && unplayed_space_left < low_watermark) | ||
789 | { | ||
790 | filling = true; | ||
791 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
792 | } | ||
793 | |||
794 | if(unplayed_space_left) | ||
795 | { | ||
796 | last_dma_chunk_size = MIN(0x2000, unplayed_space_left); | ||
797 | last_dma_chunk_size = MIN(last_dma_chunk_size, | ||
798 | space_until_end_of_buffer); | ||
799 | |||
800 | /* several tracks loaded? */ | ||
801 | track = get_trackdata(track_offset); | ||
802 | if(track) | ||
803 | { | ||
804 | /* will we move across the track boundary? */ | ||
805 | if (( audiobuf_read < track->mempos ) && | ||
806 | ((audiobuf_read+last_dma_chunk_size) > | ||
807 | track->mempos )) | ||
808 | { | ||
809 | /* Make sure that we end exactly on the boundary */ | ||
810 | last_dma_chunk_size = track->mempos - audiobuf_read; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | *psize = last_dma_chunk_size & 0xffff; | ||
815 | *ppbuf = audiobuf + audiobuf_read; | ||
816 | track = get_trackdata(0); | ||
817 | if(track) | ||
818 | track->id3.offset += last_dma_chunk_size; | ||
819 | |||
820 | /* Update the watermark debug level */ | ||
821 | if(unplayed_space_left < lowest_watermark_level) | ||
822 | lowest_watermark_level = unplayed_space_left; | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | /* Check if the end of data is because of a hard disk error. | ||
827 | If there is an open file handle, we are still playing music. | ||
828 | If not, the last file has been loaded, and the file handle is | ||
829 | closed. */ | ||
830 | if(mpeg_file >= 0) | ||
831 | { | ||
832 | /* Update the watermark debug level */ | ||
833 | if(unplayed_space_left < lowest_watermark_level) | ||
834 | lowest_watermark_level = unplayed_space_left; | ||
835 | |||
836 | DEBUGF("DMA underrun.\n"); | ||
837 | dma_underrun = true; | ||
838 | } | ||
839 | else | ||
840 | { | ||
841 | if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) | ||
842 | { | ||
843 | DEBUGF("No more MP3 data. Stopping.\n"); | ||
844 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
845 | playing = false; | ||
846 | } | ||
847 | } | ||
848 | *psize = 0; /* no more transfer */ | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | |||
853 | static struct trackdata *add_track_to_tag_list(const char *filename) | ||
854 | { | ||
855 | struct trackdata *track; | ||
856 | |||
857 | if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES) | ||
858 | { | ||
859 | DEBUGF("Tag memory is full\n"); | ||
860 | return NULL; | ||
861 | } | ||
862 | |||
863 | track = &trackdata[track_write_idx]; | ||
864 | |||
865 | /* grab id3 tag of new file and | ||
866 | remember where in memory it starts */ | ||
867 | if(mp3info(&track->id3, filename)) | ||
868 | { | ||
869 | DEBUGF("Bad mp3\n"); | ||
870 | return NULL; | ||
871 | } | ||
872 | track->mempos = audiobuf_write; | ||
873 | track->id3.elapsed = 0; | ||
874 | #ifdef HAVE_LCD_BITMAP | ||
875 | if (track->id3.title) | ||
876 | lcd_getstringsize(track->id3.title, NULL, NULL); | ||
877 | if (track->id3.artist) | ||
878 | lcd_getstringsize(track->id3.artist, NULL, NULL); | ||
879 | if (track->id3.album) | ||
880 | lcd_getstringsize(track->id3.album, NULL, NULL); | ||
881 | #endif | ||
882 | if (cuesheet_callback) | ||
883 | if (cuesheet_callback(filename)) | ||
884 | track->id3.cuesheet_type = 1; | ||
885 | |||
886 | track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
887 | debug_tags(); | ||
888 | return track; | ||
889 | } | ||
890 | |||
891 | static int new_file(int steps) | ||
892 | { | ||
893 | int max_steps = playlist_amount(); | ||
894 | int start = 0; | ||
895 | int i; | ||
896 | struct trackdata *track; | ||
897 | |||
898 | /* Find out how many steps to advance. The load_ahead_index field tells | ||
899 | us how many playlist entries it had to skip to get to a valid one. | ||
900 | We add those together to find out where to start. */ | ||
901 | if(steps > 0 && num_tracks_in_memory() > 1) | ||
902 | { | ||
903 | /* Begin with the song after the currently playing one */ | ||
904 | i = 1; | ||
905 | while((track = get_trackdata(i++))) | ||
906 | { | ||
907 | start += track->load_ahead_index; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | do { | ||
912 | char *trackname; | ||
913 | |||
914 | trackname = playlist_peek( start + steps ); | ||
915 | if ( !trackname ) | ||
916 | return -1; | ||
917 | |||
918 | DEBUGF("Loading %s\n", trackname); | ||
919 | |||
920 | mpeg_file = open(trackname, O_RDONLY); | ||
921 | if(mpeg_file < 0) { | ||
922 | DEBUGF("Couldn't open file: %s\n",trackname); | ||
923 | if(steps < 0) | ||
924 | steps--; | ||
925 | else | ||
926 | steps++; | ||
927 | } | ||
928 | else | ||
929 | { | ||
930 | struct trackdata *track = add_track_to_tag_list(trackname); | ||
931 | |||
932 | if(!track) | ||
933 | { | ||
934 | /* Bad mp3 file */ | ||
935 | if(steps < 0) | ||
936 | steps--; | ||
937 | else | ||
938 | steps++; | ||
939 | close(mpeg_file); | ||
940 | mpeg_file = -1; | ||
941 | } | ||
942 | else | ||
943 | { | ||
944 | /* skip past id3v2 tag */ | ||
945 | lseek(mpeg_file, | ||
946 | track->id3.first_frame_offset, | ||
947 | SEEK_SET); | ||
948 | track->id3.index = steps; | ||
949 | track->load_ahead_index = steps; | ||
950 | track->id3.offset = 0; | ||
951 | |||
952 | if(track->id3.vbr) | ||
953 | /* Average bitrate * 1.5 */ | ||
954 | recalculate_watermark( | ||
955 | (track->id3.bitrate * 3) / 2); | ||
956 | else | ||
957 | recalculate_watermark( | ||
958 | track->id3.bitrate); | ||
959 | |||
960 | } | ||
961 | } | ||
962 | |||
963 | /* Bail out if no file could be opened */ | ||
964 | if(abs(steps) > max_steps) | ||
965 | return -1; | ||
966 | } while ( mpeg_file < 0 ); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static void stop_playing(void) | ||
972 | { | ||
973 | struct trackdata *track; | ||
974 | |||
975 | /* Stop the current stream */ | ||
976 | mp3_play_stop(); | ||
977 | playing = false; | ||
978 | filling = false; | ||
979 | |||
980 | track = get_trackdata(0); | ||
981 | if (track != NULL) | ||
982 | prev_track_elapsed = track->id3.elapsed; | ||
983 | |||
984 | if(mpeg_file >= 0) | ||
985 | close(mpeg_file); | ||
986 | mpeg_file = -1; | ||
987 | remove_all_tags(); | ||
988 | generate_unbuffer_events(); | ||
989 | reset_mp3_buffer(); | ||
990 | } | ||
991 | |||
992 | static void end_current_track(void) { | ||
993 | struct trackdata *track; | ||
994 | |||
995 | play_pending = false; | ||
996 | playing = false; | ||
997 | mp3_play_pause(false); | ||
998 | |||
999 | track = get_trackdata(0); | ||
1000 | if (track != NULL) | ||
1001 | prev_track_elapsed = track->id3.elapsed; | ||
1002 | |||
1003 | reset_mp3_buffer(); | ||
1004 | remove_all_tags(); | ||
1005 | generate_unbuffer_events(); | ||
1006 | |||
1007 | if(mpeg_file >= 0) | ||
1008 | close(mpeg_file); | ||
1009 | } | ||
1010 | |||
1011 | /* Is this a really the end of playback or is a new playlist starting */ | ||
1012 | static void check_playlist_end(int direction) | ||
1013 | { | ||
1014 | /* Use the largest possible step size to account for skipped tracks */ | ||
1015 | int steps = playlist_amount(); | ||
1016 | |||
1017 | if (direction < 0) | ||
1018 | steps = -steps; | ||
1019 | |||
1020 | if (playlist_next(steps) < 0) | ||
1021 | is_playing = false; | ||
1022 | } | ||
1023 | |||
1024 | static void update_playlist(void) | ||
1025 | { | ||
1026 | if (num_tracks_in_memory() > 0) | ||
1027 | { | ||
1028 | struct trackdata *track = get_trackdata(0); | ||
1029 | track->id3.index = playlist_next(track->id3.index); | ||
1030 | } | ||
1031 | else | ||
1032 | { | ||
1033 | /* End of playlist? */ | ||
1034 | check_playlist_end(1); | ||
1035 | } | ||
1036 | |||
1037 | playlist_update_resume_info(audio_current_track()); | ||
1038 | } | ||
1039 | |||
1040 | static void track_change(void) | ||
1041 | { | ||
1042 | DEBUGF("Track change\n"); | ||
1043 | |||
1044 | struct trackdata *track = get_trackdata(0); | ||
1045 | prev_track_elapsed = track->id3.elapsed; | ||
1046 | |||
1047 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
1048 | /* Reset the AVC */ | ||
1049 | sound_set_avc(-1); | ||
1050 | #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
1051 | |||
1052 | if (num_tracks_in_memory() > 0) | ||
1053 | { | ||
1054 | remove_current_tag(); | ||
1055 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track()); | ||
1056 | update_playlist(); | ||
1057 | } | ||
1058 | |||
1059 | current_track_counter++; | ||
1060 | } | ||
1061 | |||
1062 | unsigned long audio_prev_elapsed(void) | ||
1063 | { | ||
1064 | return prev_track_elapsed; | ||
1065 | } | ||
1066 | |||
1067 | #ifdef DEBUG | ||
1068 | void hexdump(const unsigned char *buf, int len) | ||
1069 | { | ||
1070 | int i; | ||
1071 | |||
1072 | for(i = 0;i < len;i++) | ||
1073 | { | ||
1074 | if(i && (i & 15) == 0) | ||
1075 | { | ||
1076 | DEBUGF("\n"); | ||
1077 | } | ||
1078 | DEBUGF("%02x ", buf[i]); | ||
1079 | } | ||
1080 | DEBUGF("\n"); | ||
1081 | } | ||
1082 | #endif /* DEBUG */ | ||
1083 | |||
1084 | static void start_playback_if_ready(void) | ||
1085 | { | ||
1086 | int playable_space; | ||
1087 | |||
1088 | playable_space = audiobuf_swapwrite - audiobuf_read; | ||
1089 | if(playable_space < 0) | ||
1090 | playable_space += audiobuflen; | ||
1091 | |||
1092 | /* See if we have started playing yet. If not, do it. */ | ||
1093 | if(play_pending || dma_underrun) | ||
1094 | { | ||
1095 | /* If the filling has stopped, and we still haven't reached | ||
1096 | the watermark, the file must be smaller than the | ||
1097 | watermark. We must still play it. */ | ||
1098 | if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) || | ||
1099 | !filling || dma_underrun) | ||
1100 | { | ||
1101 | DEBUGF("P\n"); | ||
1102 | if (play_pending) /* don't do this when recovering from DMA underrun */ | ||
1103 | { | ||
1104 | generate_postbuffer_events(); /* signal first track as buffered */ | ||
1105 | if (play_pending_track_change) | ||
1106 | { | ||
1107 | play_pending_track_change = false; | ||
1108 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track()); | ||
1109 | } | ||
1110 | play_pending = false; | ||
1111 | } | ||
1112 | playing = true; | ||
1113 | |||
1114 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | ||
1115 | mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | ||
1116 | dma_underrun = false; | ||
1117 | |||
1118 | if (!paused) | ||
1119 | { | ||
1120 | last_dma_tick = current_tick; | ||
1121 | mp3_play_pause(true); | ||
1122 | } | ||
1123 | |||
1124 | /* Tell ourselves that we need more data */ | ||
1125 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1126 | } | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | static bool swap_one_chunk(void) | ||
1131 | { | ||
1132 | int free_space_left; | ||
1133 | int amount_to_swap; | ||
1134 | |||
1135 | free_space_left = get_unswapped_space(); | ||
1136 | |||
1137 | if(free_space_left == 0 && !play_pending) | ||
1138 | return false; | ||
1139 | |||
1140 | /* Swap in larger chunks when the user is waiting for the playback | ||
1141 | to start, or when there is dangerously little playable data left */ | ||
1142 | if(play_pending) | ||
1143 | amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left); | ||
1144 | else | ||
1145 | { | ||
1146 | if(get_playable_space() < low_watermark) | ||
1147 | amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE, | ||
1148 | free_space_left); | ||
1149 | else | ||
1150 | amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left); | ||
1151 | } | ||
1152 | |||
1153 | if(audiobuf_write < audiobuf_swapwrite) | ||
1154 | amount_to_swap = MIN(audiobuflen - audiobuf_swapwrite, | ||
1155 | amount_to_swap); | ||
1156 | else | ||
1157 | amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite, | ||
1158 | amount_to_swap); | ||
1159 | |||
1160 | bitswap(audiobuf + audiobuf_swapwrite, amount_to_swap); | ||
1161 | |||
1162 | audiobuf_swapwrite += amount_to_swap; | ||
1163 | if(audiobuf_swapwrite >= audiobuflen) | ||
1164 | { | ||
1165 | audiobuf_swapwrite = 0; | ||
1166 | } | ||
1167 | |||
1168 | return true; | ||
1169 | } | ||
1170 | |||
1171 | static void mpeg_thread(void) | ||
1172 | { | ||
1173 | static int pause_tick = 0; | ||
1174 | static unsigned int pause_track = 0; | ||
1175 | struct queue_event ev; | ||
1176 | int len; | ||
1177 | int free_space_left; | ||
1178 | int unplayed_space_left; | ||
1179 | int amount_to_read; | ||
1180 | int t1, t2; | ||
1181 | int start_offset; | ||
1182 | #if CONFIG_CODEC == MAS3587F | ||
1183 | int amount_to_save; | ||
1184 | int save_endpos = 0; | ||
1185 | int rc; | ||
1186 | int level; | ||
1187 | long offset; | ||
1188 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
1189 | |||
1190 | is_playing = false; | ||
1191 | play_pending = false; | ||
1192 | playing = false; | ||
1193 | mpeg_file = -1; | ||
1194 | |||
1195 | while(1) | ||
1196 | { | ||
1197 | #if CONFIG_CODEC == MAS3587F | ||
1198 | if(mpeg_mode == MPEG_DECODER) | ||
1199 | { | ||
1200 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
1201 | yield(); | ||
1202 | |||
1203 | /* Swap if necessary, and don't block on the queue_wait() */ | ||
1204 | if(swap_one_chunk()) | ||
1205 | { | ||
1206 | queue_wait_w_tmo(&mpeg_queue, &ev, 0); | ||
1207 | } | ||
1208 | else if (playing) | ||
1209 | { | ||
1210 | /* periodically update resume info */ | ||
1211 | queue_wait_w_tmo(&mpeg_queue, &ev, HZ/2); | ||
1212 | } | ||
1213 | else | ||
1214 | { | ||
1215 | DEBUGF("S R:%x W:%x SW:%x\n", | ||
1216 | audiobuf_read, audiobuf_write, audiobuf_swapwrite); | ||
1217 | queue_wait(&mpeg_queue, &ev); | ||
1218 | } | ||
1219 | |||
1220 | start_playback_if_ready(); | ||
1221 | |||
1222 | switch(ev.id) | ||
1223 | { | ||
1224 | case MPEG_PLAY: | ||
1225 | DEBUGF("MPEG_PLAY\n"); | ||
1226 | |||
1227 | #if CONFIG_TUNER | ||
1228 | /* Silence the A/D input, it may be on because the radio | ||
1229 | may be playing */ | ||
1230 | mas_codec_writereg(6, 0x0000); | ||
1231 | #endif /* CONFIG_TUNER */ | ||
1232 | |||
1233 | /* Stop the current stream */ | ||
1234 | paused = false; | ||
1235 | end_current_track(); | ||
1236 | |||
1237 | if ( new_file(0) == -1 ) | ||
1238 | { | ||
1239 | is_playing = false; | ||
1240 | track_change(); | ||
1241 | break; | ||
1242 | } | ||
1243 | |||
1244 | start_offset = (int)ev.data; | ||
1245 | |||
1246 | /* mid-song resume? */ | ||
1247 | if (start_offset) { | ||
1248 | struct mp3entry* id3 = &get_trackdata(0)->id3; | ||
1249 | lseek(mpeg_file, start_offset, SEEK_SET); | ||
1250 | id3->offset = start_offset; | ||
1251 | set_elapsed(id3); | ||
1252 | } | ||
1253 | else { | ||
1254 | /* skip past id3v2 tag */ | ||
1255 | lseek(mpeg_file, | ||
1256 | get_trackdata(0)->id3.first_frame_offset, | ||
1257 | SEEK_SET); | ||
1258 | |||
1259 | } | ||
1260 | |||
1261 | /* Make it read more data */ | ||
1262 | filling = true; | ||
1263 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1264 | |||
1265 | /* Tell the file loading code that we want to start playing | ||
1266 | as soon as we have some data */ | ||
1267 | play_pending = true; | ||
1268 | play_pending_track_change = true; | ||
1269 | |||
1270 | update_playlist(); | ||
1271 | current_track_counter++; | ||
1272 | break; | ||
1273 | |||
1274 | case MPEG_STOP: | ||
1275 | DEBUGF("MPEG_STOP\n"); | ||
1276 | is_playing = false; | ||
1277 | paused = false; | ||
1278 | |||
1279 | if (playing) | ||
1280 | playlist_update_resume_info(audio_current_track()); | ||
1281 | |||
1282 | stop_playing(); | ||
1283 | mpeg_stop_done = true; | ||
1284 | break; | ||
1285 | |||
1286 | case MPEG_PAUSE: | ||
1287 | DEBUGF("MPEG_PAUSE\n"); | ||
1288 | /* Stop the current stream */ | ||
1289 | if (playing) | ||
1290 | playlist_update_resume_info(audio_current_track()); | ||
1291 | paused = true; | ||
1292 | playing = false; | ||
1293 | pause_tick = current_tick; | ||
1294 | pause_track = current_track_counter; | ||
1295 | mp3_play_pause(false); | ||
1296 | break; | ||
1297 | |||
1298 | case MPEG_RESUME: | ||
1299 | DEBUGF("MPEG_RESUME\n"); | ||
1300 | /* Continue the current stream */ | ||
1301 | paused = false; | ||
1302 | if (!play_pending) | ||
1303 | { | ||
1304 | playing = true; | ||
1305 | if ( current_track_counter == pause_track ) | ||
1306 | last_dma_tick += current_tick - pause_tick; | ||
1307 | else | ||
1308 | last_dma_tick = current_tick; | ||
1309 | pause_tick = 0; | ||
1310 | mp3_play_pause(true); | ||
1311 | } | ||
1312 | break; | ||
1313 | |||
1314 | case MPEG_NEXT: | ||
1315 | DEBUGF("MPEG_NEXT\n"); | ||
1316 | /* is next track in ram? */ | ||
1317 | if ( num_tracks_in_memory() > 1 ) { | ||
1318 | int unplayed_space_left, unswapped_space_left; | ||
1319 | |||
1320 | /* stop the current stream */ | ||
1321 | play_pending = false; | ||
1322 | playing = false; | ||
1323 | mp3_play_pause(false); | ||
1324 | |||
1325 | track_change(); | ||
1326 | audiobuf_read = get_trackdata(0)->mempos; | ||
1327 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | ||
1328 | mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | ||
1329 | dma_underrun = false; | ||
1330 | last_dma_tick = current_tick; | ||
1331 | |||
1332 | unplayed_space_left = get_unplayed_space(); | ||
1333 | unswapped_space_left = get_unswapped_space(); | ||
1334 | |||
1335 | /* should we start reading more data? */ | ||
1336 | if(!filling && (unplayed_space_left < low_watermark)) { | ||
1337 | filling = true; | ||
1338 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
1339 | play_pending = true; | ||
1340 | } else if(unswapped_space_left && | ||
1341 | unswapped_space_left > unplayed_space_left) { | ||
1342 | /* Stop swapping the data from the previous file */ | ||
1343 | audiobuf_swapwrite = audiobuf_read; | ||
1344 | play_pending = true; | ||
1345 | } else { | ||
1346 | playing = true; | ||
1347 | if (!paused) | ||
1348 | mp3_play_pause(true); | ||
1349 | } | ||
1350 | } | ||
1351 | else { | ||
1352 | if (!playlist_check(1)) | ||
1353 | break; | ||
1354 | |||
1355 | /* stop the current stream */ | ||
1356 | end_current_track(); | ||
1357 | |||
1358 | if (new_file(1) < 0) { | ||
1359 | DEBUGF("No more files to play\n"); | ||
1360 | filling = false; | ||
1361 | |||
1362 | check_playlist_end(1); | ||
1363 | current_track_counter++; | ||
1364 | } else { | ||
1365 | /* Make it read more data */ | ||
1366 | filling = true; | ||
1367 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1368 | |||
1369 | /* Tell the file loading code that we want | ||
1370 | to start playing as soon as we have some data */ | ||
1371 | play_pending = true; | ||
1372 | play_pending_track_change = true; | ||
1373 | |||
1374 | update_playlist(); | ||
1375 | current_track_counter++; | ||
1376 | } | ||
1377 | } | ||
1378 | break; | ||
1379 | |||
1380 | case MPEG_PREV: { | ||
1381 | DEBUGF("MPEG_PREV\n"); | ||
1382 | |||
1383 | if (!playlist_check(-1)) | ||
1384 | break; | ||
1385 | |||
1386 | /* stop the current stream */ | ||
1387 | end_current_track(); | ||
1388 | |||
1389 | /* Open the next file */ | ||
1390 | if (new_file(-1) < 0) { | ||
1391 | DEBUGF("No more files to play\n"); | ||
1392 | filling = false; | ||
1393 | |||
1394 | check_playlist_end(-1); | ||
1395 | current_track_counter++; | ||
1396 | } else { | ||
1397 | /* Make it read more data */ | ||
1398 | filling = true; | ||
1399 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1400 | |||
1401 | /* Tell the file loading code that we want to | ||
1402 | start playing as soon as we have some data */ | ||
1403 | play_pending = true; | ||
1404 | play_pending_track_change = true; | ||
1405 | |||
1406 | update_playlist(); | ||
1407 | current_track_counter++; | ||
1408 | } | ||
1409 | break; | ||
1410 | } | ||
1411 | |||
1412 | case MPEG_FF_REWIND: { | ||
1413 | struct mp3entry *id3 = audio_current_track(); | ||
1414 | unsigned int oldtime = id3->elapsed; | ||
1415 | unsigned int newtime = (unsigned int)ev.data; | ||
1416 | int curpos, newpos, diffpos; | ||
1417 | DEBUGF("MPEG_FF_REWIND\n"); | ||
1418 | |||
1419 | id3->elapsed = newtime; | ||
1420 | |||
1421 | newpos = audio_get_file_pos(); | ||
1422 | if(newpos < 0) | ||
1423 | { | ||
1424 | id3->elapsed = oldtime; | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | if (mpeg_file >= 0) | ||
1429 | curpos = lseek(mpeg_file, 0, SEEK_CUR); | ||
1430 | else | ||
1431 | curpos = id3->filesize; | ||
1432 | |||
1433 | if (num_tracks_in_memory() > 1) | ||
1434 | { | ||
1435 | /* We have started loading other tracks that need to be | ||
1436 | accounted for */ | ||
1437 | struct trackdata *track; | ||
1438 | int i = 0; | ||
1439 | |||
1440 | while((track = get_trackdata(i++))) | ||
1441 | { | ||
1442 | curpos += track->id3.filesize; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | diffpos = curpos - newpos; | ||
1447 | |||
1448 | if(!filling && diffpos >= 0 && diffpos < audiobuflen) | ||
1449 | { | ||
1450 | int unplayed_space_left, unswapped_space_left; | ||
1451 | |||
1452 | /* We are changing to a position that's already in | ||
1453 | memory, so we just move the DMA read pointer. */ | ||
1454 | audiobuf_read = audiobuf_write - diffpos; | ||
1455 | if (audiobuf_read < 0) | ||
1456 | { | ||
1457 | audiobuf_read += audiobuflen; | ||
1458 | } | ||
1459 | |||
1460 | unplayed_space_left = get_unplayed_space(); | ||
1461 | unswapped_space_left = get_unswapped_space(); | ||
1462 | |||
1463 | /* If unswapped_space_left is larger than | ||
1464 | unplayed_space_left, it means that the swapwrite pointer | ||
1465 | hasn't yet advanced up to the new location of the read | ||
1466 | pointer. We just move it, there is no need to swap | ||
1467 | data that won't be played anyway. */ | ||
1468 | |||
1469 | if (unswapped_space_left > unplayed_space_left) | ||
1470 | { | ||
1471 | DEBUGF("Moved swapwrite\n"); | ||
1472 | audiobuf_swapwrite = audiobuf_read; | ||
1473 | play_pending = true; | ||
1474 | } | ||
1475 | |||
1476 | if (mpeg_file>=0 && unplayed_space_left < low_watermark) | ||
1477 | { | ||
1478 | /* We need to load more data before starting */ | ||
1479 | filling = true; | ||
1480 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
1481 | play_pending = true; | ||
1482 | } | ||
1483 | else | ||
1484 | { | ||
1485 | /* resume will start at new position */ | ||
1486 | last_dma_chunk_size = | ||
1487 | MIN(0x2000, get_unplayed_space_current_song()); | ||
1488 | mp3_play_data(audiobuf + audiobuf_read, | ||
1489 | last_dma_chunk_size, transfer_end); | ||
1490 | dma_underrun = false; | ||
1491 | } | ||
1492 | } | ||
1493 | else | ||
1494 | { | ||
1495 | /* Move to the new position in the file and start | ||
1496 | loading data */ | ||
1497 | reset_mp3_buffer(); | ||
1498 | |||
1499 | if (num_tracks_in_memory() > 1) | ||
1500 | { | ||
1501 | /* We have to reload the current track */ | ||
1502 | close(mpeg_file); | ||
1503 | remove_all_non_current_tags(); | ||
1504 | generate_unbuffer_events(); | ||
1505 | mpeg_file = -1; | ||
1506 | } | ||
1507 | |||
1508 | if (mpeg_file < 0) | ||
1509 | { | ||
1510 | mpeg_file = open(id3->path, O_RDONLY); | ||
1511 | if (mpeg_file < 0) | ||
1512 | { | ||
1513 | id3->elapsed = oldtime; | ||
1514 | break; | ||
1515 | } | ||
1516 | } | ||
1517 | |||
1518 | if(-1 == lseek(mpeg_file, newpos, SEEK_SET)) | ||
1519 | { | ||
1520 | id3->elapsed = oldtime; | ||
1521 | break; | ||
1522 | } | ||
1523 | |||
1524 | filling = true; | ||
1525 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1526 | |||
1527 | /* Tell the file loading code that we want to start playing | ||
1528 | as soon as we have some data */ | ||
1529 | play_pending = true; | ||
1530 | } | ||
1531 | |||
1532 | id3->offset = newpos; | ||
1533 | |||
1534 | break; | ||
1535 | } | ||
1536 | |||
1537 | case MPEG_FLUSH_RELOAD: { | ||
1538 | int numtracks = num_tracks_in_memory(); | ||
1539 | bool reload_track = false; | ||
1540 | |||
1541 | if (numtracks > 1) | ||
1542 | { | ||
1543 | /* Reset the buffer */ | ||
1544 | audiobuf_write = get_trackdata(1)->mempos; | ||
1545 | |||
1546 | /* Reset swapwrite unless we're still swapping current | ||
1547 | track */ | ||
1548 | if (get_unplayed_space() <= get_playable_space()) | ||
1549 | audiobuf_swapwrite = audiobuf_write; | ||
1550 | |||
1551 | close(mpeg_file); | ||
1552 | remove_all_non_current_tags(); | ||
1553 | generate_unbuffer_events(); | ||
1554 | mpeg_file = -1; | ||
1555 | reload_track = true; | ||
1556 | } | ||
1557 | else if (numtracks == 1 && mpeg_file < 0) | ||
1558 | { | ||
1559 | reload_track = true; | ||
1560 | } | ||
1561 | |||
1562 | if(reload_track && new_file(1) >= 0) | ||
1563 | { | ||
1564 | /* Tell ourselves that we want more data */ | ||
1565 | filling = true; | ||
1566 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1567 | } | ||
1568 | |||
1569 | break; | ||
1570 | } | ||
1571 | |||
1572 | case MPEG_NEED_DATA: | ||
1573 | free_space_left = audiobuf_read - audiobuf_write; | ||
1574 | |||
1575 | /* We interpret 0 as "empty buffer" */ | ||
1576 | if(free_space_left <= 0) | ||
1577 | free_space_left += audiobuflen; | ||
1578 | |||
1579 | unplayed_space_left = audiobuflen - free_space_left; | ||
1580 | |||
1581 | /* Make sure that we don't fill the entire buffer */ | ||
1582 | free_space_left -= MPEG_HIGH_WATER; | ||
1583 | |||
1584 | if (ev.data == GENERATE_UNBUFFER_EVENTS) | ||
1585 | generate_unbuffer_events(); | ||
1586 | |||
1587 | /* do we have any more buffer space to fill? */ | ||
1588 | if(free_space_left <= 0) | ||
1589 | { | ||
1590 | DEBUGF("0\n"); | ||
1591 | filling = false; | ||
1592 | generate_postbuffer_events(); | ||
1593 | ata_sleep(); | ||
1594 | break; | ||
1595 | } | ||
1596 | |||
1597 | /* Read small chunks while we are below the low water mark */ | ||
1598 | if(unplayed_space_left < low_watermark) | ||
1599 | amount_to_read = MIN(MPEG_LOW_WATER_CHUNKSIZE, | ||
1600 | free_space_left); | ||
1601 | else | ||
1602 | amount_to_read = free_space_left; | ||
1603 | |||
1604 | /* Don't read more than until the end of the buffer */ | ||
1605 | amount_to_read = MIN(audiobuflen - audiobuf_write, | ||
1606 | amount_to_read); | ||
1607 | #ifdef HAVE_MMC /* MMC is slow, so don't read too large chunks */ | ||
1608 | amount_to_read = MIN(0x40000, amount_to_read); | ||
1609 | #elif MEM == 8 | ||
1610 | amount_to_read = MIN(0x100000, amount_to_read); | ||
1611 | #endif | ||
1612 | |||
1613 | /* Read as much mpeg data as we can fit in the buffer */ | ||
1614 | if(mpeg_file >= 0) | ||
1615 | { | ||
1616 | DEBUGF("R\n"); | ||
1617 | t1 = current_tick; | ||
1618 | len = read(mpeg_file, audiobuf + audiobuf_write, | ||
1619 | amount_to_read); | ||
1620 | if(len > 0) | ||
1621 | { | ||
1622 | t2 = current_tick; | ||
1623 | DEBUGF("time: %d\n", t2 - t1); | ||
1624 | DEBUGF("R: %x\n", len); | ||
1625 | |||
1626 | /* Now make sure that we don't feed the MAS with ID3V1 | ||
1627 | data */ | ||
1628 | if (len < amount_to_read) | ||
1629 | { | ||
1630 | int i; | ||
1631 | static const unsigned char tag[] = "TAG"; | ||
1632 | int taglen = 128; | ||
1633 | int tagptr = audiobuf_write + len - 128; | ||
1634 | |||
1635 | /* Really rare case: entire potential tag wasn't | ||
1636 | read in this call AND audiobuf_write < 128 */ | ||
1637 | if (tagptr < 0) | ||
1638 | tagptr += audiobuflen; | ||
1639 | |||
1640 | for(i = 0;i < 3;i++) | ||
1641 | { | ||
1642 | if(tagptr >= audiobuflen) | ||
1643 | tagptr -= audiobuflen; | ||
1644 | |||
1645 | if(audiobuf[tagptr] != tag[i]) | ||
1646 | { | ||
1647 | taglen = 0; | ||
1648 | break; | ||
1649 | } | ||
1650 | |||
1651 | tagptr++; | ||
1652 | } | ||
1653 | |||
1654 | if(taglen) | ||
1655 | { | ||
1656 | /* Skip id3v1 tag */ | ||
1657 | DEBUGF("Skipping ID3v1 tag\n"); | ||
1658 | len -= taglen; | ||
1659 | |||
1660 | /* In the very rare case when the entire tag | ||
1661 | wasn't read in this read() len will be < 0. | ||
1662 | Take care of this when changing the write | ||
1663 | pointer. */ | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | audiobuf_write += len; | ||
1668 | |||
1669 | if (audiobuf_write < 0) | ||
1670 | audiobuf_write += audiobuflen; | ||
1671 | |||
1672 | if(audiobuf_write >= audiobuflen) | ||
1673 | { | ||
1674 | audiobuf_write = 0; | ||
1675 | DEBUGF("W\n"); | ||
1676 | } | ||
1677 | |||
1678 | /* Tell ourselves that we want more data */ | ||
1679 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1680 | } | ||
1681 | else | ||
1682 | { | ||
1683 | if(len < 0) | ||
1684 | { | ||
1685 | DEBUGF("MPEG read error\n"); | ||
1686 | } | ||
1687 | |||
1688 | close(mpeg_file); | ||
1689 | mpeg_file = -1; | ||
1690 | |||
1691 | if(new_file(1) < 0) | ||
1692 | { | ||
1693 | /* No more data to play */ | ||
1694 | DEBUGF("No more files to play\n"); | ||
1695 | filling = false; | ||
1696 | } | ||
1697 | else | ||
1698 | { | ||
1699 | /* Tell ourselves that we want more data */ | ||
1700 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1701 | } | ||
1702 | } | ||
1703 | } | ||
1704 | break; | ||
1705 | |||
1706 | case MPEG_TRACK_CHANGE: | ||
1707 | track_change(); | ||
1708 | break; | ||
1709 | |||
1710 | #ifndef USB_NONE | ||
1711 | case SYS_USB_CONNECTED: | ||
1712 | is_playing = false; | ||
1713 | paused = false; | ||
1714 | stop_playing(); | ||
1715 | |||
1716 | /* Tell the USB thread that we are safe */ | ||
1717 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | ||
1718 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
1719 | |||
1720 | /* Wait until the USB cable is extracted again */ | ||
1721 | usb_wait_for_disconnect(&mpeg_queue); | ||
1722 | break; | ||
1723 | #endif /* !USB_NONE */ | ||
1724 | |||
1725 | #if CONFIG_CODEC == MAS3587F | ||
1726 | case MPEG_INIT_RECORDING: | ||
1727 | init_recording(); | ||
1728 | init_recording_done = true; | ||
1729 | break; | ||
1730 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
1731 | |||
1732 | case SYS_TIMEOUT: | ||
1733 | if (playing) | ||
1734 | playlist_update_resume_info(audio_current_track()); | ||
1735 | break; | ||
1736 | } | ||
1737 | #if CONFIG_CODEC == MAS3587F | ||
1738 | } | ||
1739 | else | ||
1740 | { | ||
1741 | queue_wait(&mpeg_queue, &ev); | ||
1742 | switch(ev.id) | ||
1743 | { | ||
1744 | case MPEG_RECORD: | ||
1745 | if (is_prerecording) | ||
1746 | { | ||
1747 | int startpos; | ||
1748 | |||
1749 | /* Go back prerecord_count seconds in the buffer */ | ||
1750 | startpos = prerecord_index - prerecord_count; | ||
1751 | if(startpos < 0) | ||
1752 | startpos += prerecording_max_seconds; | ||
1753 | |||
1754 | /* Read the position data from the prerecord buffer */ | ||
1755 | frame_count_start = prerecord_buffer[startpos].framecount; | ||
1756 | startpos = prerecord_buffer[startpos].mempos; | ||
1757 | |||
1758 | DEBUGF("Start looking at address %x (%x)\n", | ||
1759 | audiobuf+startpos, startpos); | ||
1760 | |||
1761 | saved_header = mpeg_get_last_header(); | ||
1762 | |||
1763 | mem_find_next_frame(startpos, &offset, 1800, | ||
1764 | saved_header); | ||
1765 | |||
1766 | audiobuf_read = startpos + offset; | ||
1767 | if(audiobuf_read >= audiobuflen) | ||
1768 | audiobuf_read -= audiobuflen; | ||
1769 | |||
1770 | DEBUGF("New audiobuf_read address: %x (%x)\n", | ||
1771 | audiobuf+audiobuf_read, audiobuf_read); | ||
1772 | |||
1773 | level = disable_irq_save(); | ||
1774 | num_rec_bytes = get_unsaved_space(); | ||
1775 | restore_irq(level); | ||
1776 | } | ||
1777 | else | ||
1778 | { | ||
1779 | frame_count_start = 0; | ||
1780 | num_rec_bytes = 0; | ||
1781 | audiobuf_read = MPEG_RESERVED_HEADER_SPACE; | ||
1782 | audiobuf_write = MPEG_RESERVED_HEADER_SPACE; | ||
1783 | } | ||
1784 | |||
1785 | prepend_header(); | ||
1786 | DEBUGF("Recording...\n"); | ||
1787 | start_recording(); | ||
1788 | |||
1789 | /* Wait until at least one frame is encoded and get the | ||
1790 | frame header, for later use by the Xing header | ||
1791 | generation */ | ||
1792 | sleep(HZ/5); | ||
1793 | saved_header = mpeg_get_last_header(); | ||
1794 | |||
1795 | /* delayed until buffer is saved, don't open yet */ | ||
1796 | strcpy(delayed_filename, recording_filename); | ||
1797 | mpeg_file = -1; | ||
1798 | |||
1799 | break; | ||
1800 | |||
1801 | case MPEG_STOP: | ||
1802 | DEBUGF("MPEG_STOP\n"); | ||
1803 | |||
1804 | stop_recording(); | ||
1805 | |||
1806 | /* Save the remaining data in the buffer */ | ||
1807 | save_endpos = audiobuf_write; | ||
1808 | saving_status = STOP_RECORDING; | ||
1809 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1810 | break; | ||
1811 | |||
1812 | case MPEG_STOP_DONE: | ||
1813 | DEBUGF("MPEG_STOP_DONE\n"); | ||
1814 | |||
1815 | if (mpeg_file >= 0) | ||
1816 | close(mpeg_file); | ||
1817 | mpeg_file = -1; | ||
1818 | |||
1819 | update_header(); | ||
1820 | #ifdef DEBUG1 | ||
1821 | { | ||
1822 | int i; | ||
1823 | for(i = 0;i < 512;i++) | ||
1824 | { | ||
1825 | DEBUGF("%d - %d us (%d bytes)\n", | ||
1826 | timing_info[i*2], | ||
1827 | (timing_info[i*2+1] & 0xffff) * | ||
1828 | 10000 / 13824, | ||
1829 | timing_info[i*2+1] >> 16); | ||
1830 | } | ||
1831 | } | ||
1832 | #endif /* DEBUG1 */ | ||
1833 | |||
1834 | if (prerecording) | ||
1835 | { | ||
1836 | start_prerecording(); | ||
1837 | } | ||
1838 | mpeg_stop_done = true; | ||
1839 | break; | ||
1840 | |||
1841 | case MPEG_NEW_FILE: | ||
1842 | /* Bail out when a more important save is happening */ | ||
1843 | if (saving_status > NEW_FILE) | ||
1844 | break; | ||
1845 | |||
1846 | /* Make sure we have at least one complete frame | ||
1847 | in the buffer. If we haven't recorded a single | ||
1848 | frame within 200ms, the MAS is probably not recording | ||
1849 | anything, and we bail out. */ | ||
1850 | amount_to_save = get_unsaved_space(); | ||
1851 | if (amount_to_save < 1800) | ||
1852 | { | ||
1853 | sleep(HZ/5); | ||
1854 | amount_to_save = get_unsaved_space(); | ||
1855 | } | ||
1856 | |||
1857 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, | ||
1858 | &frame_count_end, 1); | ||
1859 | |||
1860 | last_rec_time = current_tick - record_start_time; | ||
1861 | record_start_time = current_tick; | ||
1862 | if (paused) | ||
1863 | pause_start_time = record_start_time; | ||
1864 | |||
1865 | /* capture all values at one point */ | ||
1866 | level = disable_irq_save(); | ||
1867 | save_endpos = audiobuf_write; | ||
1868 | last_rec_bytes = num_rec_bytes; | ||
1869 | num_rec_bytes = 0; | ||
1870 | restore_irq(level); | ||
1871 | |||
1872 | if (amount_to_save >= 1800) | ||
1873 | { | ||
1874 | /* Now find a frame boundary to split at */ | ||
1875 | save_endpos -= 1800; | ||
1876 | if (save_endpos < 0) | ||
1877 | save_endpos += audiobuflen; | ||
1878 | |||
1879 | rc = mem_find_next_frame(save_endpos, &offset, 1800, | ||
1880 | saved_header); | ||
1881 | if (!rc) /* No header found, save whole buffer */ | ||
1882 | offset = 1800; | ||
1883 | |||
1884 | save_endpos += offset; | ||
1885 | if (save_endpos >= audiobuflen) | ||
1886 | save_endpos -= audiobuflen; | ||
1887 | |||
1888 | last_rec_bytes += offset - 1800; | ||
1889 | level = disable_irq_save(); | ||
1890 | num_rec_bytes += 1800 - offset; | ||
1891 | restore_irq(level); | ||
1892 | } | ||
1893 | |||
1894 | saving_status = NEW_FILE; | ||
1895 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1896 | break; | ||
1897 | |||
1898 | case MPEG_SAVE_DATA: | ||
1899 | if (saving_status == BUFFER_FULL) | ||
1900 | save_endpos = audiobuf_write; | ||
1901 | |||
1902 | if (mpeg_file < 0) /* delayed file open */ | ||
1903 | { | ||
1904 | mpeg_file = open(delayed_filename, O_WRONLY|O_CREAT); | ||
1905 | |||
1906 | if (mpeg_file < 0) | ||
1907 | panicf("recfile: %d", mpeg_file); | ||
1908 | } | ||
1909 | |||
1910 | amount_to_save = save_endpos - audiobuf_read; | ||
1911 | if (amount_to_save < 0) | ||
1912 | amount_to_save += audiobuflen; | ||
1913 | |||
1914 | amount_to_save = MIN(amount_to_save, | ||
1915 | audiobuflen - audiobuf_read); | ||
1916 | #ifdef HAVE_MMC /* MMC is slow, so don't save too large chunks at once */ | ||
1917 | amount_to_save = MIN(0x40000, amount_to_save); | ||
1918 | #elif MEM == 8 | ||
1919 | amount_to_save = MIN(0x100000, amount_to_save); | ||
1920 | #endif | ||
1921 | rc = write(mpeg_file, audiobuf + audiobuf_read, | ||
1922 | amount_to_save); | ||
1923 | if (rc < 0) | ||
1924 | { | ||
1925 | if (errno == ENOSPC) | ||
1926 | { | ||
1927 | mpeg_errno = AUDIOERR_DISK_FULL; | ||
1928 | stop_recording(); | ||
1929 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
1930 | /* will close the file */ | ||
1931 | break; | ||
1932 | } | ||
1933 | else | ||
1934 | panicf("rec wrt: %d", rc); | ||
1935 | } | ||
1936 | |||
1937 | audiobuf_read += amount_to_save; | ||
1938 | if (audiobuf_read >= audiobuflen) | ||
1939 | audiobuf_read = 0; | ||
1940 | |||
1941 | if (audiobuf_read == save_endpos) /* all saved */ | ||
1942 | { | ||
1943 | switch (saving_status) | ||
1944 | { | ||
1945 | case BUFFER_FULL: | ||
1946 | rc = fsync(mpeg_file); | ||
1947 | if (rc < 0) | ||
1948 | panicf("rec fls: %d", rc); | ||
1949 | ata_sleep(); | ||
1950 | break; | ||
1951 | |||
1952 | case NEW_FILE: | ||
1953 | /* Close the current file */ | ||
1954 | rc = close(mpeg_file); | ||
1955 | if (rc < 0) | ||
1956 | panicf("rec cls: %d", rc); | ||
1957 | mpeg_file = -1; | ||
1958 | update_header(); | ||
1959 | ata_sleep(); | ||
1960 | |||
1961 | /* copy new filename */ | ||
1962 | strcpy(delayed_filename, recording_filename); | ||
1963 | prepend_header(); | ||
1964 | frame_count_start = frame_count_end; | ||
1965 | break; | ||
1966 | |||
1967 | case STOP_RECORDING: | ||
1968 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
1969 | /* will close the file */ | ||
1970 | break; | ||
1971 | |||
1972 | default: | ||
1973 | break; | ||
1974 | } | ||
1975 | saving_status = NOT_SAVING; | ||
1976 | } | ||
1977 | else /* tell ourselves to save the next chunk */ | ||
1978 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1979 | |||
1980 | break; | ||
1981 | |||
1982 | case MPEG_PRERECORDING_TICK: | ||
1983 | if(!is_prerecording) | ||
1984 | break; | ||
1985 | |||
1986 | /* Store the write pointer every second */ | ||
1987 | prerecord_buffer[prerecord_index].mempos = audiobuf_write; | ||
1988 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, | ||
1989 | &prerecord_buffer[prerecord_index].framecount, 1); | ||
1990 | |||
1991 | /* Wrap if necessary */ | ||
1992 | if(++prerecord_index == prerecording_max_seconds) | ||
1993 | prerecord_index = 0; | ||
1994 | |||
1995 | /* Update the number of seconds recorded */ | ||
1996 | if(prerecord_count < prerecording_max_seconds) | ||
1997 | prerecord_count++; | ||
1998 | break; | ||
1999 | |||
2000 | case MPEG_INIT_PLAYBACK: | ||
2001 | /* Stop the prerecording */ | ||
2002 | stop_recording(); | ||
2003 | reset_mp3_buffer(); | ||
2004 | mp3_play_init(); | ||
2005 | init_playback_done = true; | ||
2006 | break; | ||
2007 | |||
2008 | case MPEG_PAUSE_RECORDING: | ||
2009 | pause_recording(); | ||
2010 | break; | ||
2011 | |||
2012 | case MPEG_RESUME_RECORDING: | ||
2013 | resume_recording(); | ||
2014 | break; | ||
2015 | |||
2016 | case SYS_USB_CONNECTED: | ||
2017 | /* We can safely go to USB mode if no recording | ||
2018 | is taking place */ | ||
2019 | if((!is_recording || is_prerecording) && mpeg_stop_done) | ||
2020 | { | ||
2021 | /* Even if we aren't recording, we still call this | ||
2022 | function, to put the MAS in monitoring mode, | ||
2023 | to save power. */ | ||
2024 | stop_recording(); | ||
2025 | |||
2026 | /* Tell the USB thread that we are safe */ | ||
2027 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | ||
2028 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
2029 | |||
2030 | /* Wait until the USB cable is extracted again */ | ||
2031 | usb_wait_for_disconnect(&mpeg_queue); | ||
2032 | } | ||
2033 | break; | ||
2034 | } | ||
2035 | } | ||
2036 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2037 | } | ||
2038 | } | ||
2039 | #endif /* !SIMULATOR */ | ||
2040 | |||
2041 | struct mp3entry* audio_current_track() | ||
2042 | { | ||
2043 | #ifdef SIMULATOR | ||
2044 | return &taginfo; | ||
2045 | #else /* !SIMULATOR */ | ||
2046 | if(num_tracks_in_memory()) | ||
2047 | return &get_trackdata(0)->id3; | ||
2048 | else | ||
2049 | return NULL; | ||
2050 | #endif /* !SIMULATOR */ | ||
2051 | } | ||
2052 | |||
2053 | struct mp3entry* audio_next_track() | ||
2054 | { | ||
2055 | #ifdef SIMULATOR | ||
2056 | return &taginfo; | ||
2057 | #else /* !SIMULATOR */ | ||
2058 | if(num_tracks_in_memory() > 1) | ||
2059 | return &get_trackdata(1)->id3; | ||
2060 | else | ||
2061 | return NULL; | ||
2062 | #endif /* !SIMULATOR */ | ||
2063 | } | ||
2064 | |||
2065 | bool audio_has_changed_track(void) | ||
2066 | { | ||
2067 | if(last_track_counter != current_track_counter) | ||
2068 | { | ||
2069 | last_track_counter = current_track_counter; | ||
2070 | return true; | ||
2071 | } | ||
2072 | return false; | ||
2073 | } | ||
2074 | |||
2075 | #if CONFIG_CODEC == MAS3587F | ||
2076 | #ifndef SIMULATOR | ||
2077 | void audio_init_playback(void) | ||
2078 | { | ||
2079 | init_playback_done = false; | ||
2080 | queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, 0); | ||
2081 | |||
2082 | while(!init_playback_done) | ||
2083 | sleep(1); | ||
2084 | } | ||
2085 | |||
2086 | |||
2087 | /**************************************************************************** | ||
2088 | * Recording functions | ||
2089 | ***************************************************************************/ | ||
2090 | void audio_init_recording(unsigned int buffer_offset) | ||
2091 | { | ||
2092 | buffer_offset = buffer_offset; | ||
2093 | init_recording_done = false; | ||
2094 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, 0); | ||
2095 | |||
2096 | while(!init_recording_done) | ||
2097 | sleep(1); | ||
2098 | } | ||
2099 | |||
2100 | static void init_recording(void) | ||
2101 | { | ||
2102 | unsigned long val; | ||
2103 | int rc; | ||
2104 | |||
2105 | /* Disable IRQ6 */ | ||
2106 | IPRB &= 0xff0f; | ||
2107 | |||
2108 | stop_playing(); | ||
2109 | is_playing = false; | ||
2110 | paused = false; | ||
2111 | |||
2112 | /* Init the recording variables */ | ||
2113 | is_recording = false; | ||
2114 | is_prerecording = false; | ||
2115 | |||
2116 | mpeg_stop_done = true; | ||
2117 | |||
2118 | mas_reset(); | ||
2119 | |||
2120 | /* Enable the audio CODEC and the DSP core, max analog voltage range */ | ||
2121 | rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); | ||
2122 | if(rc < 0) | ||
2123 | panicf("mas_ctrl_w: %d", rc); | ||
2124 | |||
2125 | /* Stop the current application */ | ||
2126 | val = 0; | ||
2127 | mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); | ||
2128 | do | ||
2129 | { | ||
2130 | mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); | ||
2131 | } while(val); | ||
2132 | |||
2133 | /* Perform black magic as described by the data sheet */ | ||
2134 | if((mas_version_code & 0x0fff) == 0x0102) | ||
2135 | { | ||
2136 | DEBUGF("Performing MAS black magic for B2 version\n"); | ||
2137 | mas_writereg(0xa3, 0x98); | ||
2138 | mas_writereg(0x94, 0xfffff); | ||
2139 | val = 0; | ||
2140 | mas_writemem(MAS_BANK_D1, 0, &val, 1); | ||
2141 | mas_writereg(0xa3, 0x90); | ||
2142 | } | ||
2143 | |||
2144 | /* Enable A/D Converters */ | ||
2145 | shadow_codec_reg0 = 0xcccd; | ||
2146 | mas_codec_writereg(0x0, shadow_codec_reg0); | ||
2147 | |||
2148 | /* Copy left channel to right (mono mode) */ | ||
2149 | mas_codec_writereg(8, 0x8000); | ||
2150 | |||
2151 | /* ADC scale 0%, DSP scale 100% | ||
2152 | We use the DSP output for monitoring, because it works with all | ||
2153 | sources including S/PDIF */ | ||
2154 | mas_codec_writereg(6, 0x0000); | ||
2155 | mas_codec_writereg(7, 0x4000); | ||
2156 | |||
2157 | /* No mute */ | ||
2158 | shadow_soft_mute = 0; | ||
2159 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1); | ||
2160 | |||
2161 | #ifdef HAVE_SPDIF_OUT | ||
2162 | val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */ | ||
2163 | #else | ||
2164 | val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */ | ||
2165 | #endif | ||
2166 | mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1); | ||
2167 | |||
2168 | /* Set Demand mode, monitoring OFF and validate all settings */ | ||
2169 | shadow_io_control_main = 0x125; | ||
2170 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2171 | |||
2172 | /* Start the encoder application */ | ||
2173 | val = 0x40; | ||
2174 | mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); | ||
2175 | do | ||
2176 | { | ||
2177 | mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); | ||
2178 | } while(!(val & 0x40)); | ||
2179 | |||
2180 | /* We have started the recording application with monitoring OFF. | ||
2181 | This is because we want to record at least one frame to fill the DMA | ||
2182 | buffer, because the silly MAS will not negate EOD until at least one | ||
2183 | DMA transfer has taken place. | ||
2184 | Now let's wait for some data to be encoded. */ | ||
2185 | sleep(HZ/5); | ||
2186 | |||
2187 | /* Now set it to Monitoring mode as default, saves power */ | ||
2188 | shadow_io_control_main = 0x525; | ||
2189 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2190 | |||
2191 | /* Wait until the DSP has accepted the settings */ | ||
2192 | do | ||
2193 | { | ||
2194 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2195 | } while(val & 1); | ||
2196 | |||
2197 | drain_dma_buffer(); | ||
2198 | mpeg_mode = MPEG_ENCODER; | ||
2199 | |||
2200 | DEBUGF("MAS Recording application started\n"); | ||
2201 | |||
2202 | /* At this point, all settings are the reset MAS defaults, next thing is to | ||
2203 | call mpeg_set_recording_options(). */ | ||
2204 | } | ||
2205 | |||
2206 | void audio_record(const char *filename) | ||
2207 | { | ||
2208 | mpeg_errno = 0; | ||
2209 | |||
2210 | strncpy(recording_filename, filename, MAX_PATH - 1); | ||
2211 | recording_filename[MAX_PATH - 1] = 0; | ||
2212 | |||
2213 | queue_post(&mpeg_queue, MPEG_RECORD, 0); | ||
2214 | } | ||
2215 | |||
2216 | void audio_pause_recording(void) | ||
2217 | { | ||
2218 | queue_post(&mpeg_queue, MPEG_PAUSE_RECORDING, 0); | ||
2219 | } | ||
2220 | |||
2221 | void audio_resume_recording(void) | ||
2222 | { | ||
2223 | queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, 0); | ||
2224 | } | ||
2225 | |||
2226 | static void prepend_header(void) | ||
2227 | { | ||
2228 | int startpos; | ||
2229 | unsigned i; | ||
2230 | |||
2231 | /* Make room for header */ | ||
2232 | audiobuf_read -= MPEG_RESERVED_HEADER_SPACE; | ||
2233 | if(audiobuf_read < 0) | ||
2234 | { | ||
2235 | /* Clear the bottom half */ | ||
2236 | memset(audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE); | ||
2237 | |||
2238 | /* And the top half */ | ||
2239 | audiobuf_read += audiobuflen; | ||
2240 | memset(audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read); | ||
2241 | } | ||
2242 | else | ||
2243 | { | ||
2244 | memset(audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE); | ||
2245 | } | ||
2246 | /* Copy the empty ID3 header */ | ||
2247 | startpos = audiobuf_read; | ||
2248 | for(i = 0; i < sizeof(empty_id3_header); i++) | ||
2249 | { | ||
2250 | audiobuf[startpos++] = empty_id3_header[i]; | ||
2251 | if(startpos == audiobuflen) | ||
2252 | startpos = 0; | ||
2253 | } | ||
2254 | } | ||
2255 | |||
2256 | static void update_header(void) | ||
2257 | { | ||
2258 | int fd, framelen; | ||
2259 | unsigned long frames; | ||
2260 | |||
2261 | if (last_rec_bytes > 0) | ||
2262 | { | ||
2263 | /* Create the Xing header */ | ||
2264 | fd = open(delayed_filename, O_RDWR); | ||
2265 | if (fd < 0) | ||
2266 | panicf("rec upd: %d (%s)", fd, recording_filename); | ||
2267 | |||
2268 | frames = frame_count_end - frame_count_start; | ||
2269 | /* If the number of recorded frames has reached 0x7ffff, | ||
2270 | we can no longer trust it */ | ||
2271 | if (frame_count_end == 0x7ffff) | ||
2272 | frames = 0; | ||
2273 | |||
2274 | /* saved_header is saved right before stopping the MAS */ | ||
2275 | framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer, | ||
2276 | frames, last_rec_time * (1000/HZ), | ||
2277 | saved_header, NULL, false); | ||
2278 | |||
2279 | lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET); | ||
2280 | write(fd, xing_buffer, framelen); | ||
2281 | close(fd); | ||
2282 | } | ||
2283 | } | ||
2284 | |||
2285 | static void start_prerecording(void) | ||
2286 | { | ||
2287 | unsigned long val; | ||
2288 | |||
2289 | DEBUGF("Starting prerecording\n"); | ||
2290 | |||
2291 | prerecord_index = 0; | ||
2292 | prerecord_count = 0; | ||
2293 | prerecord_timeout = current_tick + HZ; | ||
2294 | memset(prerecord_buffer, 0, sizeof(prerecord_buffer)); | ||
2295 | reset_mp3_buffer(); | ||
2296 | |||
2297 | is_prerecording = true; | ||
2298 | |||
2299 | /* Stop monitoring and start the encoder */ | ||
2300 | shadow_io_control_main &= ~(1 << 10); | ||
2301 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2302 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2303 | |||
2304 | /* Wait until the DSP has accepted the settings */ | ||
2305 | do | ||
2306 | { | ||
2307 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2308 | } while(val & 1); | ||
2309 | |||
2310 | is_recording = true; | ||
2311 | saving_status = NOT_SAVING; | ||
2312 | |||
2313 | demand_irq_enable(true); | ||
2314 | } | ||
2315 | |||
2316 | static void start_recording(void) | ||
2317 | { | ||
2318 | unsigned long val; | ||
2319 | |||
2320 | if(is_prerecording) | ||
2321 | { | ||
2322 | /* This will make the IRQ handler start recording | ||
2323 | for real, i.e send MPEG_SAVE_DATA messages when | ||
2324 | the buffer is full */ | ||
2325 | is_prerecording = false; | ||
2326 | } | ||
2327 | else | ||
2328 | { | ||
2329 | /* If prerecording is off, we need to stop the monitoring | ||
2330 | and start the encoder */ | ||
2331 | shadow_io_control_main &= ~(1 << 10); | ||
2332 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2333 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2334 | |||
2335 | /* Wait until the DSP has accepted the settings */ | ||
2336 | do | ||
2337 | { | ||
2338 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2339 | } while(val & 1); | ||
2340 | } | ||
2341 | |||
2342 | is_recording = true; | ||
2343 | saving_status = NOT_SAVING; | ||
2344 | paused = false; | ||
2345 | |||
2346 | /* Store the current time */ | ||
2347 | if(prerecording) | ||
2348 | record_start_time = current_tick - prerecord_count * HZ; | ||
2349 | else | ||
2350 | record_start_time = current_tick; | ||
2351 | |||
2352 | pause_start_time = 0; | ||
2353 | |||
2354 | demand_irq_enable(true); | ||
2355 | } | ||
2356 | |||
2357 | static void pause_recording(void) | ||
2358 | { | ||
2359 | pause_start_time = current_tick; | ||
2360 | |||
2361 | /* Set the pause bit */ | ||
2362 | shadow_soft_mute |= 2; | ||
2363 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1); | ||
2364 | |||
2365 | paused = true; | ||
2366 | } | ||
2367 | |||
2368 | static void resume_recording(void) | ||
2369 | { | ||
2370 | paused = false; | ||
2371 | |||
2372 | /* Clear the pause bit */ | ||
2373 | shadow_soft_mute &= ~2; | ||
2374 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1); | ||
2375 | |||
2376 | /* Compensate for the time we have been paused */ | ||
2377 | if(pause_start_time) | ||
2378 | { | ||
2379 | record_start_time = | ||
2380 | current_tick - (pause_start_time - record_start_time); | ||
2381 | pause_start_time = 0; | ||
2382 | } | ||
2383 | } | ||
2384 | |||
2385 | static void stop_recording(void) | ||
2386 | { | ||
2387 | unsigned long val; | ||
2388 | |||
2389 | /* Let it finish the last frame */ | ||
2390 | if(!paused) | ||
2391 | pause_recording(); | ||
2392 | sleep(HZ/5); | ||
2393 | |||
2394 | demand_irq_enable(false); | ||
2395 | |||
2396 | is_recording = false; | ||
2397 | is_prerecording = false; | ||
2398 | |||
2399 | last_rec_bytes = num_rec_bytes; | ||
2400 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count_end, 1); | ||
2401 | last_rec_time = current_tick - record_start_time; | ||
2402 | |||
2403 | /* Start monitoring */ | ||
2404 | shadow_io_control_main |= (1 << 10); | ||
2405 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2406 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2407 | |||
2408 | /* Wait until the DSP has accepted the settings */ | ||
2409 | do | ||
2410 | { | ||
2411 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2412 | } while(val & 1); | ||
2413 | |||
2414 | resume_recording(); | ||
2415 | } | ||
2416 | |||
2417 | void audio_set_recording_options(struct audio_recording_options *options) | ||
2418 | { | ||
2419 | bool is_mpeg1; | ||
2420 | |||
2421 | is_mpeg1 = (options->rec_frequency < 3)?true:false; | ||
2422 | |||
2423 | rec_version_index = is_mpeg1?3:2; | ||
2424 | rec_frequency_index = options->rec_frequency % 3; | ||
2425 | |||
2426 | shadow_encoder_control = (options->rec_quality << 17) | | ||
2427 | (rec_frequency_index << 10) | | ||
2428 | ((is_mpeg1?1:0) << 9) | | ||
2429 | (((options->rec_channels * 2 + 1) & 3) << 6) | | ||
2430 | (1 << 5) /* MS-stereo */ | | ||
2431 | (1 << 2) /* Is an original */; | ||
2432 | mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); | ||
2433 | |||
2434 | DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); | ||
2435 | |||
2436 | shadow_soft_mute = options->rec_editable?4:0; | ||
2437 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); | ||
2438 | |||
2439 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); | ||
2440 | |||
2441 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ | ||
2442 | ((options->rec_source < 2)?1:2) << 8) | /* Input select */ | ||
2443 | (1 << 5) | /* SDO strobe invert */ | ||
2444 | ((is_mpeg1?0:1) << 3) | | ||
2445 | (1 << 2) | /* Inverted SIBC clock signal */ | ||
2446 | 1; /* Validate */ | ||
2447 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main,1); | ||
2448 | |||
2449 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2450 | |||
2451 | if(options->rec_source == AUDIO_SRC_MIC) | ||
2452 | { | ||
2453 | /* Copy left channel to right (mono mode) */ | ||
2454 | mas_codec_writereg(8, 0x8000); | ||
2455 | } | ||
2456 | else | ||
2457 | { | ||
2458 | /* Stereo input mode */ | ||
2459 | mas_codec_writereg(8, 0); | ||
2460 | } | ||
2461 | |||
2462 | prerecording_max_seconds = options->rec_prerecord_time; | ||
2463 | if(prerecording_max_seconds) | ||
2464 | { | ||
2465 | prerecording = true; | ||
2466 | start_prerecording(); | ||
2467 | } | ||
2468 | else | ||
2469 | { | ||
2470 | prerecording = false; | ||
2471 | is_prerecording = false; | ||
2472 | is_recording = false; | ||
2473 | } | ||
2474 | } | ||
2475 | |||
2476 | /* If use_mic is true, the left gain is used */ | ||
2477 | void audio_set_recording_gain(int left, int right, int type) | ||
2478 | { | ||
2479 | /* Enable both left and right A/D */ | ||
2480 | shadow_codec_reg0 = (left << 12) | | ||
2481 | (right << 8) | | ||
2482 | (left << 4) | | ||
2483 | (type==AUDIO_GAIN_MIC?0x0008:0) | /* Connect left A/D to mic */ | ||
2484 | 0x0007; | ||
2485 | mas_codec_writereg(0x0, shadow_codec_reg0); | ||
2486 | } | ||
2487 | |||
2488 | #if CONFIG_TUNER & S1A0903X01 | ||
2489 | /* Get the (unpitched) MAS PLL frequency, for avoiding FM interference with the | ||
2490 | * Samsung tuner. Zero means unknown. Currently handles recording from analog | ||
2491 | * input only. */ | ||
2492 | int mpeg_get_mas_pllfreq(void) | ||
2493 | { | ||
2494 | if (mpeg_mode != MPEG_ENCODER) | ||
2495 | return 0; | ||
2496 | |||
2497 | if (rec_frequency_index == 0) /* 44.1 kHz / 22.05 kHz */ | ||
2498 | return 22579000; | ||
2499 | else | ||
2500 | return 24576000; | ||
2501 | } | ||
2502 | #endif /* CONFIG_TUNER & S1A0903X01 */ | ||
2503 | |||
2504 | /* try to make some kind of beep, also in recording mode */ | ||
2505 | void audio_beep(int duration) | ||
2506 | { | ||
2507 | long starttick = current_tick; | ||
2508 | do | ||
2509 | { /* toggle bit 0 of codec register 0, toggling the DAC off & on. | ||
2510 | * While this is still audible even without an external signal, | ||
2511 | * it doesn't affect the (pre-)recording. */ | ||
2512 | mas_codec_writereg(0, shadow_codec_reg0 ^ 1); | ||
2513 | mas_codec_writereg(0, shadow_codec_reg0); | ||
2514 | yield(); | ||
2515 | } | ||
2516 | while (current_tick - starttick < duration); | ||
2517 | } | ||
2518 | |||
2519 | void audio_new_file(const char *filename) | ||
2520 | { | ||
2521 | mpeg_errno = 0; | ||
2522 | |||
2523 | strncpy(recording_filename, filename, MAX_PATH - 1); | ||
2524 | recording_filename[MAX_PATH - 1] = 0; | ||
2525 | |||
2526 | queue_post(&mpeg_queue, MPEG_NEW_FILE, 0); | ||
2527 | } | ||
2528 | |||
2529 | unsigned long audio_recorded_time(void) | ||
2530 | { | ||
2531 | if(is_prerecording) | ||
2532 | return prerecord_count * HZ; | ||
2533 | |||
2534 | if(is_recording) | ||
2535 | { | ||
2536 | if(paused) | ||
2537 | return pause_start_time - record_start_time; | ||
2538 | else | ||
2539 | return current_tick - record_start_time; | ||
2540 | } | ||
2541 | |||
2542 | return 0; | ||
2543 | } | ||
2544 | |||
2545 | unsigned long audio_num_recorded_bytes(void) | ||
2546 | { | ||
2547 | int num_bytes; | ||
2548 | int index; | ||
2549 | |||
2550 | if(is_recording) | ||
2551 | { | ||
2552 | if(is_prerecording) | ||
2553 | { | ||
2554 | index = prerecord_index - prerecord_count; | ||
2555 | if(index < 0) | ||
2556 | index += prerecording_max_seconds; | ||
2557 | |||
2558 | num_bytes = audiobuf_write - prerecord_buffer[index].mempos; | ||
2559 | if(num_bytes < 0) | ||
2560 | num_bytes += audiobuflen; | ||
2561 | |||
2562 | return num_bytes;; | ||
2563 | } | ||
2564 | else | ||
2565 | return num_rec_bytes; | ||
2566 | } | ||
2567 | else | ||
2568 | return 0; | ||
2569 | } | ||
2570 | |||
2571 | #else /* SIMULATOR */ | ||
2572 | |||
2573 | /* dummies coming up */ | ||
2574 | |||
2575 | void audio_init_playback(void) | ||
2576 | { | ||
2577 | /* a dummy */ | ||
2578 | } | ||
2579 | unsigned long audio_recorded_time(void) | ||
2580 | { | ||
2581 | /* a dummy */ | ||
2582 | return 0; | ||
2583 | } | ||
2584 | void audio_beep(int duration) | ||
2585 | { | ||
2586 | /* a dummy */ | ||
2587 | (void)duration; | ||
2588 | } | ||
2589 | void audio_pause_recording(void) | ||
2590 | { | ||
2591 | /* a dummy */ | ||
2592 | } | ||
2593 | void audio_resume_recording(void) | ||
2594 | { | ||
2595 | /* a dummy */ | ||
2596 | } | ||
2597 | unsigned long audio_num_recorded_bytes(void) | ||
2598 | { | ||
2599 | /* a dummy */ | ||
2600 | return 0; | ||
2601 | } | ||
2602 | void audio_record(const char *filename) | ||
2603 | { | ||
2604 | /* a dummy */ | ||
2605 | (void)filename; | ||
2606 | } | ||
2607 | void audio_new_file(const char *filename) | ||
2608 | { | ||
2609 | /* a dummy */ | ||
2610 | (void)filename; | ||
2611 | } | ||
2612 | |||
2613 | void audio_set_recording_gain(int left, int right, int type) | ||
2614 | { | ||
2615 | /* a dummy */ | ||
2616 | (void)left; | ||
2617 | (void)right; | ||
2618 | (void)type; | ||
2619 | } | ||
2620 | void audio_init_recording(unsigned int buffer_offset) | ||
2621 | { | ||
2622 | /* a dummy */ | ||
2623 | (void)buffer_offset; | ||
2624 | } | ||
2625 | void audio_set_recording_options(struct audio_recording_options *options) | ||
2626 | { | ||
2627 | /* a dummy */ | ||
2628 | (void)options; | ||
2629 | } | ||
2630 | #endif /* SIMULATOR */ | ||
2631 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2632 | |||
2633 | void audio_play(long offset) | ||
2634 | { | ||
2635 | #ifdef SIMULATOR | ||
2636 | char* trackname; | ||
2637 | int steps=0; | ||
2638 | |||
2639 | is_playing = true; | ||
2640 | |||
2641 | do { | ||
2642 | trackname = playlist_peek( steps ); | ||
2643 | if (!trackname) | ||
2644 | break; | ||
2645 | if(mp3info(&taginfo, trackname)) { | ||
2646 | /* bad mp3, move on */ | ||
2647 | if(++steps > playlist_amount()) | ||
2648 | break; | ||
2649 | continue; | ||
2650 | } | ||
2651 | #ifdef HAVE_MPEG_PLAY | ||
2652 | real_mpeg_play(trackname); | ||
2653 | #endif | ||
2654 | playlist_next(steps); | ||
2655 | taginfo.offset = offset; | ||
2656 | set_elapsed(&taginfo); | ||
2657 | is_playing = true; | ||
2658 | playing = true; | ||
2659 | break; | ||
2660 | } while(1); | ||
2661 | #else /* !SIMULATOR */ | ||
2662 | is_playing = true; | ||
2663 | |||
2664 | queue_post(&mpeg_queue, MPEG_PLAY, offset); | ||
2665 | #endif /* !SIMULATOR */ | ||
2666 | |||
2667 | mpeg_errno = 0; | ||
2668 | } | ||
2669 | |||
2670 | void audio_stop(void) | ||
2671 | { | ||
2672 | #ifndef SIMULATOR | ||
2673 | if (playing) | ||
2674 | { | ||
2675 | struct trackdata *track = get_trackdata(0); | ||
2676 | prev_track_elapsed = track->id3.elapsed; | ||
2677 | } | ||
2678 | mpeg_stop_done = false; | ||
2679 | queue_post(&mpeg_queue, MPEG_STOP, 0); | ||
2680 | while(!mpeg_stop_done) | ||
2681 | yield(); | ||
2682 | #else /* SIMULATOR */ | ||
2683 | paused = false; | ||
2684 | is_playing = false; | ||
2685 | playing = false; | ||
2686 | #endif /* SIMULATOR */ | ||
2687 | } | ||
2688 | |||
2689 | /* dummy */ | ||
2690 | void audio_stop_recording(void) | ||
2691 | { | ||
2692 | audio_stop(); | ||
2693 | } | ||
2694 | |||
2695 | void audio_pause(void) | ||
2696 | { | ||
2697 | #ifndef SIMULATOR | ||
2698 | queue_post(&mpeg_queue, MPEG_PAUSE, 0); | ||
2699 | #else /* SIMULATOR */ | ||
2700 | is_playing = true; | ||
2701 | playing = false; | ||
2702 | paused = true; | ||
2703 | #endif /* SIMULATOR */ | ||
2704 | } | ||
2705 | |||
2706 | void audio_resume(void) | ||
2707 | { | ||
2708 | #ifndef SIMULATOR | ||
2709 | queue_post(&mpeg_queue, MPEG_RESUME, 0); | ||
2710 | #else /* SIMULATOR */ | ||
2711 | is_playing = true; | ||
2712 | playing = true; | ||
2713 | paused = false; | ||
2714 | #endif /* SIMULATOR */ | ||
2715 | } | ||
2716 | |||
2717 | void audio_next(void) | ||
2718 | { | ||
2719 | #ifndef SIMULATOR | ||
2720 | queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); | ||
2721 | queue_post(&mpeg_queue, MPEG_NEXT, 0); | ||
2722 | #else /* SIMULATOR */ | ||
2723 | char* file; | ||
2724 | int steps = 1; | ||
2725 | int index; | ||
2726 | |||
2727 | do { | ||
2728 | file = playlist_peek(steps); | ||
2729 | if(!file) | ||
2730 | break; | ||
2731 | if(mp3info(&taginfo, file)) { | ||
2732 | if(++steps > playlist_amount()) | ||
2733 | break; | ||
2734 | continue; | ||
2735 | } | ||
2736 | index = playlist_next(steps); | ||
2737 | taginfo.index = index; | ||
2738 | current_track_counter++; | ||
2739 | is_playing = true; | ||
2740 | playing = true; | ||
2741 | break; | ||
2742 | } while(1); | ||
2743 | #endif /* SIMULATOR */ | ||
2744 | } | ||
2745 | |||
2746 | void audio_prev(void) | ||
2747 | { | ||
2748 | #ifndef SIMULATOR | ||
2749 | queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); | ||
2750 | queue_post(&mpeg_queue, MPEG_PREV, 0); | ||
2751 | #else /* SIMULATOR */ | ||
2752 | char* file; | ||
2753 | int steps = -1; | ||
2754 | int index; | ||
2755 | |||
2756 | do { | ||
2757 | file = playlist_peek(steps); | ||
2758 | if(!file) | ||
2759 | break; | ||
2760 | if(mp3info(&taginfo, file)) { | ||
2761 | steps--; | ||
2762 | continue; | ||
2763 | } | ||
2764 | index = playlist_next(steps); | ||
2765 | taginfo.index = index; | ||
2766 | current_track_counter++; | ||
2767 | is_playing = true; | ||
2768 | playing = true; | ||
2769 | break; | ||
2770 | } while(1); | ||
2771 | #endif /* SIMULATOR */ | ||
2772 | } | ||
2773 | |||
2774 | void audio_ff_rewind(long newtime) | ||
2775 | { | ||
2776 | #ifndef SIMULATOR | ||
2777 | queue_post(&mpeg_queue, MPEG_FF_REWIND, newtime); | ||
2778 | #else /* SIMULATOR */ | ||
2779 | (void)newtime; | ||
2780 | #endif /* SIMULATOR */ | ||
2781 | } | ||
2782 | |||
2783 | void audio_flush_and_reload_tracks(void) | ||
2784 | { | ||
2785 | #ifndef SIMULATOR | ||
2786 | queue_post(&mpeg_queue, MPEG_FLUSH_RELOAD, 0); | ||
2787 | #endif /* !SIMULATOR*/ | ||
2788 | } | ||
2789 | |||
2790 | int audio_status(void) | ||
2791 | { | ||
2792 | int ret = 0; | ||
2793 | |||
2794 | if(is_playing) | ||
2795 | ret |= AUDIO_STATUS_PLAY; | ||
2796 | |||
2797 | if(paused) | ||
2798 | ret |= AUDIO_STATUS_PAUSE; | ||
2799 | |||
2800 | #if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) | ||
2801 | if(is_recording && !is_prerecording) | ||
2802 | ret |= AUDIO_STATUS_RECORD; | ||
2803 | |||
2804 | if(is_prerecording) | ||
2805 | ret |= AUDIO_STATUS_PRERECORD; | ||
2806 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2807 | |||
2808 | if(mpeg_errno) | ||
2809 | ret |= AUDIO_STATUS_ERROR; | ||
2810 | |||
2811 | return ret; | ||
2812 | } | ||
2813 | |||
2814 | unsigned int audio_error(void) | ||
2815 | { | ||
2816 | return mpeg_errno; | ||
2817 | } | ||
2818 | |||
2819 | void audio_error_clear(void) | ||
2820 | { | ||
2821 | mpeg_errno = 0; | ||
2822 | } | ||
2823 | |||
2824 | #ifdef SIMULATOR | ||
2825 | static void mpeg_thread(void) | ||
2826 | { | ||
2827 | struct mp3entry* id3; | ||
2828 | while ( 1 ) { | ||
2829 | if (is_playing) { | ||
2830 | id3 = audio_current_track(); | ||
2831 | if (!paused) | ||
2832 | { | ||
2833 | id3->elapsed+=1000; | ||
2834 | id3->offset+=1000; | ||
2835 | } | ||
2836 | if (id3->elapsed>=id3->length) | ||
2837 | audio_next(); | ||
2838 | } | ||
2839 | sleep(HZ); | ||
2840 | } | ||
2841 | } | ||
2842 | #endif /* SIMULATOR */ | ||
2843 | |||
2844 | void audio_init(void) | ||
2845 | { | ||
2846 | mpeg_errno = 0; | ||
2847 | |||
2848 | #ifndef SIMULATOR | ||
2849 | audiobuflen = audiobufend - audiobuf; | ||
2850 | queue_init(&mpeg_queue, true); | ||
2851 | #endif /* !SIMULATOR */ | ||
2852 | create_thread(mpeg_thread, mpeg_stack, | ||
2853 | sizeof(mpeg_stack), 0, mpeg_thread_name | ||
2854 | IF_PRIO(, PRIORITY_SYSTEM) | ||
2855 | IF_COP(, CPU)); | ||
2856 | |||
2857 | memset(trackdata, sizeof(trackdata), 0); | ||
2858 | |||
2859 | #if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) | ||
2860 | if (HW_MASK & PR_ACTIVE_HIGH) | ||
2861 | and_b(~0x08, &PADRH); | ||
2862 | else | ||
2863 | or_b(0x08, &PADRH); | ||
2864 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2865 | |||
2866 | #ifdef DEBUG | ||
2867 | dbg_timer_start(); | ||
2868 | dbg_cnt2us(0); | ||
2869 | #endif /* DEBUG */ | ||
2870 | } | ||
2871 | |||
2872 | #endif /* CONFIG_CODEC != SWCODEC */ | ||
diff --git a/firmware/replaygain.c b/firmware/replaygain.c deleted file mode 100644 index e160a1b23d..0000000000 --- a/firmware/replaygain.c +++ /dev/null | |||
@@ -1,457 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Magnus Holmgren | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <ctype.h> | ||
23 | #include <inttypes.h> | ||
24 | #include <math.h> | ||
25 | #include <stdbool.h> | ||
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include <system.h> | ||
30 | #include "id3.h" | ||
31 | #include "debug.h" | ||
32 | #include "replaygain.h" | ||
33 | |||
34 | /* The fixed point math routines (with the exception of fp_atof) are based | ||
35 | * on oMathFP by Dan Carter (http://orbisstudios.com). | ||
36 | */ | ||
37 | |||
38 | /* 12 bits of precision gives fairly accurate result, but still allows a | ||
39 | * compact implementation. The math code supports up to 13... | ||
40 | */ | ||
41 | |||
42 | #define FP_BITS (12) | ||
43 | #define FP_MASK ((1 << FP_BITS) - 1) | ||
44 | #define FP_ONE (1 << FP_BITS) | ||
45 | #define FP_TWO (2 << FP_BITS) | ||
46 | #define FP_HALF (1 << (FP_BITS - 1)) | ||
47 | #define FP_LN2 ( 45426 >> (16 - FP_BITS)) | ||
48 | #define FP_LN2_INV ( 94548 >> (16 - FP_BITS)) | ||
49 | #define FP_EXP_ZERO ( 10922 >> (16 - FP_BITS)) | ||
50 | #define FP_EXP_ONE ( -182 >> (16 - FP_BITS)) | ||
51 | #define FP_EXP_TWO ( 4 >> (16 - FP_BITS)) | ||
52 | #define FP_INF (0x7fffffff) | ||
53 | #define FP_LN10 (150902 >> (16 - FP_BITS)) | ||
54 | |||
55 | #define FP_MAX_DIGITS (4) | ||
56 | #define FP_MAX_DIGITS_INT (10000) | ||
57 | |||
58 | #define FP_FAST_MUL_DIV | ||
59 | |||
60 | #ifdef FP_FAST_MUL_DIV | ||
61 | |||
62 | /* These macros can easily overflow, but they are good enough for our uses, | ||
63 | * and saves some code. | ||
64 | */ | ||
65 | #define fp_mul(x, y) (((x) * (y)) >> FP_BITS) | ||
66 | #define fp_div(x, y) (((x) << FP_BITS) / (y)) | ||
67 | |||
68 | #else | ||
69 | |||
70 | static long fp_mul(long x, long y) | ||
71 | { | ||
72 | long x_neg = 0; | ||
73 | long y_neg = 0; | ||
74 | long rc; | ||
75 | |||
76 | if ((x == 0) || (y == 0)) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | if (x < 0) | ||
82 | { | ||
83 | x_neg = 1; | ||
84 | x = -x; | ||
85 | } | ||
86 | |||
87 | if (y < 0) | ||
88 | { | ||
89 | y_neg = 1; | ||
90 | y = -y; | ||
91 | } | ||
92 | |||
93 | rc = (((x >> FP_BITS) * (y >> FP_BITS)) << FP_BITS) | ||
94 | + (((x & FP_MASK) * (y & FP_MASK)) >> FP_BITS) | ||
95 | + ((x & FP_MASK) * (y >> FP_BITS)) | ||
96 | + ((x >> FP_BITS) * (y & FP_MASK)); | ||
97 | |||
98 | if ((x_neg ^ y_neg) == 1) | ||
99 | { | ||
100 | rc = -rc; | ||
101 | } | ||
102 | |||
103 | return rc; | ||
104 | } | ||
105 | |||
106 | static long fp_div(long x, long y) | ||
107 | { | ||
108 | long x_neg = 0; | ||
109 | long y_neg = 0; | ||
110 | long shifty; | ||
111 | long rc; | ||
112 | int msb = 0; | ||
113 | int lsb = 0; | ||
114 | |||
115 | if (x == 0) | ||
116 | { | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | if (y == 0) | ||
121 | { | ||
122 | return (x < 0) ? -FP_INF : FP_INF; | ||
123 | } | ||
124 | |||
125 | if (x < 0) | ||
126 | { | ||
127 | x_neg = 1; | ||
128 | x = -x; | ||
129 | } | ||
130 | |||
131 | if (y < 0) | ||
132 | { | ||
133 | y_neg = 1; | ||
134 | y = -y; | ||
135 | } | ||
136 | |||
137 | while ((x & (1 << (30 - msb))) == 0) | ||
138 | { | ||
139 | msb++; | ||
140 | } | ||
141 | |||
142 | while ((y & (1 << lsb)) == 0) | ||
143 | { | ||
144 | lsb++; | ||
145 | } | ||
146 | |||
147 | shifty = FP_BITS - (msb + lsb); | ||
148 | rc = ((x << msb) / (y >> lsb)); | ||
149 | |||
150 | if (shifty > 0) | ||
151 | { | ||
152 | rc <<= shifty; | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | rc >>= -shifty; | ||
157 | } | ||
158 | |||
159 | if ((x_neg ^ y_neg) == 1) | ||
160 | { | ||
161 | rc = -rc; | ||
162 | } | ||
163 | |||
164 | return rc; | ||
165 | } | ||
166 | |||
167 | #endif /* FP_FAST_MUL_DIV */ | ||
168 | |||
169 | static long fp_exp(long x) | ||
170 | { | ||
171 | long k; | ||
172 | long z; | ||
173 | long R; | ||
174 | long xp; | ||
175 | |||
176 | if (x == 0) | ||
177 | { | ||
178 | return FP_ONE; | ||
179 | } | ||
180 | |||
181 | k = (fp_mul(abs(x), FP_LN2_INV) + FP_HALF) & ~FP_MASK; | ||
182 | |||
183 | if (x < 0) | ||
184 | { | ||
185 | k = -k; | ||
186 | } | ||
187 | |||
188 | x -= fp_mul(k, FP_LN2); | ||
189 | z = fp_mul(x, x); | ||
190 | R = FP_TWO + fp_mul(z, FP_EXP_ZERO + fp_mul(z, FP_EXP_ONE | ||
191 | + fp_mul(z, FP_EXP_TWO))); | ||
192 | xp = FP_ONE + fp_div(fp_mul(FP_TWO, x), R - x); | ||
193 | |||
194 | if (k < 0) | ||
195 | { | ||
196 | k = FP_ONE >> (-k >> FP_BITS); | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | k = FP_ONE << (k >> FP_BITS); | ||
201 | } | ||
202 | |||
203 | return fp_mul(k, xp); | ||
204 | } | ||
205 | |||
206 | static long fp_exp10(long x) | ||
207 | { | ||
208 | if (x == 0) | ||
209 | { | ||
210 | return FP_ONE; | ||
211 | } | ||
212 | |||
213 | return fp_exp(fp_mul(FP_LN10, x)); | ||
214 | } | ||
215 | |||
216 | static long fp_atof(const char* s, int precision) | ||
217 | { | ||
218 | long int_part = 0; | ||
219 | long int_one = 1 << precision; | ||
220 | long frac_part = 0; | ||
221 | long frac_count = 0; | ||
222 | long frac_max = ((precision * 4) + 12) / 13; | ||
223 | long frac_max_int = 1; | ||
224 | long sign = 1; | ||
225 | bool point = false; | ||
226 | |||
227 | while ((*s != '\0') && isspace(*s)) | ||
228 | { | ||
229 | s++; | ||
230 | } | ||
231 | |||
232 | if (*s == '-') | ||
233 | { | ||
234 | sign = -1; | ||
235 | s++; | ||
236 | } | ||
237 | else if (*s == '+') | ||
238 | { | ||
239 | s++; | ||
240 | } | ||
241 | |||
242 | while (*s != '\0') | ||
243 | { | ||
244 | if (*s == '.') | ||
245 | { | ||
246 | if (point) | ||
247 | { | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | point = true; | ||
252 | } | ||
253 | else if (isdigit(*s)) | ||
254 | { | ||
255 | if (point) | ||
256 | { | ||
257 | if (frac_count < frac_max) | ||
258 | { | ||
259 | frac_part = frac_part * 10 + (*s - '0'); | ||
260 | frac_count++; | ||
261 | frac_max_int *= 10; | ||
262 | } | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | int_part = int_part * 10 + (*s - '0'); | ||
267 | } | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | s++; | ||
275 | } | ||
276 | |||
277 | while (frac_count < frac_max) | ||
278 | { | ||
279 | frac_part *= 10; | ||
280 | frac_count++; | ||
281 | frac_max_int *= 10; | ||
282 | } | ||
283 | |||
284 | return sign * ((int_part * int_one) | ||
285 | + (((int64_t) frac_part * int_one) / frac_max_int)); | ||
286 | } | ||
287 | |||
288 | static long convert_gain(long gain) | ||
289 | { | ||
290 | /* Don't allow unreasonably low or high gain changes. | ||
291 | * Our math code can't handle it properly anyway. :) | ||
292 | */ | ||
293 | if (gain < (-48 * FP_ONE)) | ||
294 | { | ||
295 | gain = -48 * FP_ONE; | ||
296 | } | ||
297 | |||
298 | if (gain > (17 * FP_ONE)) | ||
299 | { | ||
300 | gain = 17 * FP_ONE; | ||
301 | } | ||
302 | |||
303 | gain = fp_exp10(gain / 20) << (24 - FP_BITS); | ||
304 | |||
305 | return gain; | ||
306 | } | ||
307 | |||
308 | /* Get the sample scale factor in Q7.24 format from a gain value. Returns 0 | ||
309 | * for no gain. | ||
310 | * | ||
311 | * str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored. | ||
312 | */ | ||
313 | static long get_replaygain(const char* str) | ||
314 | { | ||
315 | long gain = 0; | ||
316 | |||
317 | if (str) | ||
318 | { | ||
319 | gain = fp_atof(str, FP_BITS); | ||
320 | gain = convert_gain(gain); | ||
321 | } | ||
322 | |||
323 | return gain; | ||
324 | } | ||
325 | |||
326 | /* Get the peak volume in Q7.24 format. | ||
327 | * | ||
328 | * str Peak volume. Full scale is specified as "1.0". Returns 0 for no peak. | ||
329 | */ | ||
330 | static long get_replaypeak(const char* str) | ||
331 | { | ||
332 | long peak = 0; | ||
333 | |||
334 | if (str) | ||
335 | { | ||
336 | peak = fp_atof(str, 24); | ||
337 | } | ||
338 | |||
339 | return peak; | ||
340 | } | ||
341 | |||
342 | /* Get a sample scale factor in Q7.24 format from a gain value. | ||
343 | * | ||
344 | * int_gain Gain in dB, multiplied by 100. | ||
345 | */ | ||
346 | long get_replaygain_int(long int_gain) | ||
347 | { | ||
348 | return convert_gain(int_gain * FP_ONE / 100); | ||
349 | } | ||
350 | |||
351 | /* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a | ||
352 | * valid tag is found, update mp3entry struct accordingly. Existing values | ||
353 | * are not overwritten. Returns number of bytes written to buffer. | ||
354 | * | ||
355 | * key Name of the tag. | ||
356 | * value Value of the tag. | ||
357 | * entry mp3entry struct to update. | ||
358 | * buffer Where to store the text for gain values (for later display). | ||
359 | * length Bytes left in buffer. | ||
360 | */ | ||
361 | long parse_replaygain(const char* key, const char* value, | ||
362 | struct mp3entry* entry, char* buffer, int length) | ||
363 | { | ||
364 | char **p = NULL; | ||
365 | |||
366 | if (((strcasecmp(key, "replaygain_track_gain") == 0) | ||
367 | || (strcasecmp(key, "rg_radio") == 0)) && !entry->track_gain) | ||
368 | { | ||
369 | entry->track_gain = get_replaygain(value); | ||
370 | p = &(entry->track_gain_string); | ||
371 | } | ||
372 | else if (((strcasecmp(key, "replaygain_album_gain") == 0) | ||
373 | || (strcasecmp(key, "rg_audiophile") == 0)) && !entry->album_gain) | ||
374 | { | ||
375 | entry->album_gain = get_replaygain(value); | ||
376 | p = &(entry->album_gain_string); | ||
377 | } | ||
378 | else if (((strcasecmp(key, "replaygain_track_peak") == 0) | ||
379 | || (strcasecmp(key, "rg_peak") == 0)) && !entry->track_peak) | ||
380 | { | ||
381 | entry->track_peak = get_replaypeak(value); | ||
382 | } | ||
383 | else if ((strcasecmp(key, "replaygain_album_peak") == 0) | ||
384 | && !entry->album_peak) | ||
385 | { | ||
386 | entry->album_peak = get_replaypeak(value); | ||
387 | } | ||
388 | |||
389 | if (p) | ||
390 | { | ||
391 | int len = strlen(value); | ||
392 | |||
393 | len = MIN(len, length - 1); | ||
394 | |||
395 | /* A few characters just isn't interesting... */ | ||
396 | if (len > 1) | ||
397 | { | ||
398 | strncpy(buffer, value, len); | ||
399 | buffer[len] = 0; | ||
400 | *p = buffer; | ||
401 | return len + 1; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | /* Set ReplayGain values from integers. Existing values are not overwritten. | ||
409 | * Returns number of bytes written to buffer. | ||
410 | * | ||
411 | * album If true, set album values, otherwise set track values. | ||
412 | * gain Gain value in dB, multiplied by 512. 0 for no gain. | ||
413 | * peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no | ||
414 | * peak volume. | ||
415 | * buffer Where to store the text for gain values (for later display). | ||
416 | * length Bytes left in buffer. | ||
417 | */ | ||
418 | long parse_replaygain_int(bool album, long gain, long peak, | ||
419 | struct mp3entry* entry, char* buffer, int length) | ||
420 | { | ||
421 | long len = 0; | ||
422 | |||
423 | if (buffer != NULL) | ||
424 | { | ||
425 | len = snprintf(buffer, length, "%d.%02d dB", gain / 512, | ||
426 | ((abs(gain) & 0x01ff) * 100 + 256) / 512); | ||
427 | len++; | ||
428 | } | ||
429 | |||
430 | if (gain != 0) | ||
431 | { | ||
432 | gain = convert_gain(gain * FP_ONE / 512); | ||
433 | } | ||
434 | |||
435 | if (album) | ||
436 | { | ||
437 | entry->album_gain = gain; | ||
438 | entry->album_gain_string = buffer; | ||
439 | |||
440 | if (peak) | ||
441 | { | ||
442 | entry->album_peak = peak; | ||
443 | } | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | entry->track_gain = gain; | ||
448 | entry->track_gain_string = buffer; | ||
449 | |||
450 | if (peak) | ||
451 | { | ||
452 | entry->track_peak = peak; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | return len; | ||
457 | } | ||