1 /*
2 * Adapted from AlsaPlayer 0.99.76
3 *
4 * mikmod_engine.c
5 * Copyright (C) 1999 Paul N. Fisher <rao@gnu.org>
6 * Copyright (C) 2002 Andy Lo A Foe <andy@alsaplayer.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "../ip.h"
23 #include "../xmalloc.h"
24 #include <mikmod.h>
25 #include "../debug.h"
26 #include "../comment.h"
27
28 struct mik_private {
29 MODULE *file;
30 };
31
mikmod_init(void)32 static int mikmod_init(void)
33 {
34 static int inited = 0;
35
36 if (inited)
37 return 1;
38
39 MikMod_RegisterAllDrivers();
40 MikMod_RegisterAllLoaders();
41
42 md_reverb = 0;
43 /* we should let the user decide which one is better... */
44 md_mode = DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX | DMODE_STEREO |
45 DMODE_16BITS | DMODE_INTERP;
46
47 if (MikMod_Init(NULL)) {
48 d_print("Could not initialize mikmod, reason: %s\n",
49 MikMod_strerror(MikMod_errno));
50 return 0;
51 }
52
53 inited = 1;
54 return 1;
55 }
56
mik_open(struct input_plugin_data * ip_data)57 static int mik_open(struct input_plugin_data *ip_data)
58 {
59 MODULE *mf = NULL;
60 struct mik_private *priv;
61 int mi = mikmod_init();
62
63 if (!mi)
64 return -IP_ERROR_INTERNAL;
65
66 mf = Player_Load(ip_data->filename, 255, 0);
67
68 if (!mf)
69 return -IP_ERROR_ERRNO;
70
71 priv = xnew(struct mik_private, 1);
72 priv->file = mf;
73
74 ip_data->private = priv;
75 ip_data->sf = sf_bits(16) | sf_rate(44100) | sf_channels(2) | sf_signed(1);
76 ip_data->sf |= sf_host_endian();
77 channel_map_init_stereo(ip_data->channel_map);
78 return 0;
79 }
80
mik_close(struct input_plugin_data * ip_data)81 static int mik_close(struct input_plugin_data *ip_data)
82 {
83 struct mik_private *priv = ip_data->private;
84
85 Player_Stop();
86 Player_Free(priv->file);
87 free(ip_data->private);
88 ip_data->private = NULL;
89 return 0;
90 }
91
mik_read(struct input_plugin_data * ip_data,char * buffer,int count)92 static int mik_read(struct input_plugin_data *ip_data, char *buffer, int count)
93 {
94 int length;
95 struct mik_private *priv = ip_data->private;
96
97 if (!Player_Active())
98 Player_Start(priv->file);
99
100 if (!Player_Active())
101 return 0;
102
103 length = VC_WriteBytes(buffer, count);
104
105 return length;
106 }
107
mik_seek(struct input_plugin_data * ip_data,double offset)108 static int mik_seek(struct input_plugin_data *ip_data, double offset)
109 {
110 /* cannot seek in modules properly */
111 return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
112 }
113
mik_read_comments(struct input_plugin_data * ip_data,struct keyval ** comments)114 static int mik_read_comments(struct input_plugin_data *ip_data, struct keyval **comments)
115 {
116 struct mik_private *priv = ip_data->private;
117 GROWING_KEYVALS(c);
118 const char *val;
119
120 val = priv->file->songname;
121 if (val && val[0])
122 comments_add_const(&c, "title", val);
123
124 val = priv->file->comment;
125 if (val && val[0])
126 comments_add_const(&c, "comment", val);
127
128 keyvals_terminate(&c);
129 *comments = c.keyvals;
130 return 0;
131 }
132
mik_duration(struct input_plugin_data * ip_data)133 static int mik_duration(struct input_plugin_data *ip_data)
134 {
135 return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
136 }
137
mik_bitrate(struct input_plugin_data * ip_data)138 static long mik_bitrate(struct input_plugin_data *ip_data)
139 {
140 return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
141 }
142
mik_codec(struct input_plugin_data * ip_data)143 static char *mik_codec(struct input_plugin_data *ip_data)
144 {
145 struct mik_private *priv = ip_data->private;
146 const char *codec = priv->file->modtype;
147 return (codec && codec[0]) ? xstrdup(codec) : NULL;
148 }
149
mik_codec_profile(struct input_plugin_data * ip_data)150 static char *mik_codec_profile(struct input_plugin_data *ip_data)
151 {
152 return NULL;
153 }
154
155 const struct input_plugin_ops ip_ops = {
156 .open = mik_open,
157 .close = mik_close,
158 .read = mik_read,
159 .seek = mik_seek,
160 .read_comments = mik_read_comments,
161 .duration = mik_duration,
162 .bitrate = mik_bitrate,
163 .bitrate_current = mik_bitrate,
164 .codec = mik_codec,
165 .codec_profile = mik_codec_profile
166 };
167
168 const int ip_priority = 40;
169 const char * const ip_extensions[] = {
170 "mod", "s3m", "xm", "it", "669", "amf", "dsm",
171 "far", "med", "mtm", "stm", "ult",
172 NULL
173 };
174 const char * const ip_mime_types[] = { NULL };
175 const struct input_plugin_opt ip_options[] = { { NULL } };
176 const unsigned ip_abi_version = IP_ABI_VERSION;
177