fork download
  1. // Mucom88 -> Midi Converter
  2. // -------------------------
  3. // Written by Valley Bell, 09 March 2015
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <math.h>
  8. #include <memory.h>
  9. #ifndef __CST_STDTYPE_H__
  10. #define __CST_STDTYPE_H__
  11.  
  12. #ifdef HAVE_STDINT
  13.  
  14. #include <stdint.h>
  15.  
  16. typedef uint8_t UINT8;
  17. typedef int8_t INT8;
  18. typedef uint16_t UINT16;
  19. typedef int16_t INT16;
  20. typedef uint32_t UINT32;
  21. typedef int32_t INT32;
  22. typedef uint64_t UINT64;
  23. typedef int64_t INT64;
  24.  
  25. #else // ! HAVE_STDINT
  26.  
  27. // typedefs to use MAME's (U)INTxx types (copied from MAME\src\ods\odscomm.h)
  28. // 8-bit values
  29. typedef unsigned char UINT8;
  30. typedef signed char INT8;
  31.  
  32. // 16-bit values
  33. typedef unsigned short UINT16;
  34. typedef signed short INT16;
  35.  
  36. // 32-bit values
  37. #ifndef _WINDOWS_H
  38. typedef unsigned int UINT32;
  39. typedef signed int INT32;
  40.  
  41. // 64-bit values
  42. #ifdef _MSC_VER
  43. typedef unsigned __int64 UINT64;
  44. typedef signed __int64 INT64;
  45. #else
  46. __extension__ typedef unsigned long long UINT64;
  47. __extension__ typedef signed long long INT64;
  48. #endif
  49. #endif // _WINDOWS_H
  50.  
  51. #endif // HAVE_STDINT
  52.  
  53. #endif // __CST_STDTYPE_H__
  54.  
  55. #define INLINE static __inline
  56.  
  57. int main(int argc, char* argv[]);
  58. void ConvertMucom2MID(void);
  59. INLINE UINT8 MucomVol2Mid(UINT8 TrkMode, UINT8 Vol, UINT8 PanBoost);
  60. INLINE double FMVol2DB(UINT8 Vol);
  61. INLINE double PSGVol2DB(UINT8 Vol);
  62. INLINE double DeltaTVol2DB(UINT8 Vol);
  63. INLINE UINT8 DB2Mid(double DB);
  64. INLINE UINT32 Tempo2Mid(UINT8 TempoVal);
  65.  
  66. static void WriteEvent(UINT8* Buffer, UINT32* Pos, UINT32* Delay, UINT8 Evt, UINT8 Val1, UINT8 Val2);
  67. static void WriteMidiValue(UINT8* Buffer, UINT32* Pos, UINT32 Value);
  68. INLINE UINT16 ReadLE16(const UINT8* Data);
  69. INLINE void WriteBE16(UINT8* Buffer, UINT16 Value);
  70. INLINE void WriteBE32(UINT8* Buffer, UINT32 Value);
  71.  
  72.  
  73. #define USE_VELOCITY 1
  74. #define NO_NOTESTOP 0
  75.  
  76. static UINT32 SeqSize;
  77. static UINT8* SeqData;
  78. static UINT32 MidSize;
  79. static UINT8* MidData;
  80.  
  81. static UINT16 MIDI_RES;
  82. static UINT16 NUM_LOOPS;
  83.  
  84. int main(int argc, char* argv[])
  85. {
  86. FILE* hFile;
  87. //char FileName[0x10];
  88.  
  89. if (argc <= 2)
  90. {
  91. printf("Usage: mucom2mid input.bin output.mid\n");
  92. #ifdef _DEBUG
  93. _getch();
  94. #endif
  95. return 0;
  96. }
  97.  
  98. MIDI_RES = 24;
  99. //MIDI_RES = 0x20;
  100. NUM_LOOPS = 2;
  101.  
  102. hFile = fopen(argv[1], "rb");
  103. if (hFile == NULL)
  104. return 1;
  105.  
  106. fseek(hFile, 0, SEEK_END);
  107. SeqSize = ftell(hFile);
  108.  
  109. SeqData = (UINT8*)malloc(SeqSize);
  110. fseek(hFile, 0, SEEK_SET);
  111. fread(SeqData, 0x01, SeqSize, hFile);
  112.  
  113. fclose(hFile);
  114.  
  115. printf("Converting %s ...\n", argv[1]);
  116. MidSize = 0x20000;
  117. MidData = (UINT8*)malloc(MidSize);
  118. ConvertMucom2MID();
  119.  
  120. hFile = fopen(argv[2], "wb");
  121. if (hFile == NULL)
  122. {
  123. printf("Error saving %s!\n", argv[2]);
  124. }
  125. else
  126. {
  127. fwrite(MidData, 0x01, MidSize, hFile);
  128. fclose(hFile);
  129. }
  130. free(MidData);
  131. MidData = NULL;
  132. free(SeqData);
  133. SeqData = NULL;
  134.  
  135. printf("Done.\n");
  136.  
  137. #ifdef _DEBUG
  138. #endif
  139.  
  140. return 0;
  141. }
  142.  
  143. typedef struct _track_header
  144. {
  145. UINT16 StartOfs;
  146. UINT16 LoopOfs;
  147. } TRK_HDR;
  148. #define SEQ_BASEOFS 0x0005
  149.  
  150. void ConvertMucom2MID(void)
  151. {
  152. static const UINT8 NOTE_ARRAY[0x10] =
  153. // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
  154. // C C# D D# E -- F F# G G# A A# B -- -- --
  155. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,255,255,255,255};
  156. static const UINT8 RHYTHM_NOTES[0x06] =
  157. {0x24, 0x26, 0x33, 0x2A, 0x2D, 0x25};
  158. UINT8 Mucom88Win;
  159. UINT16 SeqSize;
  160. UINT16 TrkHdrPos;
  161. UINT16 FMInsPos;
  162. UINT16 SSGInsPos;
  163. TRK_HDR TrkHdrs[11];
  164. UINT16 SeqPos;
  165. UINT32 MidPos;
  166. UINT8 TrkCnt;
  167. UINT8 CurTrk;
  168. UINT32 MidTrkBase;
  169. UINT32 CurDly;
  170. UINT8 MidChn;
  171. UINT8 TrkEnd;
  172. UINT8 MstLoopCnt;
  173. UINT8 TrkMode; // 00 - FM, 01 - SSG
  174. INT8 NoteMove;
  175.  
  176. UINT8 CurCmd;
  177.  
  178. UINT8 CurNote;
  179. UINT8 CurNoteVol;
  180. UINT8 CurChnVol;
  181. UINT8 ChnPanOn;
  182. UINT8 LastNote;
  183. UINT8 HoldNote;
  184. UINT8 NoteStop;
  185. UINT8 CurRhythmMask;
  186. UINT8 CurRhythmOn;
  187.  
  188. UINT8 LoopIdx;
  189. UINT8 LoopStkIdx;
  190. UINT8 LoopCnt[0x10];
  191.  
  192. UINT8 TempByt;
  193. INT16 TempPos;
  194. UINT32 TempLng;
  195.  
  196. TrkHdrPos = 0x0000;
  197. if (!memcmp(SeqData, "MUB8", 4))
  198. {
  199. printf("Detected Mucom88win header.\n");
  200. Mucom88Win = 1;
  201. TrkHdrPos = ReadLE16(&SeqData[4]) + 5;
  202. }
  203. else
  204. {
  205. Mucom88Win = 0;
  206. for (SeqPos = 0x00; SeqPos < 0x08; SeqPos ++)
  207. {
  208. TempPos = ReadLE16(&SeqData[SeqPos + 0x01]);
  209. if (TempPos == 0x002F)
  210. {
  211. TrkHdrPos = SeqPos;
  212. break;
  213. }
  214. }
  215. }
  216. if (! TrkHdrPos)
  217. {
  218. printf("Unable to find sequence header!\n");
  219. return;
  220. }
  221. printf("Sequence header found at %04X.\n", TrkHdrPos);
  222.  
  223. TrkCnt = 11;
  224. SeqPos = 0x01;
  225. FMInsPos = ReadLE16(&SeqData[TrkHdrPos]);
  226. SSGInsPos = ReadLE16(&SeqData[TrkHdrPos+2]);
  227.  
  228. SeqPos = TrkHdrPos;
  229.  
  230. MidPos = 0x00;
  231. WriteBE32(&MidData[MidPos], 0x4D546864);
  232. MidPos += 0x04; // 'MThd' Signature
  233. WriteBE32(&MidData[MidPos], 0x00000006);
  234. MidPos += 0x04; // Header Size
  235. WriteBE16(&MidData[MidPos], 0x0001);
  236. MidPos += 0x02; // Format: 1
  237. WriteBE16(&MidData[MidPos], 1+TrkCnt);
  238. MidPos += 0x02; // Tracks (+1 for tempo)
  239. WriteBE16(&MidData[MidPos], MIDI_RES);
  240. MidPos += 0x02; // Ticks per Quarter
  241.  
  242. #if 1
  243. WriteBE32(&MidData[MidPos], 0x4D54726B);
  244. MidPos += 0x04; // 'MTrk' Signature
  245. WriteBE32(&MidData[MidPos], 0x00000000);
  246. MidPos += 0x04; // Track Size
  247. MidTrkBase = MidPos;
  248. CurDly = 0;
  249.  
  250. TempLng = Tempo2Mid(SeqData[SeqPos]); // default tempo value
  251. WriteEvent(MidData, &MidPos, &CurDly, 0xFF, 0x51, 0x03);
  252. WriteBE32(&MidData[MidPos - 0x01], TempLng);
  253. MidData[MidPos - 0x01] = 0x03; // write again, because the above instruction overwrote it
  254. MidPos += 0x03;
  255. SeqPos ++;
  256.  
  257. WriteEvent(MidData, &MidPos, &CurDly, 0xFF, 0x2F, 0x00);
  258. WriteBE32(&MidData[MidTrkBase - 0x04], MidPos - MidTrkBase); // write Track Length
  259. #endif
  260.  
  261. for (CurTrk = 0; CurTrk < TrkCnt; CurTrk ++, SeqPos += 0x04)
  262. {
  263. TrkHdrs[CurTrk].StartOfs = ReadLE16(&SeqData[SeqPos + 0x00]);
  264. if (TrkHdrs[CurTrk].StartOfs)
  265. TrkHdrs[CurTrk].StartOfs += TrkHdrPos;
  266. TrkHdrs[CurTrk].LoopOfs = ReadLE16(&SeqData[SeqPos + 0x02]);
  267. if (TrkHdrs[CurTrk].LoopOfs)
  268. TrkHdrs[CurTrk].LoopOfs += TrkHdrPos;
  269. }
  270. SeqSize = ReadLE16(&SeqData[SeqPos]) + TrkHdrPos;
  271. SeqPos += 0x02;
  272.  
  273. for (CurTrk = 0; CurTrk < TrkCnt; CurTrk ++)
  274. {
  275. WriteBE32(&MidData[MidPos], 0x4D54726B); // write 'MTrk'
  276. MidPos += 0x08;
  277. MidTrkBase = MidPos;
  278.  
  279. SeqPos = TrkHdrs[CurTrk].StartOfs;
  280. if (CurTrk < 3) // FM 1..3
  281. {
  282. TrkMode = 0;
  283. MidChn = CurTrk;
  284. }
  285. else if (CurTrk < 6) // SSG 1..3
  286. {
  287. TrkMode = 1;
  288. MidChn = 10 + CurTrk - 3;
  289. }
  290. else if (CurTrk == 6) // ADPCMA Rhythm
  291. {
  292. TrkMode = 3;
  293. MidChn = 9;
  294. }
  295. else if (CurTrk == 10) // ADPCMB/DeltaT
  296. {
  297. TrkMode = 2;
  298. MidChn = 9;
  299. }
  300. else
  301. {
  302. TrkMode = 0;
  303. MidChn = 3 + CurTrk - 7;
  304. }
  305. printf("Track %u ...\n", CurTrk);
  306.  
  307. CurDly = 0;
  308. TrkEnd = (SeqPos == 0x0000);
  309. MstLoopCnt = 0x00;
  310. NoteMove = TrkMode ? +12 : 0;
  311. //WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x65, 0x00); // RPN MSB: 0
  312. //WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x64, 0x00); // RPN LSB: 0
  313. //WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x06, 12); // Data MSB - set Pitch Bend Range
  314.  
  315. memset(LoopCnt, 0x00, 0x10);
  316. CurNote = 0xFF;
  317. LastNote = 0xFF;
  318. CurNoteVol = 0x7F;
  319. CurChnVol = 0x00;
  320. ChnPanOn = 0x00;
  321. HoldNote = 0x00;
  322. NoteStop = 0;
  323. CurRhythmMask = 0x00;
  324. CurRhythmOn = 0x00;
  325. LoopStkIdx = 0x00;
  326. LoopIdx = 0x00;
  327. while(! TrkEnd)
  328. {
  329. if (! MstLoopCnt && SeqPos == TrkHdrs[CurTrk].LoopOfs)
  330. {
  331. MstLoopCnt ++;
  332. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6F, 0x00);
  333. }
  334.  
  335. CurCmd = SeqData[SeqPos];
  336. SeqPos ++;
  337. if (CurCmd == 0x00)
  338. {
  339. if (TrkHdrs[CurTrk].LoopOfs)
  340. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6F, MstLoopCnt);
  341. if (TrkHdrs[CurTrk].LoopOfs && MstLoopCnt < NUM_LOOPS)
  342. {
  343. SeqPos = TrkHdrs[CurTrk].LoopOfs;
  344. MstLoopCnt ++;
  345. }
  346. else
  347. {
  348. TrkEnd = 0x01;
  349. }
  350. }
  351. else if (CurCmd < 0x80)
  352. {
  353. TempByt = SeqData[SeqPos];
  354. SeqPos ++;
  355. CurNote = NOTE_ARRAY[TempByt & 0x0F];
  356. if (CurNote == 0xFF)
  357. printf("Warning: Invalid Note %02X!\n", TempByt);
  358. CurNote += (TempByt >> 4) * 12;
  359. CurNote += NoteMove + 12;
  360.  
  361. if (TrkMode == 3)
  362. {
  363. if (! HoldNote)
  364. {
  365. for (TempByt = 0x00; TempByt < 0x06; TempByt ++)
  366. {
  367. if (CurRhythmOn & (1 << TempByt))
  368. {
  369. CurRhythmOn &= ~(1 << TempByt);
  370. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, RHYTHM_NOTES[TempByt], 0x00);
  371. }
  372. }
  373. for (TempByt = 0x00; TempByt < 0x06; TempByt ++)
  374. {
  375. if (CurRhythmMask & (1 << TempByt))
  376. {
  377. CurRhythmOn |= (1 << TempByt);
  378. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, RHYTHM_NOTES[TempByt], CurNoteVol);
  379. }
  380. }
  381. }
  382. }
  383. else if (LastNote != CurNote || ! HoldNote)
  384. {
  385. if (HoldNote)
  386. {
  387. if (CurDly >= 1)
  388. {
  389. CurDly --;
  390. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x41, 0x7F);
  391. CurDly ++;
  392. }
  393. else
  394. {
  395. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x41, 0x7F);
  396. }
  397. }
  398.  
  399. if (LastNote != 0xFF)
  400. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, LastNote, 0x00);
  401. if (CurNote != 0xFF)
  402. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, CurNote, CurNoteVol);
  403. LastNote = CurNote;
  404.  
  405. if (HoldNote)
  406. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x41, 0x00);
  407. }
  408. HoldNote = 0x00;
  409.  
  410. CurDly += CurCmd;
  411. if (NoteStop && CurDly > NoteStop && SeqData[SeqPos] != 0xFD)
  412. {
  413. CurDly -= NoteStop;
  414. if (TrkMode == 3)
  415. {
  416. for (TempByt = 0x00; TempByt < 0x06; TempByt ++)
  417. {
  418. if (CurRhythmOn & (1 << TempByt))
  419. {
  420. CurRhythmOn &= ~(1 << TempByt);
  421. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, RHYTHM_NOTES[TempByt], 0x00);
  422. }
  423. }
  424. }
  425. else if (LastNote != 0xFF)
  426. {
  427. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, LastNote, 0x00);
  428. LastNote = 0xFF;
  429. }
  430. CurDly += NoteStop;
  431. }
  432. }
  433. else if (CurCmd < 0xF0)
  434. {
  435. if (! HoldNote && LastNote != 0xFF)
  436. {
  437. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, LastNote, 0x00);
  438. LastNote = 0xFF;
  439. }
  440. HoldNote = 0x00;
  441.  
  442. CurDly += CurCmd & 0x7F;
  443. }
  444. else
  445. {
  446. switch(CurCmd)
  447. {
  448. case 0xF0: // Set Instrument
  449. if (TrkMode == 3 && Mucom88Win)
  450. {
  451. // set Rhythm Mask
  452. CurRhythmMask = SeqData[SeqPos];
  453. }
  454. else
  455. {
  456. TempByt = SeqData[SeqPos] & 0x7F;
  457. WriteEvent(MidData, &MidPos, &CurDly, 0xC0 | MidChn, TempByt, 0x00);
  458. }
  459. SeqPos ++;
  460. break;
  461. case 0xF1: // Set Volume
  462. CurChnVol = SeqData[SeqPos];
  463. TempByt = MucomVol2Mid(TrkMode, CurChnVol, ChnPanOn);
  464. if (! USE_VELOCITY)
  465. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x07, TempByt);
  466. else
  467. CurNoteVol = TempByt;
  468. SeqPos ++;
  469. if (TrkMode == 3)
  470. SeqPos += 0x06;
  471. break;
  472. case 0xF2: // Detune
  473. //WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6E, CurCmd & 0x0F);
  474. //WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x26, SeqData[SeqPos]);
  475. TempPos = ReadLE16(&SeqData[SeqPos]);
  476. TempPos = 0x2000 - (TempPos << 5);
  477. WriteEvent(MidData, &MidPos, &CurDly, 0xE0 | MidChn, TempPos & 0x7F, (TempPos >> 7) & 0x7F);
  478. SeqPos += 0x03;
  479. break;
  480. case 0xF3:
  481. if (TrkMode == 3)
  482. {
  483. // set Rhythm Mask
  484. CurRhythmMask = SeqData[SeqPos];
  485. }
  486. else
  487. {
  488. // Note Stop/Echo Volume?
  489. NoteStop = SeqData[SeqPos];
  490. //if (TrkMode == 0 && NoteStop >= 4)
  491. // NoteStop = 0;
  492. if (NO_NOTESTOP)
  493. NoteStop = 0;
  494. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x29, SeqData[SeqPos]);
  495. }
  496. SeqPos ++;
  497. break;
  498. case 0xF4: // Modulation
  499. if (! SeqData[SeqPos + 0x00])
  500. {
  501. // Set Modulation
  502. TempPos = ReadLE16(&SeqData[SeqPos + 0x03]);
  503. TempByt = SeqData[SeqPos + 0x05];
  504. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x10, SeqData[SeqPos + 0x01]);
  505. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x11, SeqData[SeqPos + 0x02]);
  506. if (! TrkMode)
  507. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x12, TempPos & 0x7F);
  508. else
  509. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x12, (TempPos/8) & 0x7F);
  510. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x13, TempByt & 0x7F);
  511.  
  512. if (TempPos < 0)
  513. TempPos = -TempPos;
  514. TempLng = (TempPos * TempPos) / 8;
  515.  
  516. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x01, TempLng);
  517. SeqPos += 0x06;
  518. }
  519. else
  520. {
  521. // Disable Modulation
  522. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x01, 0x00);
  523. SeqPos ++;
  524. }
  525. break;
  526. case 0xF5: // Loop Start
  527. TempPos = ReadLE16(&SeqData[SeqPos]); // get offset of Loop Count
  528. LoopStkIdx ++;
  529. if (SeqPos + TempPos < SeqSize)
  530. LoopCnt[LoopStkIdx] = SeqData[SeqPos + TempPos];
  531. else
  532. LoopCnt[LoopStkIdx] = 0x00;
  533. SeqPos += 0x02;
  534. break;
  535. case 0xF6: // Loop End
  536. TempByt = SeqData[SeqPos + 0x01];
  537. if (! LoopCnt[LoopStkIdx])
  538. LoopCnt[LoopStkIdx] = TempByt;
  539. SeqPos += 0x02;
  540.  
  541. TempPos = ReadLE16(&SeqData[SeqPos]);
  542. LoopCnt[LoopStkIdx] --;
  543. if (LoopCnt[LoopStkIdx])
  544. {
  545. SeqPos -= TempPos;
  546. }
  547. else
  548. {
  549. LoopStkIdx --;
  550. SeqPos += 0x02;
  551. }
  552. break;
  553. case 0xF7: // FM3 special mode
  554. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6E, CurCmd & 0x0F);
  555. SeqPos ++;
  556. break;
  557. case 0xF8:
  558. case 0xF9: // Pan
  559. if((Mucom88Win && CurCmd == 0xf8) || (!Mucom88Win && CurCmd == 0xf9))
  560. {
  561. TempByt = SeqData[SeqPos];
  562. if (TrkMode == 3) // rhythm mode works differently
  563. {
  564. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x26, TempByt);
  565. TempByt = 0x00;
  566. }
  567. TempByt &= 0x03;
  568. if (TempByt == 0x01) // right speaker
  569. TempByt = 0x7F;
  570. else if (TempByt == 0x02) // left speaker
  571. TempByt = 0x00;
  572. else // both speakers
  573. TempByt = 0x40;
  574. ChnPanOn = (TempByt == 0x40) ? 0x00 : 0x01;
  575.  
  576. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x0A, TempByt);
  577. TempByt = MucomVol2Mid(TrkMode, CurChnVol, ChnPanOn);
  578. if (! USE_VELOCITY)
  579. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x07, TempByt);
  580. else
  581. CurNoteVol = TempByt;
  582. SeqPos ++;
  583. break;
  584. }
  585. else
  586. {
  587. // seems to just write a communication byte
  588. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6E, CurCmd & 0x0F);
  589. SeqPos ++;
  590. break;
  591. }
  592. case 0xFA: // Register Write
  593. if (TrkMode == 1)
  594. {
  595. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6E, CurCmd & 0x0F);
  596. SeqPos += 0x06;
  597. }
  598. else // YM2203/2608 Register Write
  599. {
  600. if (SeqData[SeqPos + 0x00] == 0x26) // Timer B - change Tempo
  601. {
  602. TempLng = Tempo2Mid(SeqData[SeqPos + 0x01]);
  603. WriteEvent(MidData, &MidPos, &CurDly, 0xFF, 0x51, 0x03);
  604. WriteBE32(&MidData[MidPos - 0x01], TempLng);
  605. MidData[MidPos - 0x01] = 0x03; // write again, because the above instruction overwrote it
  606. MidPos += 0x03;
  607. }
  608. else
  609. {
  610. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 50, SeqData[SeqPos + 0x00]);
  611. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 51, SeqData[SeqPos + 0x01]);
  612. }
  613. SeqPos += 0x02;
  614. }
  615. break;
  616. case 0xFB: // Change Volume
  617. CurChnVol += SeqData[SeqPos];
  618. TempByt = MucomVol2Mid(TrkMode, CurChnVol, ChnPanOn);
  619. if (! USE_VELOCITY)
  620. {
  621. if (SeqData[SeqPos] != 0xFB)
  622. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x07, TempByt);
  623. }
  624. else
  625. CurNoteVol = TempByt;
  626. SeqPos ++;
  627. break;
  628. case 0xFC:
  629. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6E, CurCmd & 0x0F);
  630. //printf("Unknown command %02X at %04X!\n", CurCmd, SeqPos - 0x01);
  631. //getchar();
  632. SeqPos += 0x03;
  633. break;
  634. case 0xFD: // Hold
  635. HoldNote = 0x01;
  636. break;
  637. case 0xFE: // Loop Exit
  638. TempPos = ReadLE16(&SeqData[SeqPos]); // get offset of Loop Exit Counter
  639. TempByt = SeqData[SeqPos + TempPos];
  640. if (LoopCnt[LoopStkIdx] == 1)
  641. {
  642. LoopCnt[LoopStkIdx] = 0;
  643. LoopStkIdx --;
  644. SeqPos += TempPos + 0x04;
  645. }
  646. else
  647. {
  648. SeqPos += 0x02;
  649. }
  650. break;
  651. case 0xFF: // Master Loop Start??
  652. if(Mucom88Win)
  653. {
  654. TempByt = SeqData[SeqPos];
  655. SeqPos ++;
  656. switch(TempByt)
  657. {
  658. case 0xf0: // PCM volume mode ('vm')
  659. SeqPos++;
  660. break;
  661. case 0xf1: // PSG hardware support (mucom88 v1.5 / music lalf 1.0 only)
  662. case 0xf2:
  663. SeqPos++;
  664. break;
  665. case 0xf3: // Reverb enable
  666. case 0xf4: // Reverb mode
  667. case 0xf5: // Reverb switch
  668. SeqPos++;
  669. break;
  670. default:
  671. printf("unknown extra command %02x at %04x\n", TempByt, SeqPos);
  672. break;
  673. }
  674. WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x71, TempByt & 0x0F);
  675. }
  676. //WriteEvent(MidData, &MidPos, &CurDly, 0xB0 | MidChn, 0x6F, 0x00);
  677. //SeqPos += 0x02;
  678. break;
  679. }
  680. }
  681. }
  682. if (LastNote != 0xFF)
  683. WriteEvent(MidData, &MidPos, &CurDly, 0x90 | MidChn, LastNote, 0x00);
  684.  
  685. WriteEvent(MidData, &MidPos, &CurDly, 0xFF, 0x2F, 0x00);
  686. WriteBE32(&MidData[MidTrkBase - 0x04], MidPos - MidTrkBase); // write Track Length
  687. }
  688. MidSize = MidPos;
  689.  
  690. return;
  691. }
  692.  
  693. INLINE UINT8 MucomVol2Mid(UINT8 TrkMode, UINT8 Vol, UINT8 PanBoost)
  694. {
  695. double DBVol;
  696.  
  697. if (TrkMode == 0)
  698. DBVol = FMVol2DB(Vol);
  699. else if (TrkMode == 1)
  700. DBVol = PSGVol2DB(Vol);
  701. else if (TrkMode == 2)
  702. DBVol = DeltaTVol2DB(Vol);
  703. else if (TrkMode == 3)
  704. DBVol = DeltaTVol2DB(Vol * 4);
  705. else
  706. return Vol;
  707. if (PanBoost)
  708. DBVol -= 3.0;
  709. return DB2Mid(DBVol);
  710. }
  711.  
  712. INLINE double FMVol2DB(UINT8 Vol)
  713. {
  714. // Mucom uses a FM volume lookup table to map its volume value to 8/3 FM steps. (2 db steps)
  715. // The table contains 20 values and looks like this:
  716. // 36 33 30 2D 2A 28 25 22 20 1D 1A 18 15 12 10 0D 0A 08 05 02
  717. #if 0
  718. UINT8 FmVol;
  719.  
  720. if (Vol < 20)
  721. FmVol = (20 - Vol) * 8 / 3;
  722. else
  723. FmVol = 0;
  724. return FmVol * -0.75;
  725. #else
  726. if (Vol < 20)
  727. return (20 - Vol) * -2.0;
  728. else
  729. return 0;
  730. #endif
  731. }
  732.  
  733. INLINE double PSGVol2DB(UINT8 Vol)
  734. {
  735. if (Vol > 0x0F)
  736. return 0.0;
  737. else if (Vol > 0x00)
  738. return (0x0F - Vol) * -3.0; // AY8910 volume is 3 db per step
  739. else
  740. return -999;
  741. }
  742.  
  743. INLINE double DeltaTVol2DB(UINT8 Vol)
  744. {
  745. //return log(Vol / 255.0) / log(2.0) * 6.0;
  746. return log(Vol / 255.0) * 8.65617024533378 + 6.0; // boost its volume
  747. }
  748.  
  749. INLINE UINT8 DB2Mid(double DB)
  750. {
  751. DB += 6.0;
  752. if (DB > 0.0)
  753. DB = 0.0;
  754. return (UINT8)(pow(10.0, DB / 40.0) * 0x7F + 0.5);
  755. }
  756.  
  757. INLINE UINT32 Tempo2Mid(UINT8 TempoVal)
  758. {
  759. // Note: The tempo value is the value of YM Timer B.
  760. // higher value = higher tick frequency = higher tempo
  761.  
  762. // Base Clock = 2 MHz
  763. // Prescaler: 6 * 12
  764. // internal Timer Countdown: (100h - value) * 10h
  765. // Timer Frequency: Clock / (Countdown * Prescaler)
  766. double TicksPerSec;
  767. UINT16 TmrVal;
  768.  
  769. TmrVal = (0x100 - TempoVal) << 4;
  770. TicksPerSec = 2000000.0 / (6 * 12 * TmrVal);
  771. return (UINT32)(500000 * MIDI_RES / TicksPerSec + 0.5);
  772. }
  773.  
  774.  
  775.  
  776. static void WriteEvent(UINT8* Buffer, UINT32* Pos, UINT32* Delay, UINT8 Evt, UINT8 Val1, UINT8 Val2)
  777. {
  778. if (! (Evt & 0x80))
  779. return;
  780.  
  781. WriteMidiValue(Buffer, Pos, *Delay);
  782. *Delay = 0x00;
  783.  
  784. switch(Evt & 0xF0)
  785. {
  786. case 0x80:
  787. case 0x90:
  788. case 0xA0:
  789. case 0xB0:
  790. case 0xE0:
  791. MidData[*Pos + 0x00] = Evt;
  792. MidData[*Pos + 0x01] = Val1;
  793. MidData[*Pos + 0x02] = Val2;
  794. *Pos += 0x03;
  795. break;
  796. case 0xC0:
  797. case 0xD0:
  798. MidData[*Pos + 0x00] = Evt;
  799. MidData[*Pos + 0x01] = Val1;
  800. *Pos += 0x02;
  801. break;
  802. case 0xF0: // for Meta Event: Track End
  803. MidData[*Pos + 0x00] = Evt;
  804. MidData[*Pos + 0x01] = Val1;
  805. MidData[*Pos + 0x02] = Val2;
  806. *Pos += 0x03;
  807. break;
  808. default:
  809. break;
  810. }
  811.  
  812. return;
  813. }
  814.  
  815. static void WriteMidiValue(UINT8* Buffer, UINT32* Pos, UINT32 Value)
  816. {
  817. UINT8 ValSize;
  818. UINT8* ValData;
  819. UINT32 TempLng;
  820. UINT32 CurPos;
  821.  
  822. ValSize = 0x00;
  823. TempLng = Value;
  824. do
  825. {
  826. TempLng >>= 7;
  827. ValSize ++;
  828. } while(TempLng);
  829.  
  830. ValData = &Buffer[*Pos];
  831. CurPos = ValSize;
  832. TempLng = Value;
  833. do
  834. {
  835. CurPos --;
  836. ValData[CurPos] = 0x80 | (TempLng & 0x7F);
  837. TempLng >>= 7;
  838. } while(TempLng);
  839. ValData[ValSize - 1] &= 0x7F;
  840.  
  841. *Pos += ValSize;
  842.  
  843. return;
  844. }
  845.  
  846. INLINE UINT16 ReadLE16(const UINT8* Data)
  847. {
  848. return (Data[0x00] << 0) | (Data[0x01] << 8);
  849. }
  850.  
  851. INLINE void WriteBE16(UINT8* Buffer, UINT16 Value)
  852. {
  853. Buffer[0x00] = (Value & 0xFF00) >> 8;
  854. Buffer[0x01] = (Value & 0x00FF) >> 0;
  855.  
  856. return;
  857. }
  858.  
  859. INLINE void WriteBE32(UINT8* Buffer, UINT32 Value)
  860. {
  861. Buffer[0x00] = (Value & 0xFF000000) >> 24;
  862. Buffer[0x01] = (Value & 0x00FF0000) >> 16;
  863. Buffer[0x02] = (Value & 0x0000FF00) >> 8;
  864. Buffer[0x03] = (Value & 0x000000FF) >> 0;
  865.  
  866. return;
  867. }
