forked from TricksterGuy/audacious-plugin-highly-advanced
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathplugin.cpp
More file actions
367 lines (301 loc) · 10.1 KB
/
Copy pathplugin.cpp
File metadata and controls
367 lines (301 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
// TODO: make plugin.h
// clangd ide extension can't find this even though the build is fine
#include "builddir/config.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#ifdef DEBUG
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#endif
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
#include <libaudcore/preferences.h>
#include <libaudcore/runtime.h>
#include <libaudcore/tuple.h>
#include <libaudcore/audstrings.h>
#include "VBA/psftag.h"
#include "VBA/Util.h"
#include "gsf.h"
struct GSFPreferences
{
bool loop_forever;
bool ignore_track_length;
int track_length;
bool detect_silence;
int silence_length;
bool enable_low_pass_filter;
} preferences;
#ifdef DEBUG
// TODO: ...params like printf
void debugMessage(const char *str)
{
timeval curTime;
gettimeofday(&curTime, NULL);
int milli = curTime.tv_usec / 1000;
char buffer [80];
strftime(buffer, 80, "%H:%M:%S", localtime(&curTime.tv_sec));
char currentTime[84] = "";
sprintf(currentTime, "%s:%d", buffer, milli);
printf("[%s] Debug: %s\n", currentTime, str);
}
void debugMessageInt(const int d)
{
char message[256] = {0};
snprintf(message, 256, "%d", d);
debugMessage(message);
}
#else
void debugMessage(const char *) {}
void debugMessageInt(const int) {}
#endif
// TODO: round up all the static state
extern "C" {
int defvolume = 1000;
int relvolume = 1000;
int TrackLength = 0;
int FadeLength = 0;
int IgnoreTrackLength, DefaultLength = 150000;
int playforever = 0;
int TrailingSilence = 1000;
int DetectSilence = 0, silencedetected = 0, silencelength = 5;
}
int cpupercent = 0, sndSamplesPerSec, sndNumChannels;
int sndBitsPerSample = 16;
int deflen = 120, deffade = 4;
extern unsigned short soundFinalWave[1470];
extern int soundBufferLen;
extern char soundEcho;
extern char soundLowPass;
extern char soundReverse;
extern char soundQuality;
double decode_pos_ms; // current decoding position, in milliseconds
int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
#define CFG_ID "highlyadvanced" //ID for storing in audacious
void update_gsf_settings()
{
playforever = preferences.loop_forever;
IgnoreTrackLength = preferences.ignore_track_length;
DefaultLength = preferences.track_length * 1000;
DetectSilence = preferences.detect_silence;
silencelength = preferences.silence_length;
soundLowPass = preferences.enable_low_pass_filter;
}
extern "C" void end_of_track()
{
// TODO: hook this up
}
//////////////////////////////////////////////////////////////
//////////////// T H E G O O D P A R T S ////////////////
//////////////////////////////////////////////////////////////
class HighlyAdvancedPlugin : public InputPlugin
{
public:
static const char about[];
static const char * const exts[];
// static const char * const defaults[];
static const PreferencesWidget widgets[];
static const PluginPreferences prefs;
static constexpr PluginInfo info = {
N_("Highly Advanced"),
"gsf",
about,
& prefs,
0
};
constexpr HighlyAdvancedPlugin() : InputPlugin(info, InputInfo()
.with_exts(exts)) {}
bool init() override;
void cleanup() override;
bool is_our_file(const char * uri, VFSFile & file) override;
bool read_tag(const char * uri, VFSFile & file, Tuple & tuple,
Index<char> * image) override;
bool play(const char * uri, VFSFile & file) override;
// Our members
void on_gsf_write_audio(const void * data, int length);
// protected:
// void cfg_load();
// void cfg_save();
};
EXPORT HighlyAdvancedPlugin aud_plugin_instance;
const char HighlyAdvancedPlugin::about[] =
"audacious-highly-advanced version: " VERSION "\n\n"
"ported to audacious 3.5.1 by Brandon Whitehead\n"
"ported to audacious 4.5.1 by hypevhs\n";
const char * const HighlyAdvancedPlugin::exts[] = {
"gsf",
"minigsf",
nullptr
};
const char * const gsf_cfg_defaults[] = {
"enable_low_pass_filter", "1",
"detect_silence", "1",
"silence_length", "5",
"ignore_track_length", "0",
"track_length", "150", // in seconds
"loop_forever", "1",
nullptr
};
const PreferencesWidget HighlyAdvancedPlugin::widgets[] = {
WidgetLabel(N_("<b>HighlyAdvanced Config</b>")),
WidgetCheck(N_("Loop Forever:"),
WidgetBool(preferences.loop_forever)),
WidgetCheck(N_("Ignore Track Length:"),
WidgetBool(preferences.ignore_track_length)),
WidgetSpin(N_("Track Length:"),
WidgetInt(preferences.track_length),
{1, 2147483647, 1, N_("seconds")}),
WidgetCheck(N_("Detect Silence:"),
WidgetBool(preferences.detect_silence)),
WidgetSpin(N_("Silence Length:"),
WidgetInt(preferences.silence_length),
{1, 2147483647, 1, N_("seconds")}),
WidgetCheck(N_("Enable Low Pass Filter:"),
WidgetBool(preferences.enable_low_pass_filter)),
};
static void cfg_load()
{
debugMessage("cfg_load called");
aud_config_set_defaults(CFG_ID, gsf_cfg_defaults);
preferences.loop_forever = aud_get_bool(CFG_ID, "loop_forever");
preferences.ignore_track_length = aud_get_int(CFG_ID, "ignore_track_length");
preferences.track_length = aud_get_int(CFG_ID, "track_length") * 1000;
preferences.detect_silence = aud_get_bool(CFG_ID, "detect_silence");
preferences.silence_length = aud_get_int(CFG_ID, "silence_length");
preferences.enable_low_pass_filter = aud_get_bool(CFG_ID, "enable_low_pass_filter");
update_gsf_settings();
}
static void cfg_save()
{
debugMessage("cfg_save called");
aud_set_bool(CFG_ID, "loop_forever", preferences.loop_forever);
aud_set_int(CFG_ID, "ignore_track_length", preferences.ignore_track_length);
aud_set_int(CFG_ID, "track_length", preferences.track_length);
aud_set_bool(CFG_ID, "detect_silence", preferences.detect_silence);
aud_set_int(CFG_ID, "silence_length", preferences.silence_length);
aud_set_bool(CFG_ID, "enable_low_pass_filter", preferences.enable_low_pass_filter);
}
const PluginPreferences HighlyAdvancedPlugin::prefs = {
{widgets},
cfg_load,
cfg_save,
nullptr
};
bool HighlyAdvancedPlugin::init()
{
debugMessage("HighlyAdvancedPlugin::init()");
cfg_load();
debugMessage("after load cfg");
return true;
}
void HighlyAdvancedPlugin::cleanup()
{
debugMessage("HighlyAdvancedPlugin::cleanup()");
cfg_save();
}
bool HighlyAdvancedPlugin::is_our_file(const char * uri, VFSFile & /*file*/)
{
debugMessage("HighlyAdvancedPlugin::is_our_file()");
StringBuf filename = uri_to_filename(uri, false);
debugMessage("local filename:");
debugMessage(filename);
IMAGE_TYPE type = utilFindType(filename);
switch (type) {
case IMAGE_GBA:
return true;
case IMAGE_GB:
debugMessage("Can't play Gameboy images");
return false;
case IMAGE_UNKNOWN:
default:
debugMessage("Unknown image type");
return false;
}
}
bool HighlyAdvancedPlugin::read_tag(const char * uri, VFSFile & /*file*/, Tuple & tuple,
Index<char> * /*image*/)
{
debugMessage("HighlyAdvancedPlugin::read_tag()");
StringBuf filename = uri_to_filename(uri, false);
debugMessage("local filename:");
debugMessage(filename);
PSFTAG *tag = psftag_create();
char tmp_str[TAGMAX];
int ret = psftag_readfromfile(tag, filename);
if (ret != 0) {
debugMessage("psftag_readfromfile: Couldn't read tags");
const char *error = psftag_getlasterror(tag);
debugMessage("Reason given:");
debugMessage(error);
psftag_delete(tag);
return false;
}
if (!psftag_getvar(tag, "title", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Title, tmp_str);
if (!psftag_getvar(tag, "artist", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Artist, tmp_str);
if (!psftag_getvar(tag, "game", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Album, tmp_str);
if (!psftag_getvar(tag, "year", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Date, tmp_str);
if (!psftag_getvar(tag, "copyright", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Copyright, tmp_str);
if (!psftag_getvar(tag, "tagger", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Invalid, tmp_str);
if (!psftag_getvar(tag, "length", tmp_str, sizeof(tmp_str) - 1))
{
int length_ms = LengthFromString(tmp_str) + FadeLength;
tuple.set_int(Tuple::Length, length_ms);
}
if (!psftag_getvar(tag, "comment", tmp_str, sizeof(tmp_str) - 1))
tuple.set_str(Tuple::Comment, tmp_str);
tuple.set_str(Tuple::Codec, "GameBoy Advanced Audio (GSF)");
tuple.set_str(Tuple::Quality, "sequenced");
psftag_delete(tag);
return true;
}
bool HighlyAdvancedPlugin::play(const char * uri, VFSFile & /*file*/)
{
debugMessage("HighlyAdvancedPlugin::play()");
decode_pos_ms = 0;
seek_needed = -1;
TrailingSilence = 1000;
StringBuf filename = uri_to_filename(uri, false);
debugMessage("local filename:");
debugMessage(filename);
int r = GSFRun(filename);
if (!r) return false;
set_stream_bitrate(sndSamplesPerSec * 2 * sndNumChannels);
open_audio(FMT_S16_LE, sndSamplesPerSec, sndNumChannels);
while (!check_stop())
{
int seek_value = check_seek();
if (seek_value > 0)
{
if (seek_value < decode_pos_ms)
{
GSFClose();
r = GSFRun(filename);
if (!r) return false;
}
seek_needed = seek_value;
}
EmulationLoop();
}
GSFClose();
return true;
}
void HighlyAdvancedPlugin::on_gsf_write_audio(const void * data, int length)
{
write_audio(data, length);
}
/// The static functions that gsf calls directly
extern "C" void writeSound(void)
{
int ret = soundBufferLen;
aud_plugin_instance.on_gsf_write_audio(soundFinalWave, ret);
decode_pos_ms += (1000.0f * ret / (2 * sndNumChannels)) / sndSamplesPerSec;
}