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