new_mod.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. //TO DO:
  22. // Sample playing (including cache'ing and freeing up mem if needed)
  23. // Internal .MOD conversion
  24. #include "ems.h"
  25. #include "meminter.h"
  26. #include "mod.h"
  27. #include "bwsb.h"
  28. #include "data.h"
  29. #include "timer.h"
  30. #include <fcntl.h>
  31. #include <io.h>
  32. #include <dos.h>
  33. #include "string.h"
  34. #include "error.h"
  35. #include "boardmem.h"
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <sys\stat.h>
  39. extern char no_ems;
  40. extern int rob_global_ems;
  41. //Error leniency, 0 is least lenient, 2 is most lenient.
  42. //
  43. //Errors in most lenient: (normal game)
  44. // File "MZXBLANK.FIL" not found; Music code compromised
  45. // Low on conventional memory; Music code compromised
  46. //
  47. //Additional errors in middle leniency: (game w/debug menu)
  48. // Error opening module file
  49. // Error loading module
  50. // Error loading SAM
  51. // Out of memory for SAM
  52. //
  53. //Additional errors in least lenient: (editor)
  54. // Music is off- Module is set for board but not loaded
  55. // Music is off- SAM cannot play
  56. unsigned char error_mode=2;
  57. GDMHeader ModHeader; /* Module header */
  58. int ErrorFlag;
  59. int file, MusChans, t1;
  60. unsigned int Addr=0xFFFF,IRQ=0xFF,DMA=0xFF;
  61. char refresh_mod_playing;
  62. //char mod_playing[FILENAME_SIZE];
  63. char sfx_chan[4]={ -1,-1,-1,-1 };//Actual IDs of SFX channels (left)
  64. char sfx_chan2[4]={ -1,-1,-1,-1 };//Actual IDs of SFX channels (right)
  65. char actual_num_sfx=0;//Actual number of different SFX channels
  66. char current_sfx=0;//Current sfx channel
  67. char mod_active=0;//1=blank mod 2=real mod
  68. //Data for data integrity error checks
  69. int SCDoing=0;
  70. char far *SCLoadingName;
  71. #define FT_GDM 1
  72. #define FT_4MOD 2
  73. #define FT_8MOD 3
  74. #define FT_XMOD 4
  75. //(unkown)
  76. #define FT_NONE 0
  77. int _file_type(int fp,char *fn) {
  78. char id[5];
  79. int tmp;
  80. //Tells us what kind of Music file it is! (assumes at start of file)
  81. read(fp,&id,4);
  82. id[4]=0;
  83. if(!str_cmp(id,"GDMþ")) return FT_GDM;
  84. lseek(fp,1080,SEEK_SET);
  85. read(fp,&id,4);
  86. id[4]=0;
  87. if(!str_cmp(id,"M.K.")) {
  88. //WOW??
  89. tmp=str_len(fn);
  90. if(!str_cmp(&fn[tmp-3],"WOW")) return FT_8MOD;
  91. else return FT_4MOD;
  92. }
  93. if((!str_cmp(id,"M!K!"))||(!str_cmp(id,"FLT4"))||
  94. (!str_cmp(id,"4CHN"))) return FT_4MOD;
  95. if((!str_cmp(id,"8CHN"))||(!str_cmp(id,"FLT8"))||
  96. (!str_cmp(id,"OCTA"))) return FT_8MOD;
  97. if((id[1]=='C')&&(id[2]=='H')&&(id[3]=='N')) return FT_XMOD;
  98. if((id[2]=='C')&&(id[3]=='H')) return FT_XMOD;
  99. return FT_NONE;
  100. }
  101. int ConvertMOD(int file,int type);
  102. void load_mod(char far *filename) {
  103. int t1,t2;
  104. char temp3[FILENAME_SIZE];
  105. SCDoing|=512;
  106. SCLoadingName=filename;
  107. if(!music_device) music_on=0;
  108. if (!str_cmp(filename, "*")) {
  109. if (refresh_mod_playing) {
  110. //str_cpy(temp, real_mod_playing);
  111. if (str_cmp(real_mod_playing, "*")) {
  112. str_cpy(temp3, real_mod_playing);
  113. load_mod(temp3);
  114. } else { // just so we don't eat ourselves recursively
  115. error("load_mod(): real_mod_playing is ``*'' -- this is a bug\n",0,8,current_pg_seg,0x0f00);
  116. }
  117. }
  118. str_cpy(mod_playing, "*");
  119. refresh_mod_playing = 0;
  120. return;
  121. }
  122. refresh_mod_playing = 0;
  123. free_sam_cache(1);//Clear entire sfx cache
  124. save_map_state_EMS(rob_global_ems);
  125. if(mod_active>0) {
  126. StopMusic();
  127. StopOutput();
  128. UnloadModule();
  129. }
  130. mod_active=0;
  131. mod_playing[0]=0;
  132. real_mod_playing[0]=0;
  133. if(!music_on) {
  134. //Save mod playing...
  135. if(filename!=NULL) {
  136. str_cpy(mod_playing,filename);
  137. str_cpy(real_mod_playing,filename);
  138. if(!error_mode) error("Music is off- Module is set for board but not loaded",
  139. 0,24,current_pg_seg,0x3201);
  140. }
  141. restore_map_state_EMS(rob_global_ems);
  142. SCDoing&=~512;
  143. return;
  144. }
  145. if(filename==NULL) goto load_empty_mod;
  146. retry_1:
  147. ErrorFlag=EmsExist()&&1;/* Enable EMS if available */
  148. //Turn off EMS if requested in CMD line-
  149. if(no_ems) ErrorFlag=0;
  150. file=open(filename,O_RDONLY|O_BINARY);
  151. if(file>-1) {
  152. //Check file type
  153. t1=_file_type(file,filename);
  154. if(t1==FT_NONE) {
  155. ErrorFlag=1;
  156. close(file);
  157. goto tsukino;
  158. }
  159. if(t1==FT_GDM) {
  160. LoadGDM(file,0,&ErrorFlag,&ModHeader);
  161. close(file);
  162. }
  163. else {
  164. //Mod file
  165. file=ConvertMOD(file,t1);
  166. LoadGDM(file,0,&ErrorFlag,&ModHeader);
  167. close(file);
  168. }
  169. }
  170. else {
  171. if(error_mode<2) error("Error opening module file",1,24,current_pg_seg,0x3701);
  172. goto load_empty_mod;
  173. }
  174. //Errors-
  175. if(ErrorFlag) {
  176. UnloadModule();
  177. //Try to free up memory
  178. restore_map_state_EMS(rob_global_ems);
  179. free_up_board_memory();
  180. save_map_state_EMS(rob_global_ems);
  181. file=open(filename,O_RDONLY|O_BINARY);
  182. if(file>-1) {
  183. //Check file type
  184. t1=_file_type(file,filename);
  185. if(t1==FT_NONE) {
  186. ErrorFlag=1;
  187. close(file);
  188. goto tsukino;
  189. }
  190. if(t1==FT_GDM) {
  191. LoadGDM(file,0,&ErrorFlag,&ModHeader);
  192. close(file);
  193. }
  194. else {
  195. //Mod file
  196. file=ConvertMOD(file,t1);
  197. LoadGDM(file,0,&ErrorFlag,&ModHeader);
  198. close(file);
  199. }
  200. }
  201. else {
  202. tsukino:
  203. if(error_mode<2) error("Error opening module file",1,24,current_pg_seg,0x3701);
  204. goto load_empty_mod;
  205. }
  206. if(ErrorFlag) {
  207. UnloadModule();
  208. if(error_mode<2)
  209. if(error("Error loading module",1,26,current_pg_seg,0x3300+ErrorFlag)==2)
  210. goto retry_1;
  211. goto load_empty_mod;
  212. }
  213. }
  214. //Count number of channels
  215. MusChans=current_sfx=actual_num_sfx=0;
  216. sfx_chan[0]=sfx_chan[1]=sfx_chan[2]=sfx_chan[3]=-1;
  217. sfx_chan2[0]=sfx_chan2[1]=sfx_chan2[2]=sfx_chan2[3]=-1;
  218. t2=0;//Start on left
  219. for(t1=0;t1<32;t1++) {
  220. if(ModHeader.PanMap[t1]!=0xFF) MusChans++;
  221. else if(actual_num_sfx<4) {
  222. ModHeader.PanMap[t1]=t2;
  223. if(t2==0) {//Left channel
  224. sfx_chan[actual_num_sfx]=t1;
  225. t2=0xF;
  226. }
  227. else {//Right channel
  228. sfx_chan2[actual_num_sfx++]=t1;
  229. t2=0;
  230. }
  231. }
  232. }
  233. if(actual_num_sfx>sfx_channels) actual_num_sfx=sfx_channels;
  234. MusChans+=actual_num_sfx<<1;
  235. if((actual_num_sfx==0)&&(sfx_channels>0)) {
  236. actual_num_sfx=1;
  237. sfx_chan[0]=30;
  238. sfx_chan2[0]=31;
  239. }
  240. //Activate up to 4 (8) SFX channels
  241. StartOutput(MusChans,0);
  242. StartMusic();
  243. str_cpy(mod_playing,filename);
  244. str_cpy(real_mod_playing,filename);
  245. mod_active=2;
  246. restore_map_state_EMS(rob_global_ems);
  247. SCDoing&=~512;
  248. return;
  249. load_empty_mod:
  250. retry_2:
  251. //Load "blank MOD"
  252. ErrorFlag=EmsExist()&&1;/* Enable EMS if available */
  253. //Turn off EMS if requested in CMD line-
  254. if(no_ems) ErrorFlag=0;
  255. file=open(mzx_blank_mod_file,O_RDONLY|O_BINARY);
  256. if(file>-1) {
  257. LoadGDM(file,0,&ErrorFlag,&ModHeader);
  258. close(file);
  259. }
  260. else {
  261. error("File \"MZXBLANK.FIL\" not found; Music code compromised",1,24,
  262. current_pg_seg,0x3601);
  263. goto load_no_mod;
  264. }
  265. //Errors-
  266. if(ErrorFlag) {
  267. UnloadModule();
  268. //Try to free up memory
  269. restore_map_state_EMS(rob_global_ems);
  270. free_up_board_memory();
  271. save_map_state_EMS(rob_global_ems);
  272. file=open(filename,O_RDONLY|O_BINARY);
  273. if(file>-1) {
  274. LoadGDM(file,0,&ErrorFlag,&ModHeader);
  275. close(file);
  276. }
  277. else {
  278. error("File \"MZXBLANK.FIL\" not found; Music code compromised",1,24,
  279. current_pg_seg,0x3601);
  280. goto load_no_mod;
  281. }
  282. if(ErrorFlag) {
  283. UnloadModule();
  284. if(error("Low on memory; Music code compromised",1,26,current_pg_seg,0x0600+ErrorFlag)==2)
  285. goto retry_2;
  286. goto load_no_mod;
  287. }
  288. }
  289. //Count number of channels
  290. MusChans=sfx_channels<<1;
  291. current_sfx=0;
  292. actual_num_sfx=sfx_channels;
  293. sfx_chan[0]=sfx_chan[1]=sfx_chan[2]=sfx_chan[3]=-1;
  294. sfx_chan2[0]=sfx_chan2[1]=sfx_chan2[2]=sfx_chan2[3]=-1;
  295. for(t1=0;t1<sfx_channels;t1++) {
  296. ModHeader.PanMap[(t1<<1)]=0;
  297. ModHeader.PanMap[(t1<<1)+1]=0xF;
  298. sfx_chan[t1]=(t1<<1);
  299. sfx_chan2[t1]=(t1<<1)+1;
  300. }
  301. //Activate up to 4 SFX channels
  302. StartOutput(MusChans,0);
  303. StartMusic();
  304. if(filename!=NULL) {
  305. str_cpy(mod_playing,filename);
  306. str_cpy(real_mod_playing,filename);
  307. }
  308. mod_active=1;
  309. restore_map_state_EMS(rob_global_ems);
  310. SCDoing&=~512;
  311. return;
  312. load_no_mod:
  313. mod_active=actual_num_sfx=0;
  314. if(filename!=NULL) {
  315. str_cpy(mod_playing,filename);
  316. str_cpy(real_mod_playing,filename);
  317. }
  318. restore_map_state_EMS(rob_global_ems);
  319. SCDoing&=~512;
  320. return;
  321. }
  322. void end_mod(void) {
  323. load_mod(NULL);
  324. }
  325. //Sample allocation info-
  326. //Number of samples minimum cacheable (must be min. 4)
  327. #define NUM_SAM_CACHE 16
  328. //For sample allocation into MOD memory
  329. SamHeader SamHead[NUM_SAM_CACHE];
  330. //Allocated pointers (NULL does NOT mean NOT LOADED. see SamPlayed)
  331. char far *SamStorage[NUM_SAM_CACHE];
  332. //Filenames
  333. char SamNames[NUM_SAM_CACHE][13];
  334. //Number of times played (0=NOT LOADED)
  335. int SamPlayed[NUM_SAM_CACHE];
  336. //SFX Channel currently playing on plus one (0=none) 1-4
  337. char SamChannel[NUM_SAM_CACHE];
  338. //Sam numbers stored in, in MOD memory- 250 minus cache index
  339. //Internal func-initialize arrays
  340. void _init_sam_cache(void) {
  341. int t1,t2;
  342. for(t1=0;t1<NUM_SAM_CACHE;t1++) {
  343. SamStorage[t1]=NULL;
  344. SamNames[t1][0]=0;
  345. SamPlayed[t1]=0;
  346. SamChannel[t1]=0;
  347. for(t2=0;t2<32;t2++) SamHead[t1].SamName[t2]=0;
  348. for(t2=0;t2<12;t2++) SamHead[t1].FileName[t2]=0;
  349. SamHead[t1].EmsHandle=0;
  350. SamHead[t1].LoopBegin=0;
  351. SamHead[t1].LoopEnd=0;
  352. SamHead[t1].Flags=0;
  353. SamHead[t1].C4Hertz=8363;
  354. SamHead[t1].Volume=64;
  355. SamHead[t1].Pan=0xFF;
  356. SamHead[t1].Length=0;
  357. SamHead[t1].Segment=0;
  358. }
  359. }
  360. //Internal- Deallocates one sample by cache index
  361. void _free_sam(char sam_num) {
  362. if(SamPlayed[sam_num]==0) return;
  363. SCDoing|=32;
  364. save_map_state_EMS(rob_global_ems);
  365. if(SamChannel[sam_num]) {
  366. //Stop playing
  367. ChannelPos(sfx_chan[SamChannel[sam_num]-1]+1,65534);
  368. ChannelPos(sfx_chan2[SamChannel[sam_num]-1]+1,65534);
  369. ChannelVol(sfx_chan[SamChannel[sam_num]-1]+1,0);
  370. ChannelVol(sfx_chan2[SamChannel[sam_num]-1]+1,0);
  371. }
  372. //Free actual sample from music code
  373. if(FreeSample(250-sam_num)&255) error("BAD !",2,4,current_pg_seg,1);
  374. //Free memory (auto freed by FreeSample)
  375. if(SamStorage[sam_num]!=NULL) SamStorage[sam_num]=NULL;
  376. //Set other stuff
  377. SamNames[sam_num][0]=0;
  378. SamPlayed[sam_num]=0;
  379. SamChannel[sam_num]=0;
  380. SamHead[sam_num].Length=0;
  381. SamHead[sam_num].Segment=0;
  382. SamHead[sam_num].EmsHandle=0;
  383. restore_map_state_EMS(rob_global_ems);
  384. SCDoing&=~32;
  385. }
  386. //This function will remove samples from the cache one at a time,
  387. //starting with least-played and ending with currently-playing.
  388. //Call it removes ONE sample unless CLEAR_ALL is set. Returns 1
  389. //if nothing was found to deallocate (IE no further fixes possible)
  390. char free_sam_cache(char clear_all) {
  391. //LeastPlayedNotPlaying, LeastPlayedCurrentlyPlaying
  392. int lpnp,lpcp;
  393. //Value of the above, IE the number of TIMES played
  394. int lpnpv,lpcpv;
  395. int t1;
  396. SCDoing|=clear_all?64:128;
  397. next:
  398. lpnp=lpcp=-1;
  399. lpnpv=lpcpv=32767;
  400. for(t1=0;t1<NUM_SAM_CACHE;t1++) {
  401. if(SamPlayed[t1]<1) continue;//Skip those not loaded
  402. if(SamChannel[t1]) {
  403. if(SamPlayed[t1]<lpcpv) {
  404. lpcpv=SamPlayed[t1];
  405. lpcp=t1;
  406. }
  407. }
  408. else {
  409. if(SamPlayed[t1]<lpnpv) {
  410. lpnpv=SamPlayed[t1];
  411. lpnp=t1;
  412. }
  413. }
  414. }
  415. //Any NOT playing?
  416. if(lpnp>=0) {
  417. //Yep, deallocate
  418. _free_sam(lpnp);
  419. if(clear_all) goto next;
  420. SCDoing&=~(64|128);
  421. return 0;
  422. }
  423. //No? Any PLAYING!?
  424. if(lpcp>=0) {
  425. //Yep, deallocate
  426. _free_sam(lpcp);
  427. if(clear_all) goto next;
  428. SCDoing&=~(64|128);
  429. return 0;
  430. }
  431. //Nope.
  432. SCDoing&=~(64|128);
  433. return 1;
  434. }
  435. //This one will return the cache index for a given sample filename.
  436. //If needed it will allocate it, freeing memory if necessary.
  437. //Returns -1 if out of memory, -2 on error loading sample
  438. //Increases SamPlayed.
  439. char _load_sam(char far *file) {
  440. //First, see if already loaded
  441. int t1,t2;
  442. char oldc;
  443. FILE *fp;
  444. long siz;
  445. SCLoadingName=file;
  446. SCDoing|=256;
  447. for(t1=0;t1<NUM_SAM_CACHE;t1++) {
  448. if(!str_cmp(file,SamNames[t1]))
  449. if(SamPlayed[t1]) break;//Found
  450. }
  451. if(t1<NUM_SAM_CACHE) {
  452. if(SamPlayed[t1]<32700) SamPlayed[t1]++;//No overflow!
  453. SCDoing&=~256;
  454. return t1;
  455. }
  456. //Oops, must load a new one
  457. //Find an empty slot
  458. find_empty:
  459. for(t1=0;t1<NUM_SAM_CACHE;t1++)
  460. if(SamPlayed[t1]==0) break;
  461. if(t1>=NUM_SAM_CACHE) {
  462. //Create a new slot
  463. free_sam_cache(0);
  464. goto find_empty;
  465. }
  466. //Now open file and get filesize
  467. fp=fopen(file,"rb");
  468. if(fp==NULL) return -2;
  469. fseek(fp,0,SEEK_END);
  470. siz=ftell(fp);
  471. siz&=~1;//Make it even through truncation
  472. if(siz>65500) siz=65500;//Truncate filesize
  473. if(siz<4) {
  474. //Too short
  475. fclose(fp);
  476. SCDoing&=~256;
  477. return -2;
  478. }
  479. //Now we work to allocate memory
  480. if(NULL==(SamStorage[t1]=(char far *)farmalloc(siz))) {
  481. //Try to free up memory
  482. free_up_board_memory();
  483. if(NULL==(SamStorage[t1]=(char far *)farmalloc(siz))) {
  484. //Free up other samples
  485. while(!free_sam_cache(0)) {
  486. SamStorage[t1]=(char far *)farmalloc(siz);
  487. if(SamStorage[t1]!=NULL) break;
  488. }
  489. //Did we not get it?
  490. if(SamStorage[t1]==NULL) {
  491. fclose(fp);
  492. SCDoing&=~256;
  493. return -1;//Out of memory
  494. }
  495. }
  496. }
  497. //Allocated. Load sample in.
  498. fseek(fp,0,SEEK_SET);
  499. fread(SamStorage[t1],siz,1,fp);
  500. fclose(fp);
  501. mem_xor(SamStorage[t1],siz,128);
  502. //Save name and set played to 1
  503. //Before saving name, truncate filename if over 12 chars
  504. if(str_len(file)>12) {
  505. error("BAD !",2,4,current_pg_seg,3);
  506. oldc=file[12];
  507. file[12]=0;
  508. str_cpy(SamNames[t1],file);
  509. file[12]=oldc;
  510. }
  511. else str_cpy(SamNames[t1],file);
  512. SamPlayed[t1]=1;
  513. //Now allocate into actual MOD memory
  514. save_map_state_EMS(rob_global_ems);
  515. SamHead[t1].Length=siz;
  516. SamHead[t1].EmsHandle=0;
  517. SamHead[t1].Segment=FP_SEG(SamStorage[t1]);
  518. t2=AllocSample(250-t1,&SamHead[t1]);
  519. restore_map_state_EMS(rob_global_ems);
  520. //Free memory?
  521. if(t2) {
  522. farfree(SamStorage[t1]);
  523. SamStorage[t1]=NULL;
  524. }
  525. //Error?
  526. if(t2<2) {
  527. SCDoing&=~256;
  528. return t1;
  529. }
  530. error("BAD !",2,4,current_pg_seg,2);
  531. SamPlayed[t1]=0;
  532. SamNames[t1][0]=0;
  533. SamHead[t1].Length=0;
  534. SamHead[t1].Segment=0;
  535. SamHead[t1].EmsHandle=0;
  536. SCDoing&=~256;
  537. return -2;
  538. }
  539. //Quick Set SamChannel array to clear all instances
  540. //of something being played on given channel (doesn't STOP playback)
  541. void _clear_cache_chan(char channel) {
  542. int t1;
  543. for(t1=0;t1<NUM_SAM_CACHE;t1++)
  544. if(SamChannel[t1]==channel+1) SamChannel[t1]=0;
  545. }
  546. //Old frequencies - 214 = C-3 (c-5 now), INCREASE octave = half
  547. //New frequencies - 16770 = C-3 (c-5 now), DECREASE octave = half
  548. //Equation NEW=3588780/OLD
  549. void play_sample(int freq,char far *file) {
  550. long conv;
  551. int sample;
  552. if(!mod_active) return;
  553. if(!music_device) return;
  554. if(music_device==6) return;
  555. if(!actual_num_sfx) return;
  556. if(!freq) return;
  557. SCDoing|=1;
  558. conv=(3588780L/(long)freq);
  559. if(conv>65535U) conv=65535U;
  560. sample=_load_sam(file);
  561. if(sample<0) {
  562. //Error
  563. if(error_mode<2) {
  564. switch(sample) {
  565. case -1://Out of memory for SAM 0x2A01
  566. error("Out of memory for SAM",1,24,current_pg_seg,0x2A01);
  567. break;
  568. case -2://Error loading SAM 0x3501
  569. error("Error loading SAM",1,24,current_pg_seg,0x3501);
  570. break;
  571. }
  572. }
  573. SCDoing&=~1;
  574. return;
  575. }
  576. _clear_cache_chan(current_sfx);
  577. SamChannel[sample]=current_sfx+1;
  578. save_map_state_EMS(rob_global_ems);
  579. PlaySample(sfx_chan[current_sfx]+1,250-sample,conv,sound_gvol<<3,0xFF);
  580. PlaySample(sfx_chan2[current_sfx++]+1,250-sample,conv,sound_gvol<<3,0xFF);
  581. restore_map_state_EMS(rob_global_ems);
  582. if(current_sfx>=actual_num_sfx) current_sfx=0;
  583. SCDoing&=~1;
  584. }
  585. void end_sample(void) {
  586. int t1;
  587. if(!mod_active) return;
  588. if(!music_device) return;
  589. if(music_device==6) return;
  590. if(!actual_num_sfx) return;
  591. SCDoing|=2;
  592. save_map_state_EMS(rob_global_ems);
  593. for(t1=0;t1<actual_num_sfx;t1++) {
  594. ChannelVol(sfx_chan[t1]+1,0);
  595. ChannelVol(sfx_chan2[t1]+1,0);
  596. }
  597. for(t1=0;t1<NUM_SAM_CACHE;t1++)
  598. SamChannel[t1]=0;
  599. restore_map_state_EMS(rob_global_ems);
  600. SCDoing&=~2;
  601. }
  602. void jump_mod(int order) {
  603. if(!music_device) return;
  604. if(!mod_active) return;
  605. SCDoing|=4;
  606. save_map_state_EMS(rob_global_ems);
  607. MusicOrder(order);
  608. restore_map_state_EMS(rob_global_ems);
  609. SCDoing&=~4;
  610. }
  611. void volume_mod(int vol) {
  612. if(!music_device) return;
  613. if(!mod_active) return;
  614. SCDoing|=8;
  615. save_map_state_EMS(rob_global_ems);
  616. MusicVolume((vol*music_gvol)>>5);
  617. restore_map_state_EMS(rob_global_ems);
  618. SCDoing&=~8;
  619. }
  620. void mod_exit(void) {
  621. if(!music_device) return;
  622. free_sam_cache(1);
  623. if(mod_active>0) {
  624. StopMusic();
  625. StopOutput();
  626. UnloadModule();
  627. }
  628. mod_active=0;
  629. FreeMSE();
  630. music_device=0;
  631. }
  632. void music_off(void) {
  633. if(!music_device) return;
  634. free_sam_cache(1);
  635. save_map_state_EMS(rob_global_ems);
  636. if(mod_active>0) {
  637. StopMusic();
  638. StopOutput();
  639. UnloadModule();
  640. }
  641. mod_active=0;
  642. restore_map_state_EMS(rob_global_ems);
  643. }
  644. void mod_init(void) {
  645. if(!music_device) return;
  646. //Concatenate path of base MZX directory-
  647. str_cat(mzx_blank_mod_file,"MZXBLANK.FIL");
  648. str_cat(mzx_convert_mod_file,"MZX_CMOD.FIL");
  649. str_cat(MSE_file,music_MSEs[music_device]);
  650. ErrorFlag=LoadMSE(MSE_file,0,mixing_rate,4096,&Addr,&IRQ,&DMA);
  651. switch(ErrorFlag) {
  652. case 1:
  653. music_device=0;
  654. error("Sound card I/O address detection failure",2,20,
  655. current_pg_seg,0x3801);
  656. case 2:
  657. music_device=0;
  658. error("Sound card IRQ level detection failure",2,20,
  659. current_pg_seg,0x3901);
  660. case 3:
  661. case 4:
  662. music_device=0;
  663. error("Sound card DMA channel detection failure",2,20,
  664. current_pg_seg,0x3A01+ErrorFlag-3);
  665. case 10:
  666. case 11:
  667. music_device=0;
  668. error("Error loading MSE music driver",2,20,
  669. current_pg_seg,0x3C01+ErrorFlag-10);
  670. case 12:
  671. music_device=0;
  672. error("MVSOUND.SYS must be loaded for PAS support",2,20,
  673. current_pg_seg,0x3D01);
  674. default:
  675. music_device=0;
  676. error("Error initializing sound card/music code",2,20,
  677. current_pg_seg,0x3B01+ErrorFlag-6);
  678. case 0:
  679. break;
  680. }
  681. end_mod();
  682. _init_sam_cache();
  683. }
  684. //Old frequencies - 214 = C-3 (c-5 now), INCREASE octave = half
  685. //New frequencies - 16770 = C-3 (c-5 now), DECREASE octave = half
  686. //Equation NEW=3588780/OLD
  687. void spot_sample(int freq,int sample) {
  688. long conv;
  689. if(!freq) return;
  690. if(!music_device) return;
  691. if(!actual_num_sfx) return;
  692. if(!mod_active) return;
  693. SCDoing|=16;
  694. conv=(3588780L/(long)freq);
  695. if(conv>65535U) conv=65535U;
  696. _clear_cache_chan(current_sfx);
  697. save_map_state_EMS(rob_global_ems);
  698. PlaySample(sfx_chan[current_sfx]+1,sample,conv,sound_gvol<<3,0xFF);
  699. PlaySample(sfx_chan2[current_sfx++]+1,sample,conv,sound_gvol<<3,0xFF);
  700. restore_map_state_EMS(rob_global_ems);
  701. if(current_sfx>=actual_num_sfx) current_sfx=0;
  702. SCDoing&=~16;
  703. }
  704. typedef unsigned char byte;
  705. typedef unsigned int word;
  706. typedef unsigned long dword;
  707. //Converts a mod
  708. int MODSamC4Hertz[16]={
  709. 8363, 8424, 8485, 8547, 8608, 8671, 8734, 8797, 7894,
  710. 7951, 8009, 8067, 8125, 8184, 8244, 8303 };
  711. GDMHeader GDMHead={//Pre-init as much data as possible
  712. { 'G','D','M','þ' },
  713. { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  714. { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  715. { 13,10,26 },
  716. { 'G','M','F','S' },
  717. 1,
  718. 0,
  719. 115,
  720. 2,
  721. 5,
  722. { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  723. 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 },
  724. 64,
  725. 6,
  726. 125,
  727. 1,
  728. 0,0,
  729. 0,0,
  730. 0,0,0,
  731. 0,0,
  732. 0,0,
  733. 0,0 };
  734. SamHeader2 SamHead2[31]={//Pre-init as much data as possible :)
  735. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  736. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  737. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  738. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  739. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  740. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  741. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  742. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  743. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  744. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  745. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  746. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  747. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  748. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  749. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  750. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  751. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  752. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  753. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  754. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  755. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  756. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  757. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  758. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  759. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  760. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  761. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  762. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  763. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  764. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  765. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  766. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  767. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  768. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  769. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  770. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  771. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  772. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  773. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  774. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  775. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  776. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  777. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  778. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  779. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  780. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  781. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  782. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  783. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  784. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  785. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  786. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  787. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  788. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  789. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  790. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  791. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  792. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  793. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  794. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 },
  795. { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  796. { 0,0,0,0,0,0,0,0,0,0,0,0 },0,0,0,0,0,0,0,255 } };
  797. byte far patdata[2624];//Allocate at runtime, later. (dest info for GDM)
  798. byte far Music[2048];//Same. (orig pattern info)
  799. //Periods for standard mod notes
  800. int PT[60]={
  801. 1712, 1616, 1525, 1440, 1357, 1281, 1209, 1141, 1077, 1017, 961, 907,
  802. 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
  803. 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
  804. 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113,
  805. 107, 101, 95, 90, 85, 80, 76, 71, 67, 64, 60, 57 };
  806. //GDM note value for each of these 60 "notes"
  807. byte Note2GDM[60]={
  808. 33,34,35,36,37,38,39,40,41,42,43,44,
  809. 49,50,51,52,53,54,55,56,57,58,59,60,
  810. 65,66,67,68,69,70,71,72,73,74,75,76,
  811. 81,82,83,84,85,86,87,88,89,90,91,92,
  812. 97,98,99,100,101,102,103,104,105,106,107,108 };
  813. //Generic order for channel mapping
  814. byte DefPan[32]={ 15,0,0,15,15,0,0,15,15,0,0,15,
  815. 15,0,0,15,15,0,0,15,15,0,0,15,15,0,0,15,15,0,0,15 };
  816. //Uses DOS file handle; returns handle to new file.
  817. //Always closes old file. Returns -1 on error.
  818. int ConvertMOD(int file,int type) {
  819. int tmp,tmp2,sam,NOP,patpos,pos,Note,LastFit;
  820. byte MaxChan,Patt,Row,Channel,FX1,FX1Data,NumChan,NumSam,
  821. Byte1,Byte2,Byte3,GDMNote,GDMIns,Chan,Ins,EvPos;
  822. byte Events[20];
  823. //For sample copy
  824. byte far *buff=NULL;
  825. word chunk=60000,chunk2;
  826. long len;
  827. char id[5];
  828. int destfile=open(mzx_convert_mod_file,O_CREAT|O_TRUNC|O_RDWR|O_BINARY,
  829. S_IREAD|S_IWRITE);
  830. if(destfile==-1) {
  831. close(file);
  832. return -1;
  833. }
  834. NumSam=30;
  835. switch(type) {
  836. case FT_4MOD:
  837. NumChan=3;
  838. break;
  839. case FT_8MOD:
  840. NumChan=7;
  841. break;
  842. default:
  843. //Determine number of channels
  844. lseek(file,1080,SEEK_SET);
  845. read(file,id,4);
  846. if(id[3]=='N') NumChan=id[0]-'1';//1 through 9 channels
  847. else NumChan=(id[1]-'1')+((id[0]-'0')*10);//10 and up channels
  848. break;
  849. }
  850. lseek(destfile,sizeof(GDMHeader),SEEK_SET);
  851. //Header conversion
  852. mem_cpy(GDMHead.PanMap,DefPan,32);
  853. GDMHead.NOS=NumSam;
  854. //Sample header conversion
  855. lseek(file,20,SEEK_SET);
  856. GDMHead.SamHeadOffset=tell(destfile);
  857. for(sam=0;sam<=NumSam;sam++) {
  858. //Convert sample header #sam
  859. tmp2=4;
  860. lseek(file,22,SEEK_CUR);
  861. read(file,Events,8);
  862. asm rol word ptr Events,8
  863. asm rol word ptr Events+4,8
  864. asm rol word ptr Events+6,8
  865. SamHead2[sam].Length=((unsigned int *)Events)[0]<<1;
  866. SamHead2[sam].C4Hertz=MODSamC4Hertz[Events[2]&0xF];
  867. if((SamHead2[sam].Volume=Events[3])>64) SamHead2[sam].Volume=64;
  868. SamHead2[sam].LoopBegin=((unsigned int *)Events)[2]<<1;
  869. SamHead2[sam].LoopEnd=SamHead2[sam].LoopBegin+
  870. (((unsigned int *)Events)[3]<<1)+1;
  871. if((SamHead2[sam].LoopEnd-SamHead2[sam].LoopBegin)>8) tmp2|=1;
  872. if(SamHead2[sam].LoopEnd>SamHead2[sam].Length)
  873. SamHead2[sam].LoopEnd=SamHead2[sam].Length+1;
  874. SamHead2[sam].Flags=tmp2;
  875. }
  876. for(tmp=NumSam;tmp>=0;tmp--)
  877. if((SamHead2[tmp].SamName[0])||(SamHead2[tmp].Length)) break;
  878. GDMHead.NOS=tmp;
  879. for(sam=0;sam<=GDMHead.NOS;sam++)
  880. write(destfile,&SamHead2[sam],sizeof(SamHeader2));
  881. //Order conversion
  882. read(file,patdata,130);
  883. GDMHead.NOO=patdata[0]-1;
  884. GDMHead.OrdOffset=tell(destfile);
  885. NOP=0;
  886. for(tmp=2;tmp<130;tmp++)
  887. if(patdata[tmp]>NOP) NOP=patdata[tmp];
  888. GDMHead.NOP=NOP;
  889. write(destfile,&patdata[2],GDMHead.NOO+1);
  890. //Pattern conversion
  891. lseek(file,154+(NumSam+1)*30,SEEK_SET);
  892. GDMHead.PatOffset=tell(destfile);
  893. MaxChan=0;
  894. for(Patt=0;Patt<=GDMHead.NOP;Patt++) {
  895. //Convert pattern #Patt
  896. patpos=2;
  897. pos=0;
  898. read(file,Music,(NumChan+1)<<8);
  899. for(Row=0;Row<64;Row++) {
  900. for(Channel=0;Channel<=NumChan;Channel++) {
  901. GDMNote=GDMIns=0;
  902. Byte1=Music[pos++];
  903. Byte2=Music[pos++];
  904. Byte3=Music[pos++];
  905. FX1Data=Music[pos++];
  906. Note=((Byte1&15)<<8)+Byte2;
  907. Ins=(Byte3>>4)+(Byte1&0xF0);
  908. if((Note)||(Ins)) {
  909. GDMIns=Ins;
  910. if(GDMIns>(GDMHead.NOS+1)) GDMIns=0;
  911. if(Note) {
  912. LastFit=32767;
  913. for(tmp=0;tmp<60;tmp++) {
  914. if(abs(PT[tmp]-Note)<LastFit) {
  915. GDMNote=Note2GDM[tmp];
  916. LastFit=abs(PT[tmp]-Note);
  917. }
  918. }
  919. }
  920. }
  921. FX1=Byte3&15;
  922. switch(FX1) {
  923. //Effects to leave as-is-
  924. //1 Portamento up
  925. //2 Portamento down
  926. //4 Vibrato
  927. //7 Tremolo
  928. //9 Sample offset
  929. //B Jump to order
  930. //D Pattern break
  931. case 0://Arpeggio or no-command
  932. if(FX1Data) FX1=0x10;
  933. break;
  934. case 3://Portamento to
  935. if(GDMNote) GDMNote=((GDMNote-1)|128)+1;
  936. break;
  937. case 5://Portamento to+Volume slide
  938. if(GDMNote) GDMNote=((GDMNote-1)|128)+1;
  939. if(FX1Data==0) FX1=3;
  940. break;
  941. case 6://Vibrato+Volume slide
  942. if(FX1Data==0) FX1=4;
  943. break;
  944. case 8://Pan
  945. /* if(FX1Data==0xA4) {
  946. FX1=0x1E;
  947. FX1Data=1;
  948. }
  949. else {
  950. if(FX1Data<0x80) {
  951. FX1Data>>=3;
  952. if(FX1Data>15) FX1Data=15;
  953. FX1=0x1E;
  954. FX1Data|=0x80;
  955. }
  956. else FX1=FX1Data=0;
  957. }*/
  958. FX1=FX1Data=0;
  959. break;
  960. case 0xA://Volume Slide
  961. if(FX1Data==0) FX1=0;
  962. break;
  963. case 0xC://Set Volume
  964. if(FX1Data>64) FX1Data=64;
  965. break;
  966. case 0xF://Set Tempo or BPM
  967. if(FX1Data>31) FX1=0x1F;
  968. else if(FX1Data==0) FX1=0;
  969. break;
  970. case 0xE://Extended effects
  971. switch(FX1Data>>4) {
  972. //Effects to leave as-is-
  973. //1 Fineslide Up
  974. //2 Fineslide Down
  975. //3 Glissando Control
  976. //4 Vibrato Waveform
  977. //5 Set C-4 finetune
  978. //6 Patttern Loop
  979. //7 Tremolo Waveform
  980. //A Fine Volume up
  981. //B Fine Volume down
  982. //C Note Cut
  983. //E Pattern Delay
  984. //F Invert Loop
  985. case 0://0 Set filter- remove
  986. FX1=0;
  987. FX1Data=0;
  988. break;
  989. case 8://Pan Position
  990. FX1=0x1E;
  991. break;
  992. case 9://Retrigger
  993. FX1=0x12;
  994. FX1Data&=0xF;
  995. if(FX1Data==0) FX1=0;
  996. break;
  997. case 0xD://Note Delay
  998. if(GDMNote) GDMNote=((GDMNote-1)|128)+1;
  999. else FX1=FX1Data=0;
  1000. break;
  1001. }
  1002. break;
  1003. }
  1004. if((GDMNote)||(GDMIns)||(FX1)) {
  1005. Chan=Channel;
  1006. if(Channel>=MaxChan) MaxChan=Channel+1;
  1007. EvPos=1;
  1008. if((GDMNote)||(GDMIns)) {
  1009. Chan|=32;
  1010. Events[EvPos++]=GDMNote;
  1011. Events[EvPos++]=GDMIns;
  1012. }
  1013. if(FX1) {
  1014. Chan|=64;
  1015. Events[EvPos++]=FX1;
  1016. Events[EvPos++]=FX1Data;
  1017. }
  1018. Events[0]=Chan;
  1019. mem_cpy(&patdata[patpos],Events,EvPos);
  1020. patpos+=EvPos;
  1021. }
  1022. }//Next channel
  1023. patdata[patpos++]=0;
  1024. }//Next row
  1025. patdata[0]=patpos&255;
  1026. patdata[1]=patpos>>8;
  1027. write(destfile,patdata,patpos);
  1028. }//Next pattern
  1029. for(tmp=MaxChan;tmp<32;tmp++)
  1030. GDMHead.PanMap[tmp]=0xFF;
  1031. //Sample conversion
  1032. GDMHead.SamOffset=tell(destfile);
  1033. //Allocate for sample copy
  1034. buff=(byte far *)farmalloc(chunk);
  1035. if(buff==NULL) {
  1036. chunk=farcoreleft()-64;
  1037. if(chunk>=2625) buff=(byte far *)farmalloc(chunk);
  1038. if((buff==NULL)||(chunk<=2624)) {
  1039. buff=patdata;
  1040. chunk=2624;
  1041. }
  1042. }
  1043. for(tmp=0;tmp<=GDMHead.NOS;tmp++) {
  1044. //Convert sample #tmp
  1045. if((len=SamHead2[tmp].Length)!=0) {
  1046. //Copy buffer by buffer
  1047. do {
  1048. if(len<chunk) chunk2=len;
  1049. else chunk2=chunk;
  1050. read(file,buff,chunk2);
  1051. mem_xor(buff,chunk2,128);
  1052. write(destfile,buff,chunk2);
  1053. } while((len-=chunk2)>0);
  1054. }
  1055. }//Next sample
  1056. lseek(destfile,0,SEEK_SET);
  1057. write(destfile,&GDMHead,sizeof(GDMHead));
  1058. //Done!
  1059. if(chunk>2624) farfree(buff);
  1060. close(file);
  1061. return destfile;
  1062. }
  1063. void fix_global_volumes(void) {
  1064. //Call this when music_gvol and/or sound_gvol changes
  1065. //This resets all the volumes properly
  1066. MusicVolume((volume*music_gvol)>>5);
  1067. }