Success #stdin #stdout 0s 5276KB
stdin
/*  Berechnung des Hamming-Abstandes zwischen zwei 128-Bit Werten in 	*/
/*	einer Textdatei. 													*/
/*  Die Werte müssen auf einer separaten Zeile gespeichert sein			*/
/* 																		*/
/*	Erstellt: 17.5.2010													*/
/*  Autor: Thomas Scheffler												*/

#include <stdio.h>
#include <stdlib.h>

#define ARRAY_SIZE 32

unsigned Hamdist(unsigned x, unsigned y)
{
  unsigned dist = 0, val = x ^ y;
 
  // Count the number of set bits
  while(val)
  {
    ++dist; 
    val &= val - 1;
  }
 
  return dist;
}



int main (void)
{
	char hex;
	int i;
	int a[ARRAY_SIZE];
	int b[ARRAY_SIZE];
	int hamDist = 0;
	FILE* fp;
	
	//Arrays mit 0 initialisieren
	for (i = 0; i < ARRAY_SIZE; ++i)
	{
  		a[i] = 0;
  		b[i] = 0;
	}

	
	fp = fopen("hex.txt","r");
	if (fp == NULL) 
	{
		printf("Die Datei hex.txt wurde nicht gefunden!");
		exit(EXIT_FAILURE);
	}

	i=0;
	printf("1.Zeile einlesen.\n");

 	while((hex=fgetc(fp))!='\n' && hex != EOF)
    {
        a[i]=strtol(&hex,0,16);
		i++;
    }
	i=0;
	printf("2.Zeile einlesen.\n");

 	while((hex=fgetc(fp))!='\n' && hex != EOF)
    {
    	b[i]=strtol(&hex,0,16);
        i++;
    }
	fclose(fp);

	printf("Hamming-Abweichung pro Nibble:\n");
	for (i = 0; i < ARRAY_SIZE; ++i)
	{
		printf ("%i\t%i\t%i\n",a[i],b[i],Hamdist(a[i],b[i]));
		hamDist += Hamdist(a[i],b[i]);
	}
	printf ("\nHamming-Abweichung der Hash-Werte:%d\n",hamDist);
}

stdout
Usage: mucom2mid input.bin output.mid