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