mloader.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:12k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
  3. AUTHORS for complete list.
  4. This library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. 02111-1307, USA.
  18. */
  19. /*==============================================================================
  20.   $Id: mloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
  21.   These routines are used to access the available module loaders
  22. ==============================================================================*/
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #ifdef HAVE_UNISTD_H
  27. #include <unistd.h>
  28. #endif
  29. #ifdef HAVE_MEMORY_H
  30. #include <memory.h>
  31. #endif
  32. #include <string.h>
  33. #include "mikmod_internals.h"
  34. #ifdef SUNOS
  35. extern int fprintf(FILE *, const char *, ...);
  36. #endif
  37. MREADER *modreader;
  38. MODULE of;
  39. static MLOADER *firstloader=NULL;
  40. UWORD finetune[16]={
  41. 8363,8413,8463,8529,8581,8651,8723,8757,
  42. 7895,7941,7985,8046,8107,8169,8232,8280
  43. };
  44. MIKMODAPI CHAR* MikMod_InfoLoader(void)
  45. {
  46. int len=0;
  47. MLOADER *l;
  48. CHAR *list=NULL;
  49. MUTEX_LOCK(lists);
  50. /* compute size of buffer */
  51. for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version);
  52. if(len)
  53. if((list=_mm_malloc(len*sizeof(CHAR)))) {
  54. list[0]=0;
  55. /* list all registered module loders */
  56. for(l=firstloader;l;l=l->next)
  57. sprintf(list,(l->next)?"%s%sn":"%s%s",list,l->version);
  58. }
  59. MUTEX_UNLOCK(lists);
  60. return list;
  61. }
  62. void _mm_registerloader(MLOADER* ldr)
  63. {
  64. MLOADER *cruise=firstloader;
  65. if(cruise) {
  66. while(cruise->next) cruise = cruise->next;
  67. cruise->next=ldr;
  68. } else
  69. firstloader=ldr; 
  70. }
  71. MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
  72. {
  73. /* if we try to register an invalid loader, or an already registered loader,
  74.    ignore this attempt */
  75. if ((!ldr)||(ldr->next))
  76. return;
  77. MUTEX_LOCK(lists);
  78. _mm_registerloader(ldr);
  79. MUTEX_UNLOCK(lists);
  80. }
  81. BOOL ReadComment(UWORD len)
  82. {
  83. if(len) {
  84. int i;
  85. if(!(of.comment=(CHAR*)_mm_malloc(len+1))) return 0;
  86. _mm_read_UBYTES(of.comment,len,modreader);
  87. /* translate IT linefeeds */
  88. for(i=0;i<len;i++)
  89. if(of.comment[i]=='r') of.comment[i]='n';
  90. of.comment[len]=0; /* just in case */
  91. }
  92. if(!of.comment[0]) {
  93. free(of.comment);
  94. of.comment=NULL;
  95. }
  96. return 1;
  97. }
  98. BOOL ReadLinedComment(UWORD len,UWORD linelen)
  99. {
  100. CHAR *tempcomment,*line,*storage;
  101. UWORD total=0,t,lines;
  102. int i;
  103. lines = (len + linelen - 1) / linelen;
  104. if (len) {
  105. if(!(tempcomment=(CHAR*)_mm_malloc(len+1))) return 0;
  106. if(!(storage=(CHAR*)_mm_malloc(linelen+1))) {
  107. free(tempcomment);
  108. return 0;
  109. }
  110. memset(tempcomment, ' ', len);
  111. _mm_read_UBYTES(tempcomment,len,modreader);
  112. /* compute message length */
  113. for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
  114. for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;
  115. for(i=0;i<linelen;i++) if (!line[i]) break;
  116. total+=1+i;
  117. }
  118. if(total>lines) {
  119. if(!(of.comment=(CHAR*)_mm_malloc(total+1))) {
  120. free(storage);
  121. free(tempcomment);
  122. return 0;
  123. }
  124. /* convert message */
  125. for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
  126. for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
  127. storage[i]=0; /* if (i==linelen) */
  128. strcat(of.comment,storage);strcat(of.comment,"r");
  129. }
  130. free(storage);
  131. free(tempcomment);
  132. }
  133. }
  134. return 1;
  135. }
  136. BOOL AllocPositions(int total)
  137. {
  138. if(!total) {
  139. _mm_errno=MMERR_NOT_A_MODULE;
  140. return 0;
  141. }
  142. if(!(of.positions=_mm_calloc(total,sizeof(UWORD)))) return 0;
  143. return 1;
  144. }
  145. BOOL AllocPatterns(void)
  146. {
  147. int s,t,tracks = 0;
  148. if((!of.numpat)||(!of.numchn)) {
  149. _mm_errno=MMERR_NOT_A_MODULE;
  150. return 0;
  151. }
  152. /* Allocate track sequencing array */
  153. if(!(of.patterns=(UWORD*)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
  154. if(!(of.pattrows=(UWORD*)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
  155. for(t=0;t<=of.numpat;t++) {
  156. of.pattrows[t]=64;
  157. for(s=0;s<of.numchn;s++)
  158. of.patterns[(t*of.numchn)+s]=tracks++;
  159. }
  160. return 1;
  161. }
  162. BOOL AllocTracks(void)
  163. {
  164. if(!of.numtrk) {
  165. _mm_errno=MMERR_NOT_A_MODULE;
  166. return 0;
  167. }
  168. if(!(of.tracks=(UBYTE **)_mm_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
  169. return 1;
  170. }
  171. BOOL AllocInstruments(void)
  172. {
  173. int t,n;
  174. if(!of.numins) {
  175. _mm_errno=MMERR_NOT_A_MODULE;
  176. return 0;
  177. }
  178. if(!(of.instruments=(INSTRUMENT*)_mm_calloc(of.numins,sizeof(INSTRUMENT))))
  179. return 0;
  180. for(t=0;t<of.numins;t++) {
  181. for(n=0;n<INSTNOTES;n++) { 
  182. /* Init note / sample lookup table */
  183. of.instruments[t].samplenote[n]   = n;
  184. of.instruments[t].samplenumber[n] = t;
  185. }   
  186. of.instruments[t].globvol = 64;
  187. }
  188. return 1;
  189. }
  190. BOOL AllocSamples(void)
  191. {
  192. UWORD u;
  193. if(!of.numsmp) {
  194. _mm_errno=MMERR_NOT_A_MODULE;
  195. return 0;
  196. }
  197. if(!(of.samples=(SAMPLE*)_mm_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
  198. for(u=0;u<of.numsmp;u++) {
  199. of.samples[u].panning = 128; /* center */
  200. of.samples[u].handle  = -1;
  201. of.samples[u].globvol = 64;
  202. of.samples[u].volume  = 64;
  203. }
  204. return 1;
  205. }
  206. static BOOL ML_LoadSamples(void)
  207. {
  208. SAMPLE *s;
  209. int u;
  210. for(u=of.numsmp,s=of.samples;u;u--,s++)
  211. if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
  212. return 1;
  213. }
  214. /* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
  215.    terminating non-printing characters like 0, spaces etc.                    */
  216. CHAR *DupStr(CHAR* s,UWORD len,BOOL strict)
  217. {
  218. UWORD t;
  219. CHAR *d=NULL;
  220. /* Scan for last printing char in buffer [includes high ascii up to 254] */
  221. while(len) {
  222. if(s[len-1]>0x20) break;
  223. len--;
  224. }
  225. /* Scan forward for possible NULL character */
  226. if(strict) {
  227. for(t=0;t<len;t++) if (!s[t]) break;
  228. if (t<len) len=t;
  229. }
  230. /* When the buffer wasn't completely empty, allocate a cstring and copy the
  231.    buffer into that string, except for any control-chars */
  232. if((d=(CHAR*)_mm_malloc(sizeof(CHAR)*(len+1)))) {
  233. for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];
  234. d[len]=0;
  235. }
  236. return d;
  237. }
  238. static void ML_XFreeSample(SAMPLE *s)
  239. {
  240. if(s->handle>=0)
  241. MD_SampleUnload(s->handle);
  242. if(s->samplename) free(s->samplename);
  243. }
  244. static void ML_XFreeInstrument(INSTRUMENT *i)
  245. {
  246. if(i->insname) free(i->insname);
  247. }
  248. static void ML_FreeEx(MODULE *mf)
  249. {
  250. UWORD t;
  251. if(mf->songname) free(mf->songname);
  252. if(mf->comment)  free(mf->comment);
  253. if(mf->modtype)   free(mf->modtype);
  254. if(mf->positions) free(mf->positions);
  255. if(mf->patterns)  free(mf->patterns);
  256. if(mf->pattrows)  free(mf->pattrows);
  257. if(mf->tracks) {
  258. for(t=0;t<mf->numtrk;t++)
  259. if(mf->tracks[t]) free(mf->tracks[t]);
  260. free(mf->tracks);
  261. }
  262. if(mf->instruments) {
  263. for(t=0;t<mf->numins;t++)
  264. ML_XFreeInstrument(&mf->instruments[t]);
  265. free(mf->instruments);
  266. }
  267. if(mf->samples) {
  268. for(t=0;t<mf->numsmp;t++)
  269. if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
  270. free(mf->samples);
  271. }
  272. memset(mf,0,sizeof(MODULE));
  273. if(mf!=&of) free(mf);
  274. }
  275. static MODULE *ML_AllocUniMod(void)
  276. {
  277. MODULE *mf;
  278. return (mf=_mm_malloc(sizeof(MODULE)));
  279. }
  280. void Player_Free_internal(MODULE *mf)
  281. {
  282. if(mf) {
  283. Player_Exit_internal(mf);
  284. ML_FreeEx(mf);
  285. }
  286. }
  287. MIKMODAPI void Player_Free(MODULE *mf)
  288. {
  289. MUTEX_LOCK(vars);
  290. Player_Free_internal(mf);
  291. MUTEX_UNLOCK(vars);
  292. }
  293. static CHAR* Player_LoadTitle_internal(MREADER *reader)
  294. {
  295. MLOADER *l;
  296. modreader=reader;
  297. _mm_errno = 0;
  298. _mm_critical = 0;
  299. _mm_iobase_setcur(modreader);
  300. /* Try to find a loader that recognizes the module */
  301. for(l=firstloader;l;l=l->next) {
  302. _mm_rewind(modreader);
  303. if(l->Test()) break;
  304. }
  305. if(!l) {
  306. _mm_errno = MMERR_NOT_A_MODULE;
  307. if(_mm_errorhandler) _mm_errorhandler();
  308. return NULL;
  309. }
  310. return l->LoadTitle();
  311. }
  312. MIKMODAPI CHAR* Player_LoadTitleFP(FILE *fp)
  313. {
  314. CHAR* result=NULL;
  315. MREADER* reader;
  316. if(fp && (reader=_mm_new_file_reader(fp))) {
  317. MUTEX_LOCK(lists);
  318. result=Player_LoadTitle_internal(reader);
  319. MUTEX_UNLOCK(lists);
  320. _mm_delete_file_reader(reader);
  321. }
  322. return result;
  323. }
  324. MIKMODAPI CHAR* Player_LoadTitle(CHAR* filename)
  325. {
  326. CHAR* result=NULL;
  327. FILE* fp;
  328. MREADER* reader;
  329. if((fp=_mm_fopen(filename,"rb"))) {
  330. if((reader=_mm_new_file_reader(fp))) {
  331. MUTEX_LOCK(lists);
  332. result=Player_LoadTitle_internal(reader);
  333. MUTEX_UNLOCK(lists);
  334. _mm_delete_file_reader(reader);
  335. }
  336. _mm_fclose(fp);
  337. }
  338. return result;
  339. }
  340. /* Loads a module given an reader */
  341. MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)
  342. {
  343. int t;
  344. MLOADER *l;
  345. BOOL ok;
  346. MODULE *mf;
  347. modreader = reader;
  348. _mm_errno = 0;
  349. _mm_critical = 0;
  350. _mm_iobase_setcur(modreader);
  351. /* Try to find a loader that recognizes the module */
  352. for(l=firstloader;l;l=l->next) {
  353. _mm_rewind(modreader);
  354. if(l->Test()) break;
  355. }
  356. if(!l) {
  357. _mm_errno = MMERR_NOT_A_MODULE;
  358. if(_mm_errorhandler) _mm_errorhandler();
  359. _mm_rewind(modreader);_mm_iobase_revert();
  360. return NULL;
  361. }
  362. /* init unitrk routines */
  363. if(!UniInit()) {
  364. if(_mm_errorhandler) _mm_errorhandler();
  365. _mm_rewind(modreader);_mm_iobase_revert();
  366. return NULL;
  367. }
  368. /* init the module structure with vanilla settings */
  369. memset(&of,0,sizeof(MODULE));
  370. of.bpmlimit = 33;
  371. of.initvolume = 128;
  372. for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64;
  373. for (t = 0; t < UF_MAXCHAN; t++)
  374. of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT;
  375. /* init module loader and load the header / patterns */
  376. if (!l->Init || l->Init()) {
  377. _mm_rewind(modreader);
  378. ok = l->Load(curious);
  379. /* propagate inflags=flags for in-module samples */
  380. for (t = 0; t < of.numsmp; t++)
  381. if (of.samples[t].inflags == 0)
  382. of.samples[t].inflags = of.samples[t].flags;
  383. } else
  384. ok = 0;
  385. /* free loader and unitrk allocations */
  386. if (l->Cleanup) l->Cleanup();
  387. UniCleanup();
  388. if(!ok) {
  389. ML_FreeEx(&of);
  390. if(_mm_errorhandler) _mm_errorhandler();
  391. _mm_rewind(modreader);_mm_iobase_revert();
  392. return NULL;
  393. }
  394. if(!ML_LoadSamples()) {
  395. ML_FreeEx(&of);
  396. if(_mm_errorhandler) _mm_errorhandler();
  397. _mm_rewind(modreader);_mm_iobase_revert();
  398. return NULL;
  399. }
  400. if(!(mf=ML_AllocUniMod())) {
  401. ML_FreeEx(&of);
  402. _mm_rewind(modreader);_mm_iobase_revert();
  403. if(_mm_errorhandler) _mm_errorhandler();
  404. return NULL;
  405. }
  406. /* If the module doesn't have any specific panning, create a
  407.    MOD-like panning, with the channels half-separated. */
  408. if (!(of.flags & UF_PANNING))
  409. for (t = 0; t < of.numchn; t++)
  410. of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT;
  411. /* Copy the static MODULE contents into the dynamic MODULE struct. */
  412. memcpy(mf,&of,sizeof(MODULE));
  413. if(maxchan>0) {
  414. if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
  415. maxchan = mf->numchn;
  416. else
  417.   if((mf->numvoices)&&(mf->numvoices<maxchan))
  418. maxchan = mf->numvoices;
  419. if(maxchan<mf->numchn) mf->flags |= UF_NNA;
  420. if(MikMod_SetNumVoices_internal(maxchan,-1)) {
  421. _mm_iobase_revert();
  422. Player_Free(mf);
  423. return NULL;
  424. }
  425. }
  426. if(SL_LoadSamples()) {
  427. _mm_iobase_revert();
  428. Player_Free_internal(mf);
  429. return NULL;
  430. }
  431. if(Player_Init(mf)) {
  432. _mm_iobase_revert();
  433. Player_Free_internal(mf);
  434. mf=NULL;
  435. }
  436. _mm_iobase_revert();
  437. return mf;
  438. }
  439. MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
  440. {
  441. MODULE* result;
  442. MUTEX_LOCK(vars);
  443. MUTEX_LOCK(lists);
  444. result=Player_LoadGeneric_internal(reader,maxchan,curious);
  445. MUTEX_UNLOCK(lists);
  446. MUTEX_UNLOCK(vars);
  447. return result;
  448. }
  449. /* Loads a module given a file pointer.
  450.    File is loaded from the current file seek position. */
  451. MIKMODAPI MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
  452. {
  453. MODULE* result=NULL;
  454. struct MREADER* reader=_mm_new_file_reader (fp);
  455. if (reader) {
  456. result=Player_LoadGeneric(reader,maxchan,curious);
  457. _mm_delete_file_reader(reader);
  458. }
  459. return result;
  460. }
  461. /* Open a module via its filename.  The loader will initialize the specified
  462.    song-player 'player'. */
  463. MIKMODAPI MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious)
  464. {
  465. FILE *fp;
  466. MODULE *mf=NULL;
  467. if((fp=_mm_fopen(filename,"rb"))) {
  468. mf=Player_LoadFP(fp,maxchan,curious);
  469. _mm_fclose(fp);
  470. }
  471. return mf;
  472. }
  473. /* ex:set ts=4: */