Hallo
angeregt durch einen anderen Thread, den ich hier mal gelesen habe,
wollte ich auch einen eigenen MP3-Player bauen. Um zu testen, ob alles
funktioniert, benutze ich das STM32F4 Discovery Board. Dort habe ich
einen SD-Kartensockel angelötet. In meiner Software ist FATFS von
ElmChan drin, sowie der Helix-Decoder.
Zuerst habe ich, um den Decoder zu testen, einfach eine kleine MP3-Datei
als Array in den Flash des STM geladen und dann jeweils Stück für Stück
in den RAM kopiert. Damit hat das Abspielen eines MP3 wunderbar
geklappt, ohne Aussetzer oder so, selbst bei 48 kHz und 320 kBuit/s.
Jetzt will ich das MP3-File allerdings von der SD-Karte lesen! Da ich
später noch ein GUI implementieren will, habe ich mir gedacht, die SW
als kleinen Zustandsautomaten zu implementierren. Hier mein main-Code:
1 | __attribute__((noreturn)) void main(void)
|
2 | {
|
3 | state_t state = init_play_mp3;
|
4 | int ind = 0;
|
5 | int remain_bytes;
|
6 | int free_samples;
|
7 | int bytes_to_read;
|
8 |
|
9 | int br;
|
10 | int filesize;
|
11 | memset(buf, 0, sizeof(buf));
|
12 | memset(sdbuf, 0, sizeof(sdbuf));
|
13 |
|
14 |
|
15 | init_hardware();
|
16 |
|
17 | mci_media_init();
|
18 |
|
19 |
|
20 | f_mount(&fs, "0:", 1);
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | while(1)
|
27 | {
|
28 |
|
29 |
|
30 |
|
31 | switch(state)
|
32 | {
|
33 | case init_play_mp3:
|
34 | {
|
35 | init_mp3(buf, NUMOF_ELEMENTS(buf));
|
36 | state = preload_mp3_buffer;
|
37 |
|
38 | f_open(&fl, "0:/eminence_front.mp3", FA_READ);
|
39 | f_stat("0:/eminence_front.mp3", &fileinfo);
|
40 | filesize = fileinfo.fsize;
|
41 |
|
42 | ind = 0;
|
43 |
|
44 | break;
|
45 | }
|
46 |
|
47 | case preload_mp3_buffer:
|
48 | {
|
49 | int decoded_bytes;
|
50 |
|
51 | bytes_to_read = (filesize - ind) > BUFSZ ? BUFSZ : (filesize - ind);
|
52 |
|
53 | f_lseek(&fl, ind);
|
54 | f_read(&fl, sdbuf, bytes_to_read, &br);
|
55 |
|
56 |
|
57 | remain_bytes = decode_mp3(sdbuf, bytes_to_read);
|
58 | decoded_bytes = bytes_to_read - remain_bytes;
|
59 |
|
60 | ind = ind + decoded_bytes;
|
61 |
|
62 | free_samples = get_free_samps();
|
63 |
|
64 |
|
65 | if(free_samples < 4608)
|
66 | {
|
67 | start_playback();
|
68 | state = play_mp3;
|
69 | }
|
70 |
|
71 | break;
|
72 | }
|
73 |
|
74 | case play_mp3:
|
75 | {
|
76 |
|
77 | int prev_remain_bytes = 0;
|
78 | int decoded_bytes;
|
79 |
|
80 | free_samples = get_free_samps();
|
81 | if(free_samples > 2304*1)
|
82 | {
|
83 |
|
84 |
|
85 |
|
86 | GPIOC_BSRR = BIT_05;
|
87 | prev_remain_bytes = remain_bytes;
|
88 |
|
89 | remain_bytes = decode_mp3(&sdbuf[sizeof(sdbuf)-remain_bytes], remain_bytes);
|
90 | decoded_bytes = prev_remain_bytes - remain_bytes;
|
91 | ind = ind + decoded_bytes;
|
92 |
|
93 | GPIOC_BSRR = BIT_21;
|
94 | }
|
95 |
|
96 |
|
97 | if((remain_bytes < 512) || (decoded_bytes == 0))
|
98 | {
|
99 |
|
100 | GPIOD_BSRR = BIT_12;
|
101 | bytes_to_read = (filesize - ind) > BUFSZ ? BUFSZ : (filesize - ind);
|
102 |
|
103 | if(bytes_to_read < 100)
|
104 | {
|
105 | stop_playback();
|
106 | state = stop_mp3;
|
107 | break;
|
108 | }
|
109 | f_lseek(&fl, ind);
|
110 | f_read(&fl, sdbuf, bytes_to_read, &br);
|
111 |
|
112 | remain_bytes = bytes_to_read;
|
113 |
|
114 | GPIOD_BSRR = BIT_28;
|
115 | }
|
116 |
|
117 |
|
118 |
|
119 | break;
|
120 | }
|
121 |
|
122 | case stop_mp3:
|
123 | {
|
124 | free_mp3();
|
125 | state = init_play_mp3;
|
126 | ind = 0;
|
127 | break;
|
128 | }
|
129 | }
|
130 | }
|
131 | }
|
Jetzt stelle ich allerdings fest, dass es gelegentlich zu kleinen
Aussetzern kommt. Da alles funktioniert, wenn ich die Datei per memcpy()
aus dem Flash kopiere und so decodieren, muss das Problem am
Buffer-Management zusammen mit dem Lesen der SD-Karte zusammenhängen.
Leider sehe ich gerade nicht, wo man was optimieren müsste. Wäre es
möglich dass die Profis hier mal kurz auf meinen Code schauen? :-)