1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name mikmod.cpp - MikMod support */
12 //
13 // (c) Copyright 2004-2005 by Nehal Mistry
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 //@{
31
32 /*----------------------------------------------------------------------------
33 -- Includes
34 ----------------------------------------------------------------------------*/
35
36 #include "stratagus.h"
37
38 #ifdef USE_MIKMOD // {
39
40 #include "sound.h"
41 #include "sound_server.h"
42 #include "iolib.h"
43
44 #include <mikmod.h>
45
46 /*----------------------------------------------------------------------------
47 -- Declarations
48 ----------------------------------------------------------------------------*/
49
50 struct MikModData {
51 MODULE *MikModModule;
52 CFile *MikModFile;
53 };
54
55 static CFile *CurrentFile;
56
57 class CSampleMikMod : public CSample
58 {
59 public:
60 ~CSampleMikMod();
61 int Read(void *buf, int len);
62
63 MikModData Data;
64 };
65
66 class CSampleMikModStream : public CSample
67 {
68 public:
69 ~CSampleMikModStream();
70 int Read(void *buf, int len);
71
72 MikModData Data;
73 };
74
75 /*----------------------------------------------------------------------------
76 -- Functions
77 ----------------------------------------------------------------------------*/
78
Seek(struct MREADER *,long off,int whence)79 static BOOL Seek(struct MREADER *, long off, int whence)
80 {
81 return CurrentFile->seek(off, whence);
82 }
83
Tell(struct MREADER *)84 static long Tell(struct MREADER *)
85 {
86 return CurrentFile->tell();
87 }
88
Read(struct MREADER *,void * buf,size_t len)89 static BOOL Read(struct MREADER *, void *buf, size_t len)
90 {
91 return CurrentFile->read(buf, len);
92 }
93
Get(struct MREADER *)94 static int Get(struct MREADER *)
95 {
96 char c;
97 CurrentFile->read(&c, 1);
98 return c;
99 }
100
Eof(struct MREADER *)101 static BOOL Eof(struct MREADER *)
102 {
103 return 0;
104 }
105
106 static MREADER MReader = { Seek, Tell, Read, Get, Eof };
107
108 /**
109 ** Type member function to read from the module
110 **
111 ** @param buf Buffer to write data to
112 ** @param len Length of the buffer
113 **
114 ** @return Number of bytes read
115 */
Read(void * buf,int len)116 int CSampleMikModStream::Read(void *buf, int len)
117 {
118 int read;
119
120 // fill up the buffer
121 read = 0;
122 while (this->Len < SOUND_BUFFER_SIZE / 2 && Player_Active()) {
123 memcpy(this->Buffer, this->Buffer + this->Pos, this->Len);
124 this->Pos = 0;
125 CurrentFile = this->Data.MikModFile;
126 read = VC_WriteBytes((SBYTE *)this->Buffer + this->Pos,
127 SOUND_BUFFER_SIZE - (this->Pos + this->Len));
128 this->Len += read;
129 }
130
131 if (this->Len < len) {
132 // EOF
133 len = this->Len;
134 }
135
136 memcpy(buf, this->Buffer + this->Pos, len);
137 this->Len -= len;
138 this->Pos += len;
139
140 return len;
141 }
142
143 /**
144 ** Type member function to free sample
145 */
~CSampleMikModStream()146 CSampleMikModStream::~CSampleMikModStream()
147 {
148 CurrentFile = this->Data.MikModFile;
149
150 Player_Stop();
151 Player_Free(this->Data.MikModModule);
152 MikMod_Exit();
153 this->Data.MikModFile->close();
154 delete this->Data.MikModFile;
155 delete[] this->Buffer;
156 }
157
158 /**
159 ** Type member function to read from the module
160 **
161 ** @param buf Buffer to write data to
162 ** @param len Length of the buffer
163 **
164 ** @return Number of bytes read
165 */
Read(void * buf,int len)166 int CSampleMikMod::Read(void *buf, int len)
167 {
168 if (this->Len < len) {
169 len = this->Len;
170 }
171
172 memcpy(buf, this->Buffer + this->Pos, len);
173 this->Pos += len;
174 this->Len -= len;
175
176 return len;
177 }
178
179 /**
180 ** Type member function to free sample
181 */
~CSampleMikMod()182 CSampleMikMod::~CSampleMikMod()
183 {
184 delete[] this->Buffer;
185 }
186
187
188 /**
189 ** Load MikMod.
190 **
191 ** @param name Filename of the module.
192 ** @param flags Unused.
193 **
194 ** @return Returns the loaded sample.
195 */
LoadMikMod(const char * name,int flags)196 CSample *LoadMikMod(const char *name, int flags)
197 {
198 CSample *sample;
199 MikModData *data;
200 MODULE *module;
201 CFile *f;
202 char s[256];
203 static int registered = 0;
204
205 md_mode |= DMODE_STEREO | DMODE_INTERP | DMODE_SURROUND | DMODE_HQMIXER;
206 MikMod_RegisterDriver(&drv_nos);
207 if (!registered) {
208 MikMod_RegisterAllLoaders();
209 registered = 1;
210 }
211
212 strcpy_s(s, sizeof(s), name);
213 f = new CFile;
214 if (f->open(name, CL_OPEN_READ) == -1) {
215 delete f;
216 return nullptr;
217 }
218 CurrentFile = f;
219
220 MikMod_Init((char *)"");
221 module = Player_LoadGeneric(&MReader, 64, 0);
222 if (!module) {
223 MikMod_Exit();
224 f->close();
225 delete f;
226 return nullptr;
227 }
228
229 if (flags & PlayAudioStream) {
230 CSampleMikModStream *sampleMikModStream = new CSampleMikModStream;
231 sample = sampleMikModStream;
232 data = &sampleMikModStream->Data;
233 } else {
234 CSampleMikMod *sampleMikMod = new CSampleMikMod;
235 sample = sampleMikMod;
236 data = &sampleMikMod->Data;
237 }
238 data->MikModFile = f;
239 data->MikModModule = module;
240 sample->Channels = 2;
241 sample->SampleSize = 16;
242 sample->Frequency = 44100;
243 sample->Pos = 0;
244 //Wyrmgus start
245 sample->File = name;
246 //Wyrmgus end
247
248 if (flags & PlayAudioStream) {
249 sample->Len = 0;
250 sample->Buffer = new unsigned char[SOUND_BUFFER_SIZE];
251
252 Player_Start(data->MikModModule);
253 } else {
254 int read;
255 int pos;
256
257 // FIXME: need to find the correct length
258 sample->Len = 55000000;
259 sample->Buffer = new unsigned char[sample->Len];
260
261 pos = 0;
262 Player_Start(data->MikModModule);
263 while (Player_Active()) {
264 read = VC_WriteBytes((SBYTE *)sample->Buffer + pos, sample->Len - pos);
265 pos += read;
266 }
267
268 Player_Stop();
269 Player_Free(data->MikModModule);
270 MikMod_Exit();
271
272 data->MikModFile->close();
273 delete data->MikModFile;
274 }
275
276 return sample;
277 }
278
279 #endif // } USE_MIKMOD
280
281 //@}
282