1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2004 Linus Nielsen Feltzing
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
25 static const struct plugin_api
* rb
;
27 static char *audiobuf
;
28 static ssize_t audiobuflen
;
29 unsigned char xingbuf
[1500];
30 char tmpname
[MAX_PATH
];
32 static void xingupdate(int percent
)
36 rb
->snprintf(buf
, 32, "%d%%", percent
);
37 rb
->lcd_puts(0, 1, buf
);
41 static int insert_data_in_file(const char *fname
, int fpos
, char *buf
, int num_bytes
)
47 rb
->snprintf(tmpname
, MAX_PATH
, "%s.tmp", fname
);
49 orig_fd
= rb
->open(fname
, O_RDONLY
);
51 return 10*orig_fd
- 1;
54 fd
= rb
->creat(tmpname
);
60 /* First, copy the initial portion (the ID3 tag) */
62 readlen
= rb
->read(orig_fd
, audiobuf
, fpos
);
66 return 10*readlen
- 3;
69 rc
= rb
->write(fd
, audiobuf
, readlen
);
77 /* Now insert the data into the file */
78 rc
= rb
->write(fd
, buf
, num_bytes
);
87 readlen
= rb
->read(orig_fd
, audiobuf
, audiobuflen
);
91 return 10*readlen
- 7;
94 rc
= rb
->write(fd
, audiobuf
, readlen
);
100 } while(readlen
> 0);
105 /* Remove the old file */
106 rc
= rb
->remove(fname
);
111 /* Replace the old file with the new */
112 rc
= rb
->rename(tmpname
, fname
);
120 static void fileerror(int rc
)
122 rb
->splashf(HZ
*2, "File error: %d", rc
);
125 static const unsigned char empty_id3_header
[] =
127 'I', 'D', '3', 0x04, 0x00, 0x00,
128 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */
131 static bool vbr_fix(const char *selected_file
)
133 struct mp3entry entry
;
142 rb
->lcd_clear_display();
143 rb
->lcd_puts_scroll(0, 0, selected_file
);
148 rc
= rb
->mp3info(&entry
, selected_file
);
154 fd
= rb
->open(selected_file
, O_RDWR
);
160 flen
= rb
->lseek(fd
, 0, SEEK_END
);
164 num_frames
= rb
->count_mp3_frames(fd
, entry
.first_frame_offset
,
168 /* Note: We don't need to pass a template header because it will be
169 taken from the mpeg stream */
170 framelen
= rb
->create_xing_header(fd
, entry
.first_frame_offset
,
171 flen
, xingbuf
, num_frames
, 0,
172 0, xingupdate
, true);
174 /* Try to fit the Xing header first in the stream. Replace the existing
175 VBR header if there is one, else see if there is room between the
176 ID3 tag and the first MP3 frame. */
177 if(entry
.first_frame_offset
- entry
.id3v2len
>=
178 (unsigned int)framelen
) {
179 DEBUGF("Using existing space between ID3 and first frame\n");
181 /* Seek to the beginning of the unused space */
182 rc
= rb
->lseek(fd
, entry
.id3v2len
, SEEK_SET
);
190 entry
.first_frame_offset
- entry
.id3v2len
- framelen
;
192 /* Fill the unused space with 0's (using the MP3 buffer)
193 and write it to the file */
196 rb
->memset(audiobuf
, 0, unused_space
);
197 rc
= rb
->write(fd
, audiobuf
, unused_space
);
205 /* Then write the Xing header */
206 rc
= rb
->write(fd
, xingbuf
, framelen
);
215 /* If not, insert some space. If there is an ID3 tag in the
216 file we only insert just enough to squeeze the Xing header
217 in. If not, we insert an additional empty ID3 tag of 4K. */
221 /* Nasty trick alert! The insert_data_in_file() function
222 uses the MP3 buffer when copying the data. We assume
223 that the ID3 tag isn't longer than 1MB so the xing
224 buffer won't be overwritten. */
226 if(entry
.first_frame_offset
) {
227 DEBUGF("Inserting %d bytes\n", framelen
);
230 DEBUGF("Inserting 4096+%d bytes\n", framelen
);
231 numbytes
= 4096 + framelen
;
233 rb
->memset(audiobuf
+ 0x100000, 0, numbytes
);
235 /* Insert the ID3 header */
236 rb
->memcpy(audiobuf
+ 0x100000, empty_id3_header
,
237 sizeof(empty_id3_header
));
240 /* Copy the Xing header */
241 rb
->memcpy(audiobuf
+ 0x100000 + numbytes
- framelen
,
244 rc
= insert_data_in_file(selected_file
,
245 entry
.first_frame_offset
,
246 audiobuf
+ 0x100000, numbytes
);
259 DEBUGF("Not a VBR file\n");
260 rb
->splash(HZ
*2, "Not a VBR file");
266 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void *parameter
)
273 audiobuf
= rb
->plugin_get_audio_buffer((size_t *)&audiobuflen
);
275 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
281 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
282 rb
->cpu_boost(false);