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