Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

input_mod.cpp

Go to the documentation of this file.
00001 /*
00002 
00003   How It Works
00004 
00005   
00006   MikMod/Integration
00007   --
00008   We actually implement a MikMod output driver to render PCM
00009   data.  When AcqRead needs more PCM data, we ask MikMod to
00010   update until we have enough data.
00011 
00012 */
00013 
00014 
00015 #include <stdio.h>
00016 #include <string.h>
00017 #include "input_mod.hpp"
00018 #include "debug.hpp"
00019 #include "utility.hpp"
00020 
00021 
00022 MD_DEVICE MODInputStream::drv_acq =
00023 {
00024   "Audiere Output",
00025   "Internal Audiere Output Driver",
00026   0,
00027   VC_MAXVOICES,
00028 
00029   NULL,
00030   NULL,
00031   NULL,
00032 
00033   // Sample loading
00034   VC_SampleAlloc,
00035   VC_SampleGetPtr,
00036   VC_SampleLoad,
00037   VC_SampleUnload,
00038   VC_SampleSpace,
00039   VC_SampleLength,
00040 
00041   // Detection and initialization
00042   ACQ_IsThere,
00043   ACQ_Init,
00044   ACQ_Exit,
00045   ACQ_Update,
00046   VC_Preempt,
00047 
00048   NULL,
00049   ACQ_SetSoftVoices,
00050 
00051   ACQ_SetMode,
00052   ACQ_GetMode,
00053 
00054   VC_SetVolume,
00055   VC_GetVolume,
00056 
00057   // Voice control and voice information
00058   VC_GetActiveVoices,
00059 
00060   VC_VoiceSetVolume,
00061   VC_VoiceGetVolume,
00062   VC_VoiceSetFrequency,
00063   VC_VoiceGetFrequency,
00064   VC_VoiceSetPosition,
00065   VC_VoiceGetPosition,
00066   VC_VoiceSetSurround,
00067   VC_VoiceSetResonance,
00068 
00069   VC_VoicePlay,
00070   VC_VoiceResume,
00071   VC_VoiceStop,
00072   VC_VoiceStopped,
00073   VC_VoiceReleaseSustain,
00074 
00075   VC_VoiceRealVolume
00076 };
00077 
00078 
00080 
00081 MODInputStream::MODInputStream()
00082 {
00083   m_file = 0;
00084 
00085   m_driver = 0;
00086   m_module = 0;
00087   m_player = 0;
00088 
00089   m_samples_left = 0;
00090   m_next_sample = m_sample_buffer;
00091 
00092   m_at_eof = false;
00093 }
00094 
00096 
00097 MODInputStream::~MODInputStream()
00098 {
00099   // were we initialized successfully?
00100   if (m_file) {
00101     
00102     Player_Free(m_player);
00103     Unimod_Free(m_module);
00104     Mikmod_Exit(m_driver);
00105 
00106     delete m_file;
00107     m_file = 0;
00108   }
00109 }
00110 
00112 
00113 bool
00114 MODInputStream::Initialize(IFile* file)
00115 {
00116   m_file = file;
00117 
00118   // first time we run, initialize MikMod
00119   static bool initialized = false;
00120   if (!initialized) {
00121     ADR_GUARD("Initializing MikMod");
00122 
00123     Mikmod_RegisterLoader(load_it);
00124     Mikmod_RegisterLoader(load_xm);
00125     Mikmod_RegisterLoader(load_s3m);
00126     Mikmod_RegisterLoader(load_mod);
00127     Mikmod_RegisterLoader(load_stm);
00128     
00129     Mikmod_RegisterDriver(drv_acq);
00130 
00131     initialized = true;
00132   }
00133 
00134   m_stream.fp      = (FILE*)this;
00135   m_stream.dp      = 0;
00136   m_stream.iobase  = 0;
00137   m_stream.seekpos = 0;
00138   m_stream.fread   = MMRead;
00139   m_stream.fwrite  = MMWrite;
00140   m_stream.fgetc   = MMGetC;
00141   m_stream.fputc   = MMPutC;
00142   m_stream.fseek   = MMSeek;
00143   m_stream.ftell   = MMTell;
00144   m_stream.feof    = MMEof;
00145 
00146   m_samples_left = 0;
00147   m_next_sample  = m_next_sample;
00148 
00149   m_at_eof = false;
00150 
00151   // create output device
00152   m_driver = Mikmod_Init(
00153     44100, 2400, this, MD_STEREO, CPU_AUTODETECT,
00154     DMODE_16BITS | DMODE_INTERP | DMODE_NOCLICK);
00155   if (!m_driver) {
00156     m_file = 0;
00157     return false;
00158   }
00159 
00160   ADR_LOG("Mikmod_Init succeeded");
00161 
00162   // load the song
00163   m_module = Unimod_LoadFP(
00164     m_driver,
00165     &m_stream,
00166     &m_stream,
00167     MM_STATIC);
00168   if (!m_module) {
00169     Mikmod_Exit(m_driver);
00170     m_driver = 0;
00171     m_file = 0;
00172     return false;
00173   }
00174 
00175   ADR_LOG("Unimod_LoadFP succeeded");
00176 
00177   // load the samples (???)
00178   if (SL_LoadSamples(m_driver)) {
00179     Unimod_Free(m_module);
00180     m_module = 0;
00181     Mikmod_Exit(m_driver);
00182     m_driver = 0;
00183     m_file = 0;
00184     return false;
00185   }
00186 
00187   ADR_LOG("SL_LoadSamples succeeded");
00188 
00189   // create a player
00190   m_player = Player_InitSong(m_module, NULL, 0, 64);
00191   if (!m_player) {
00192     Unimod_Free(m_module);
00193     m_module = 0;
00194     Mikmod_Exit(m_driver);
00195     m_driver = 0;
00196     m_file = 0;
00197     return false;
00198   }
00199 
00200   ADR_LOG("Player_InitSong succeeded");
00201 
00202   // start playback of the module
00203   // we won't actually get samples until the read call
00204   Player_Start(m_player);
00205 
00206   ADR_LOG("Player_Start succeeded");
00207 
00208   return true;
00209 }
00210 
00212 
00213 void
00214 MODInputStream::GetFormat(
00215   int& channel_count,
00216   int& sample_rate,
00217   int& bits_per_sample)
00218 {
00219   channel_count   = 2;
00220   sample_rate     = 44100;
00221   bits_per_sample = 16;
00222 }
00223 
00225 
00226 int
00227 MODInputStream::Read(int sample_count, void* samples)
00228 {
00229   ADR_GUARD("MOD_Read");
00230 
00231   adr_u32* out = reinterpret_cast<adr_u32*>(samples);
00232 
00233   int total_written = 0;
00234   while (sample_count > 0) {
00235 
00236     // if there are no samples in the buffer, tell mikmod to give us a few
00237     if (m_samples_left == 0) {
00238 
00239       // if the song isn't playing any more, just stop
00240       if (!Player_Active(m_player)) {
00241         break;
00242       }
00243 
00244       Mikmod_Update(m_driver);
00245     }
00246 
00247     // read data out of the buffer
00248     adr_u32 samples_to_read = adr_min<adr_u32>(
00249       sample_count,
00250       m_samples_left);
00251     memcpy(out, m_next_sample, samples_to_read * 4);
00252 
00253     // update pointers and indices and counts, oh my
00254     out            += samples_to_read;    
00255     m_next_sample  += samples_to_read;
00256     m_samples_left -= samples_to_read;
00257     sample_count   -= samples_to_read;
00258     total_written  += samples_to_read;
00259   }
00260 
00261   return total_written;
00262 }
00263 
00265 
00266 bool
00267 MODInputStream::Reset()
00268 {
00269   ADR_GUARD("MOD_Reset");
00270 
00271   m_samples_left = 0;
00272   m_next_sample  = m_sample_buffer;
00273 
00274   Player_Stop(m_player);
00275   Player_Start(m_player);
00276   return true;
00277 }
00278 
00280 
00281 BOOL
00282 MODInputStream::ACQ_IsThere()
00283 {
00284   return 1;
00285 }
00286 
00288 
00289 BOOL
00290 MODInputStream::ACQ_Init(MDRIVER* md, uint latency, void* optstr)
00291 {
00292   ADR_GUARD("ACQ_Init");
00293 
00294   md->device.vc = VC_Init();
00295   if (!md->device.vc) {
00296     return 1;
00297   }
00298 
00299   md->device.local = optstr;
00300   return 0;
00301 }
00302 
00304 
00305 void
00306 MODInputStream::ACQ_Exit(MDRIVER* md)
00307 {
00308   ADR_GUARD("ACQ_Exit");
00309 
00310   VC_Exit(md->device.vc);
00311 }
00312 
00314 
00315 void
00316 MODInputStream::ACQ_Update(MDRIVER* md)
00317 {
00318   ADR_GUARD("ACQ_Update");
00319 
00320   MODInputStream* stream = reinterpret_cast<MODInputStream*>(md->device.local);
00321 
00322   // we should only write into the buffer if it's empty
00323   if (stream->m_samples_left != 0) {
00324     return;
00325   }
00326 
00327   VC_WriteBytes(
00328     md,
00329     (signed char*)stream->m_sample_buffer,
00330     SAMPLE_BUFFER_SIZE * sizeof(adr_u32));
00331   stream->m_samples_left = SAMPLE_BUFFER_SIZE;
00332   stream->m_next_sample = stream->m_sample_buffer;
00333 }
00334 
00336 
00337 BOOL
00338 MODInputStream::ACQ_SetSoftVoices(MDRIVER* md, uint voices)
00339 {
00340   return VC_SetSoftVoices(md->device.vc, voices);
00341 }
00342 
00344 
00345 BOOL
00346 MODInputStream::ACQ_SetMode(MDRIVER* md, uint mixspeed, uint mode,
00347                  uint channels, uint cpumode)
00348 {
00349   return VC_SetMode(md->device.vc, mixspeed, mode, channels, cpumode);
00350 }
00351 
00353 
00354 void
00355 MODInputStream::ACQ_GetMode(MDRIVER* md, uint* mixspeed, uint* mode,
00356                  uint* channels, uint* cpumode)
00357 {
00358   VC_GetMode(md->device.vc, mixspeed, mode, channels, cpumode);
00359 }
00360 
00362 
00363 int CRT_CALL
00364 MODInputStream::MMRead(void* buffer, size_t size, size_t count, FILE* stream)
00365 {
00366   MODInputStream* istream = reinterpret_cast<MODInputStream*>(stream);
00367   int result = istream->m_file->Read(buffer, size * count) / size;
00368   if (result == 0) {
00369     istream->m_at_eof = true;
00370   }
00371   return result;
00372 }
00373 
00375 
00376 int CRT_CALL
00377 MODInputStream::MMWrite(const void* buffer, size_t size, size_t count, FILE* stream)
00378 {
00379   // we can't write
00380   return -1;
00381 }
00382 
00384 
00385 int CRT_CALL
00386 MODInputStream::MMGetC(FILE* stream)
00387 {
00388   unsigned char c;
00389   if (MMRead(&c, 1, 1, stream) == 1) {
00390     return c;
00391   } else {
00392    return EOF;
00393   }
00394 }
00395 
00397 
00398 int CRT_CALL
00399 MODInputStream::MMPutC(int c, FILE* stream)
00400 {
00401   char ch = (char)c;
00402   return MMWrite(&ch, 1, 1, stream);
00403 }
00404 
00406 
00407 int CRT_CALL
00408 MODInputStream::MMSeek(FILE* stream, long offset, int origin)
00409 {
00410   MODInputStream* istream = reinterpret_cast<MODInputStream*>(stream);
00411   IFile* file = istream->m_file;
00412 
00413   ADR_SEEK_TYPE seek_type;
00414   switch (origin) {
00415     case SEEK_SET: seek_type = ADR_BEGIN;   break;
00416     case SEEK_CUR: seek_type = ADR_CURRENT; break;
00417     case SEEK_END: seek_type = ADR_END;     break;
00418     default: return -1;
00419   }
00420 
00421   return file->Seek(offset, seek_type) ? 0 : -1;
00422 }
00423 
00425 
00426 int CRT_CALL
00427 MODInputStream::MMTell(FILE* stream)
00428 {
00429   MODInputStream* istream = reinterpret_cast<MODInputStream*>(stream);
00430   IFile* file = istream->m_file;
00431   return file->Tell();
00432 }
00433 
00435 
00436 int CRT_CALL
00437 MODInputStream::MMEof(FILE* stream)
00438 {
00439   MODInputStream* istream = reinterpret_cast<MODInputStream*>(stream);
00440   return istream->m_at_eof ? 1 : 0;
00441 }
00442 

Generated at Mon Jun 10 02:55:12 2002 for audiere by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001