1 /*
2 WildMidi plugin for DeaDBeeF Player
3 Copyright (C) 2009-2014 Alexey Yakovenko
4
5 Based on wildmidi library
6 Midi Wavetable Processing library
7 Copyright (C)2001-2004 Chris Ison
8
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any damages
11 arising from the use of this software.
12
13 Permission is granted to anyone to use this software for any purpose,
14 including commercial applications, and to alter it and redistribute it
15 freely, subject to the following restrictions:
16
17 1. The origin of this software must not be misrepresented; you must not
18 claim that you wrote the original software. If you use this software
19 in a product, an acknowledgment in the product documentation would be
20 appreciated but is not required.
21
22 2. Altered source versions must be plainly marked as such, and must not be
23 misrepresented as being the original software.
24
25 3. This notice may not be removed or altered from any source distribution.
26 */
27
28
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include "../../deadbeef.h"
33 #include "wildmidi_lib.h"
34 #ifdef HAVE_CONFIG_H
35 #include "../../config.h"
36 #endif
37 #include "../../gettext.h"
38
39 extern DB_decoder_t wmidi_plugin;
40
41 #define trace(...) { fprintf(stderr, __VA_ARGS__); }
42 //#define trace(fmt,...)
43
44 static DB_functions_t *deadbeef;
45
46 #define min(x,y) ((x)<(y)?(x):(y))
47 #define max(x,y) ((x)>(y)?(x):(y))
48
49 typedef struct {
50 DB_fileinfo_t info;
51 midi *m;
52 } wmidi_info_t;
53
54 DB_fileinfo_t *
wmidi_open(uint32_t hints)55 wmidi_open (uint32_t hints) {
56 DB_fileinfo_t *_info = (DB_fileinfo_t *)malloc (sizeof (wmidi_info_t));
57 memset (_info, 0, sizeof (wmidi_info_t));
58 return _info;
59 }
60
61 static int
62 wmidi_init_conf (void);
63
64 int
wmidi_init(DB_fileinfo_t * _info,DB_playItem_t * it)65 wmidi_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
66 if (wmidi_init_conf () < 0) {
67 return -1;
68 }
69
70 wmidi_info_t *info = (wmidi_info_t *)_info;
71
72 deadbeef->pl_lock ();
73 info->m = WildMidi_Open (deadbeef->pl_find_meta (it, ":URI"));
74 deadbeef->pl_unlock ();
75 if (!info->m) {
76 trace ("wmidi: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
77 return -1;
78 }
79
80 _info->plugin = &wmidi_plugin;
81 _info->fmt.channels = 2;
82 _info->fmt.bps = 16;
83 _info->fmt.samplerate = 44100;
84 _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
85 _info->readpos = 0;
86
87 return 0;
88 }
89
90 void
wmidi_free(DB_fileinfo_t * _info)91 wmidi_free (DB_fileinfo_t *_info) {
92 wmidi_info_t *info = (wmidi_info_t *)_info;
93 if (info) {
94 if (info->m) {
95 WildMidi_Close (info->m);
96 info->m = NULL;
97 }
98 free (info);
99 }
100 }
101
102 int
wmidi_read(DB_fileinfo_t * _info,char * bytes,int size)103 wmidi_read (DB_fileinfo_t *_info, char *bytes, int size) {
104 wmidi_info_t *info = (wmidi_info_t *)_info;
105 int bufferused = WildMidi_GetOutput (info->m, (char *)bytes, size);
106 if (bufferused < 0) {
107 trace ("WildMidi_GetOutput returned %d\n", bufferused);
108 return 0;
109 }
110
111 return bufferused;
112 }
113
114 int
wmidi_seek_sample(DB_fileinfo_t * _info,int sample)115 wmidi_seek_sample (DB_fileinfo_t *_info, int sample) {
116 wmidi_info_t *info = (wmidi_info_t *)_info;
117 unsigned long int s = sample;
118 WildMidi_SampledSeek (info->m, &s);
119 _info->readpos = s/(float)_info->fmt.samplerate;
120 return 0;
121 }
122
123 int
wmidi_seek(DB_fileinfo_t * _info,float time)124 wmidi_seek (DB_fileinfo_t *_info, float time) {
125 return wmidi_seek_sample (_info, time * _info->fmt.samplerate);
126 }
127
128 DB_playItem_t *
wmidi_insert(ddb_playlist_t * plt,DB_playItem_t * after,const char * fname)129 wmidi_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
130 if (wmidi_init_conf () < 0) {
131 return NULL;
132 }
133
134 DB_playItem_t *it = NULL;
135
136 midi *m = WildMidi_Open (fname);
137 if (!m) {
138 trace ("wmidi: failed to open %s\n", fname);
139 return NULL;
140 }
141
142 struct _WM_Info *inf = WildMidi_GetInfo (m);
143 it = deadbeef->pl_item_alloc_init (fname, wmidi_plugin.plugin.id);
144 deadbeef->pl_add_meta (it, "title", NULL);
145 deadbeef->plt_set_item_duration (plt, it, inf->approx_total_samples / 44100.f);
146 deadbeef->pl_add_meta (it, ":FILETYPE", "MID");
147 after = deadbeef->plt_insert_item (plt, after, it);
148 deadbeef->pl_item_unref (it);
149 WildMidi_Close (m);
150 return after;
151 }
152
153 #define DEFAULT_TIMIDITY_CONFIG "/usr/local/share/freepats/freepats.cfg"
154
155 extern int WM_Initialized;
156
157 static int
wmidi_init_conf(void)158 wmidi_init_conf (void) {
159 if (WM_Initialized) {
160 return 0;
161 }
162 char config_files[1000];
163 deadbeef->conf_get_str ("wildmidi.config", DEFAULT_TIMIDITY_CONFIG, config_files, sizeof (config_files));
164 char config[1024] = "";
165 const char *p = config_files;
166 while (p) {
167 *config = 0;
168 char *e = strchr (p, ':');
169 if (e) {
170 strncpy (config, p, e-p);
171 config[e-p] = 0;
172 e++;
173 }
174 else {
175 strcpy (config, p);
176 }
177 if (*config) {
178 FILE *f = fopen (config, "rb");
179 if (f) {
180 fclose (f);
181 break;
182 }
183 *config = 0;
184 }
185 p = e;
186 }
187 if (*config) {
188 WildMidi_Init (config, 44100, 0);
189 }
190 else {
191 fprintf (stderr, _("wildmidi: freepats config file not found. Please install timidity-freepats package, or specify path to freepats.cfg in the plugin settings."));
192 return -1;
193 }
194 return 0;
195 }
196
197 int
wmidi_start(void)198 wmidi_start (void) {
199 return 0;
200 }
201
202 int
wmidi_stop(void)203 wmidi_stop (void) {
204 if (WM_Initialized) {
205 WildMidi_Shutdown ();
206 }
207 return 0;
208 }
209
210 DB_plugin_t *
wildmidi_load(DB_functions_t * api)211 wildmidi_load (DB_functions_t *api) {
212 deadbeef = api;
213 return DB_PLUGIN (&wmidi_plugin);
214 }
215
216 static const char *exts[] = { "mid",NULL };
217
218 static const char settings_dlg[] =
219 "property \"Timidity++ bank configuration file\" file wildmidi.config \"" DEFAULT_TIMIDITY_CONFIG "\";\n"
220 ;
221 // define plugin interface
222 DB_decoder_t wmidi_plugin = {
223 .plugin.api_vmajor = 1,
224 .plugin.api_vminor = 0,
225 .plugin.type = DB_PLUGIN_DECODER,
226 .plugin.version_major = 1,
227 .plugin.version_minor = 0,
228 .plugin.name = "WildMidi player",
229 .plugin.descr = "MIDI player based on WildMidi library\n\nRequires freepats package to be installed\nSee http://freepats.zenvoid.org/\nMake sure to set correct freepats.cfg path in plugin settings.",
230 .plugin.copyright =
231 "WildMidi plugin for DeaDBeeF Player\n"
232 "Copyright (C) 2009-2014 Alexey Yakovenko\n"
233 "\n"
234 "Based on wildmidi library\n"
235 "Midi Wavetable Processing library\n"
236 "Copyright (C)2001-2004 Chris Ison\n"
237 "\n"
238 "This software is provided 'as-is', without any express or implied\n"
239 "warranty. In no event will the authors be held liable for any damages\n"
240 "arising from the use of this software.\n"
241 "\n"
242 "Permission is granted to anyone to use this software for any purpose,\n"
243 "including commercial applications, and to alter it and redistribute it\n"
244 "freely, subject to the following restrictions:\n"
245 "\n"
246 "1. The origin of this software must not be misrepresented; you must not\n"
247 " claim that you wrote the original software. If you use this software\n"
248 " in a product, an acknowledgment in the product documentation would be\n"
249 " appreciated but is not required.\n"
250 "\n"
251 "2. Altered source versions must be plainly marked as such, and must not be\n"
252 " misrepresented as being the original software.\n"
253 "\n"
254 "3. This notice may not be removed or altered from any source distribution.\n"
255 ,
256 .plugin.website = "http://deadbeef.sf.net",
257 .plugin.start = wmidi_start,
258 .plugin.stop = wmidi_stop,
259 .plugin.id = "wmidi",
260 .plugin.configdialog = settings_dlg,
261 .open = wmidi_open,
262 .init = wmidi_init,
263 .free = wmidi_free,
264 .read = wmidi_read,
265 .seek = wmidi_seek,
266 .seek_sample = wmidi_seek_sample,
267 .insert = wmidi_insert,
268 .exts = exts,
269 };
270