A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1
2/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
3/* Inflate code taken from WikiViewer plugin by Adam Gashlin */
4
5#include <codecs/lib/codeclib.h>
6
7#include "libgme/blargg_endian.h"
8#include "libgme/vgm_emu.h"
9#include "libgme/inflate/mallocer.h"
10#include "libgme/inflate/inflate.h"
11
12CODEC_HEADER
13
14/* Maximum number of bytes to process in one iteration */
15#define CHUNK_SIZE (1024*4)
16#define MAINMEMBUF 0
17
18static int16_t samples[CHUNK_SIZE] IBSS_ATTR;
19static struct Vgm_Emu vgm_emu;
20
21static void *inflatebuf; /* heap for gunzip */
22static char *songbuf; /* destination for uncompressed song */
23static uint32_t songbuflen=0; /* size of the song buffer */
24static uint32_t songlen=0; /* used size of the song buffer */
25
26static void codec_vgz_update_length(void)
27{
28 ci->id3->length = Track_get_length( &vgm_emu );
29 ci->id3->tail_trim = 4 * 1000;
30
31 if (vgm_emu.info.loop_length <= 0)
32 ci->id3->tail_trim = 0;
33
34 ci->id3->length += ci->id3->tail_trim;
35}
36
37static void codec_update_fade(void)
38{
39 /* for REPEAT_ONE we disable track limits */
40 Track_set_fade(&vgm_emu,
41 ci->loop_track() ? indefinite_count :
42 ci->id3->length - ci->id3->tail_trim,
43 ci->id3->tail_trim);
44}
45
46static void codec_update_elapsed(void)
47{
48 ci->set_elapsed(ci->loop_track() ? 0 : Track_tell(&vgm_emu));
49}
50
51/****************** rockbox interface ******************/
52
53/* this is the codec entry point */
54enum codec_status codec_main(enum codec_entry_call_reason reason)
55{
56 if (reason == CODEC_LOAD) {
57 /* we only render 16 bits */
58 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
59
60 /* 44 Khz, Interleaved stereo */
61 ci->configure(DSP_SET_FREQUENCY, 44100);
62 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
63
64 Vgm_init(&vgm_emu);
65 Vgm_set_sample_rate(&vgm_emu, 44100);
66 }
67
68 return CODEC_OK;
69}
70
71/* this is called for each file to process */
72enum codec_status codec_run(void)
73{
74 blargg_err_t err;
75 uint8_t *buf;
76 size_t n;
77 intptr_t param;
78
79 DEBUGF("VGM: next_track\n");
80 if (codec_init()) {
81 return CODEC_ERROR;
82 }
83
84 codec_set_replaygain(ci->id3);
85
86 /* Read the entire file */
87 DEBUGF("VGM: request file\n");
88 ci->seek_buffer(0);
89 buf = ci->request_buffer(&n, ci->filesize);
90 if (!buf) {
91 DEBUGF("VGM: file load failed\n");
92 return CODEC_ERROR;
93 }
94
95 /* If couldn't get the whole buffer
96 will trim file and put and 'end_command'
97 at the end*/
98 if (n < (size_t)ci->filesize) {
99 DEBUGF("VGM: file was trimmed\n");
100 }
101
102 /* If is gzipped decompress it */
103 if ( get_le16( buf ) == 0x8b1f ) {
104 wpw_init_mempool(MAINMEMBUF);
105 inflatebuf=wpw_malloc(MAINMEMBUF,0x13500);
106
107 /* Will use available remaining memory
108 as output buffer */
109 songbuflen=wpw_available(MAINMEMBUF);
110 songbuf=wpw_malloc(MAINMEMBUF,songbuflen);
111
112 songlen=decompress(buf,n,songbuf,songbuflen,0,inflatebuf);
113
114 if ((err = Vgm_load_mem(&vgm_emu, songbuf, songlen, true))) {
115 DEBUGF("VGM: Vgm_load_mem failed (%s)\n", err);
116 return CODEC_ERROR;
117 }
118
119 /* Since metadata parser doesn't support VGZ
120 will set song length here */
121 codec_vgz_update_length();
122 }
123 else if ((err = Vgm_load_mem(&vgm_emu, buf, n, false))) {
124 DEBUGF("VGM: Vgm_load failed_mem (%s)\n", err);
125 return CODEC_ERROR;
126 }
127
128 Vgm_start_track(&vgm_emu);
129
130 if (ci->id3->elapsed != 0)
131 Track_seek(&vgm_emu, ci->id3->elapsed);
132
133 codec_update_elapsed();
134 codec_update_fade();
135
136 /* The main decoder loop */
137 while (1) {
138 long action = ci->get_command(¶m);
139
140 if (action == CODEC_ACTION_HALT)
141 break;
142
143 if (action == CODEC_ACTION_SEEK_TIME) {
144 Track_seek(&vgm_emu, param);
145 codec_update_elapsed();
146 ci->seek_complete();
147
148 /* Set fade again in case we seek to start of song */
149 codec_update_fade();
150 }
151
152 /* Generate audio buffer */
153 err = Vgm_play(&vgm_emu, CHUNK_SIZE, samples);
154 if (err || Track_ended(&vgm_emu)) break;
155
156 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE / 2);
157 codec_update_elapsed();
158 }
159
160 return CODEC_OK;
161}