1 /*
2  * tracker music (module file) decoding support using libmikmod
3  * Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  *
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "quakedef.h"
22 
23 #if defined(USE_CODEC_MIKMOD)
24 #include "snd_codec.h"
25 #include "snd_codeci.h"
26 #include "snd_mikmod.h"
27 #include <mikmod.h>
28 
29 #if ((LIBMIKMOD_VERSION+0) < 0x030105)
30 #error libmikmod version is way too old and unusable.
31 #endif
32 #if (LIBMIKMOD_VERSION < 0x030107) /* ancient libmikmod */
33 #define S_MIKMOD_initlib(c) MikMod_Init()
34 #else
35 #define S_MIKMOD_initlib(c) MikMod_Init(c)
36 #endif
37 
38 #ifndef DMODE_NOISEREDUCTION
39 #define DMODE_NOISEREDUCTION 0x1000 /* Low pass filtering */
40 #endif
41 #ifndef DMODE_SIMDMIXER
42 #define DMODE_SIMDMIXER 0x0800 /* enable SIMD mixing */
43 #endif
44 
45 typedef struct _mik_priv {
46 	/* MREADER core members in libmikmod2/3: */
47 	int  (*Seek)(struct MREADER*, long, int);
48 	long (*Tell)(struct MREADER*);
49 	BOOL (*Read)(struct MREADER*, void*, size_t);
50 	int  (*Get)(struct MREADER*);
51 	BOOL (*Eof)(struct MREADER*);
52 	/* no iobase members in libmikmod <= 3.2.0-beta2 */
53 	long iobase, prev_iobase;
54 
55 	fshandle_t *fh;
56 	MODULE *module;
57 } mik_priv_t;
58 
MIK_Seek(MREADER * r,long ofs,int whence)59 static int MIK_Seek (MREADER *r, long ofs, int whence)
60 {
61 	return FS_fseek(((mik_priv_t *)r)->fh, ofs, whence);
62 }
63 
MIK_Tell(MREADER * r)64 static long MIK_Tell (MREADER *r)
65 {
66 	return FS_ftell(((mik_priv_t *)r)->fh);
67 }
68 
MIK_Read(MREADER * r,void * ptr,size_t siz)69 static BOOL MIK_Read (MREADER *r, void *ptr, size_t siz)
70 {
71 	return !!FS_fread(ptr, siz, 1, ((mik_priv_t *)r)->fh);
72 }
73 
MIK_Get(MREADER * r)74 static int MIK_Get (MREADER *r)
75 {
76 	return FS_fgetc(((mik_priv_t *)r)->fh);
77 }
78 
MIK_Eof(MREADER * r)79 static BOOL MIK_Eof (MREADER *r)
80 {
81 	return FS_feof(((mik_priv_t *)r)->fh);
82 }
83 
S_MIKMOD_CodecInitialize(void)84 static qboolean S_MIKMOD_CodecInitialize (void)
85 {
86 	if (mikmod_codec.initialized)
87 		return true;
88 
89 	/* set mode flags to only we like: */
90 	md_mode = 0;
91 	if ((shm->samplebits / 8) == 2)
92 		md_mode |= DMODE_16BITS;
93 	if (shm->channels == 2)
94 		md_mode |= DMODE_STEREO;
95 	md_mode |= DMODE_SOFT_MUSIC;	/* this is a software-only mixer */
96 
97 	/* md_mixfreq is UWORD, so something like 96000 isn't OK */
98 	md_mixfreq = (shm->speed < 65536)? shm->speed : 48000;
99 
100 	/* keeping md_device as 0 which is default (auto-detect: we
101 	 * only register drv_nos, and it will be the only one found.)
102 	 * md_pansep (stereo channels separation) default 128 is OK.
103 	 * no reverbation (md_reverb 0 (up to 15)) is OK.
104 	 * md_musicvolume and md_sndfxvolume defaults are 128: OK. */
105 	/* just tone down overall volume md_volume from 128 to 96? */
106 	md_volume = 96;
107 
108 	MikMod_RegisterDriver(&drv_nos);	/* only need the "nosound" driver, none else */
109 	MikMod_RegisterAllLoaders();
110 	if (S_MIKMOD_initlib(NULL))
111 	{
112 		Con_DPrintf("Could not initialize MikMod: %s\n", MikMod_strerror(MikMod_errno));
113 		return false;
114 	}
115 
116 	/* this can't get set with drv_nos, but whatever, be safe: */
117 	md_mode &= ~DMODE_SIMDMIXER;	/* SIMD mixer is buggy when combined with HQMIXER */
118 
119 	mikmod_codec.initialized = true;
120 	return true;
121 }
122 
S_MIKMOD_CodecShutdown(void)123 static void S_MIKMOD_CodecShutdown (void)
124 {
125 	if (mikmod_codec.initialized)
126 	{
127 		mikmod_codec.initialized = false;
128 		MikMod_Exit();
129 	}
130 }
131 
S_MIKMOD_CodecOpenStream(snd_stream_t * stream)132 static qboolean S_MIKMOD_CodecOpenStream (snd_stream_t *stream)
133 {
134 	mik_priv_t *priv;
135 
136 	stream->priv = Z_Malloc(sizeof(mik_priv_t));
137 	priv = (mik_priv_t *) stream->priv;
138 	priv->Seek = MIK_Seek;
139 	priv->Tell = MIK_Tell;
140 	priv->Read = MIK_Read;
141 	priv->Get  = MIK_Get;
142 	priv->Eof  = MIK_Eof;
143 	priv->fh = &stream->fh;
144 
145 	priv->module = Player_LoadGeneric((MREADER *)stream->priv, 64, 0);
146 	if (!priv->module)
147 	{
148 		Con_DPrintf("Could not load module: %s\n", MikMod_strerror(MikMod_errno));
149 		Z_Free(stream->priv);
150 		return false;
151 	}
152 
153 	/* default values of module options set by Player_Init():
154 	 * fadeout (0): don't fade out volume during when last position of the
155 	 *              module is being played,
156 	 * extspd  (1): process Protracker extended speed effect,
157 	 * panflag (1): process panning effects,
158 	 * wrap    (0): don't wrap to restart position when module is finished,
159 	 * loop    (1): process all in-module loops -- possible backward loops
160 	 *              would make the module to loop endlessly.
161 	 */
162 	priv->module->wrap = stream->loop;
163 	Player_Start(priv->module);
164 
165 	stream->info.rate	= md_mixfreq;
166 	stream->info.bits	= (md_mode & DMODE_16BITS)? 16: 8;
167 	stream->info.width	= stream->info.bits / 8;
168 	stream->info.channels	= (md_mode & DMODE_STEREO)? 2 : 1;
169 /*	Con_DPrintf("Playing %s (%d chn)\n", priv->module->songname, priv->module->numchn);*/
170 
171 	return true;
172 }
173 
S_MIKMOD_CodecReadStream(snd_stream_t * stream,int bytes,void * buffer)174 static int S_MIKMOD_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer)
175 {
176 	if (!Player_Active())
177 		return 0;
178 
179 	/* handle possible loop setting change: */
180 	((mik_priv_t *)stream->priv)->module->wrap = stream->loop;
181 
182 	return (int) VC_WriteBytes((SBYTE *)buffer, bytes);
183 }
184 
S_MIKMOD_CodecCloseStream(snd_stream_t * stream)185 static void S_MIKMOD_CodecCloseStream (snd_stream_t *stream)
186 {
187 	Player_Stop();
188 	Player_Free(((mik_priv_t *)stream->priv)->module);
189 	Z_Free(stream->priv);
190 	S_CodecUtilClose(&stream);
191 }
192 
S_MIKMOD_CodecJumpToOrder(snd_stream_t * stream,int to)193 static int S_MIKMOD_CodecJumpToOrder (snd_stream_t *stream, int to)
194 {
195 	Player_SetPosition ((UWORD)to);
196 	return 0;
197 }
198 
S_MIKMOD_CodecRewindStream(snd_stream_t * stream)199 static int S_MIKMOD_CodecRewindStream (snd_stream_t *stream)
200 {
201 	Player_SetPosition (0); /* FIXME: WRONG: THIS IS NOT A TIME SEEK */
202 	return 0;
203 }
204 
205 snd_codec_t mikmod_codec =
206 {
207 	CODECTYPE_MOD,
208 	false,
209 	"s3m",
210 	S_MIKMOD_CodecInitialize,
211 	S_MIKMOD_CodecShutdown,
212 	S_MIKMOD_CodecOpenStream,
213 	S_MIKMOD_CodecReadStream,
214 	S_MIKMOD_CodecRewindStream,
215 	S_MIKMOD_CodecJumpToOrder,
216 	S_MIKMOD_CodecCloseStream,
217 	NULL
218 };
219 
220 #endif	/* USE_CODEC_MIKMOD */
221 
222