📄 qmus2mid.c
字号:
// Emacs style mode select -*- C++ -*-//-----------------------------------------------------------------------------//// $Id: qmus2mid.c,v 1.6 2001/03/09 21:53:56 metzgermeister Exp $//// Copyright (C) 1995 by Sebastien Bacquet.// Portions Copyright (C) 1998-2000 by DooM Legacy Team.//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License// as published by the Free Software Foundation; either version 2// of the License, or (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.////// $Log: qmus2mid.c,v $// Revision 1.6 2001/03/09 21:53:56 metzgermeister// *** empty log message ***//// Revision 1.5 2001/03/03 19:45:12 ydario// Do not compile under OS/2//// Revision 1.4 2000/10/08 13:30:01 bpereira// no message//// Revision 1.3 2000/09/10 10:46:15 metzgermeister// merged with SDL version//// Revision 1.2 2000/02/26 00:28:42 hurdler// Mostly bug fix (see borislog.txt 23-2-2000, 24-2-2000)////// DESCRIPTION:// convert Doom MUS data to a MIDI music data// used by both DOS/WIN32////-----------------------------------------------------------------------------#ifndef __OS2__#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include "doomdef.h"#include "i_system.h"#include "byteptr.h"#include "m_swap.h"#include "qmus2mid.h"// MUS events#define MUS_EV_SCOREEND 6ULONG TRACKBUFFERSIZE = 65536UL; /* 64 Ko */struct Track track[16];static unsigned char MUS2MIDcontrol[15] ={ 0, /* Program change - not a MIDI control change */ 0x00, /* Bank select */ 0x01, /* Modulation pot */ 0x07, /* Volume */ 0x0A, /* Pan pot */ 0x0B, /* Expression pot */ 0x5B, /* Reverb depth */ 0x5D, /* Chorus depth */ 0x40, /* Sustain pedal */ 0x43, /* Soft pedal */ 0x78, /* All sounds off */ 0x7B, /* All notes off */ 0x7E, /* Mono */ 0x7F, /* Poly */ 0x79 /* Reset all controllers */};static byte MUSchannel;static byte MIDItrack;#define fwritemem(p,s,n,f) memcpy(*f,p,n*s);*f+=(s*n)#define fwriteshort(x,f) WRITESHORT(*f,((x>>8) & 0xff) | (x<<8))#define fwritelong(x,f) WRITEULONG(*f,((x>>24) & 0xff) | ((x>>8) & 0xff00) | ((x<<8) & 0xff0000) | (x<<24))#define last(e) ((unsigned char)(e & 0x80))#define event_type(e) ((unsigned char)((e & 0x7F)>>4))#define channel(e) ((unsigned char)(e & 0x0F))static void FreeTracks ( void ){ int i; for (i = 0; i < 16; i++ ) if (track[i].data ) free( track[i].data );}static void TWriteByte (byte MIDItrack, char bbyte){ ULONG pos; pos = track[MIDItrack].current; if (pos < TRACKBUFFERSIZE ) track[MIDItrack].data[pos] = bbyte; else I_Error("Mus Convert Error : Track buffer full.\n"); track[MIDItrack].current++;}static void TWriteVarLen (byte tracknum, ULONG value){ ULONG buffer; buffer = value & 0x7f; while( (value >>= 7) ) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x7f); } while( 1 ) { TWriteByte( tracknum, (byte)buffer); if (buffer & 0x80 ) buffer >>= 8; else break; }}static int WriteMIDheader( USHORT ntrks, USHORT division, byte **file ){ fwritemem( MIDIMAGIC , 10, 1,file ); fwriteshort( ntrks, file); fwriteshort( division, file ); return 0;}static void WriteTrack (int tracknum, byte **file){ USHORT size; size_t quot, rem; /* Do we risk overflow here ? */ size = (USHORT)track[tracknum].current + 4; fwritemem( "MTrk", 4, 1, file ); if (!tracknum ) size += 33; fwritelong( size, file ); if (!tracknum) { memset(*file,'\0',33); *file+=33; } quot = (size_t) (track[tracknum].current / 4096); rem = (size_t) (track[tracknum].current - quot*4096); fwritemem (track[tracknum].data, 4096, quot, file ); fwritemem (((byte *) track[tracknum].data)+4096*quot, rem, 1, file ); fwritemem (TRACKMAGIC2, 4, 1, file );}static void WriteFirstTrack (byte **file){ USHORT size; size = 43; fwritemem( "MTrk", 4, 1, file ); fwritelong( size, file ); fwritemem( TRACKMAGIC3 , 4, 1, file ); memset(*file,'\0',22); *file+=22; fwritemem( TRACKMAGIC4, 6, 1, file ); fwritemem( TRACKMAGIC5, 7, 1, file ); fwritemem( TRACKMAGIC6, 4, 1, file );}static ULONG ReadTime( byte **file ){ ULONG time = 0; int bbyte; do { bbyte = *(*file)++; if (bbyte != EOF ) time = (time << 7) + (bbyte & 0x7F); } while( (bbyte != EOF) && (bbyte & 0x80) ); return time;}// return first MIDI channel available, except percussion channel 9static char FirstChannelAvailable (char MUS2MIDchannel[]){ int i; signed char max = -1; // note: skip channel 15 which is percussions for (i = 0; i < 15; i++ ) if (MUS2MIDchannel[i] > max ) max = MUS2MIDchannel[i]; // MIDI channel 9 is used for percussions return (max == 8 ? 10 : max+1);}static void MidiEvent(byte NewEvent){ if ((NewEvent != track[MIDItrack].LastEvent) /*|| nocomp*/ ) { TWriteByte( MIDItrack, NewEvent ); track[MIDItrack].LastEvent = NewEvent; }}int qmus2mid (byte *mus, byte *mid, // buffers in memory USHORT division, int BufferSize, int nocomp, int length, int midbuffersize, unsigned long* midilength) //faB: returns midi file length in here{ byte* file_mus; byte* file_mid; // pointer in memory static MUSheader* MUSh; byte MIDIchannel; byte et; USHORT TrackCnt=0; int i, event, data; ULONG DeltaTime; ULONG TotalTime=0; byte MIDIchan2track[16]; char MUS2MIDchannel[16]; char ouch = 0; file_mus = mus; file_mid = mid; //r = ReadMUSheader (&MUSh, file_mus); MUSh = (MUSheader *)mus; if (strncmp (MUSh->ID, MUSMAGIC, 4)) return NOTMUSFILE; //fseek( file_mus, MUSh.scoreStart, SEEK_SET ); file_mus = (char *)mus + MUSh->scoreStart; if (MUSh->channels > 15) /* <=> MUSchannels+drums > 16 */ return TOOMCHAN; for (i=0; i<16; i++) { MUS2MIDchannel[i] = -1; track[i].current = 0; track[i].vel = 64; track[i].DeltaTime = 0; track[i].LastEvent = 0; track[i].data = NULL; } if (BufferSize) TRACKBUFFERSIZE = ((ULONG) BufferSize) << 10; event = *(file_mus++); et = event_type (event); MUSchannel = channel (event); while ( (et != MUS_EV_SCOREEND) && file_mus-mus < length && /*!feof( file_mus )*/ (event != EOF) ) { if (MUS2MIDchannel[MUSchannel] == -1) { MIDIchannel = MUS2MIDchannel[MUSchannel] = // if percussion use channel 9 (MUSchannel == 15 ? 9 : FirstChannelAvailable (MUS2MIDchannel) ); MIDItrack = MIDIchan2track[MIDIchannel] = (byte)TrackCnt++; if (!(track[MIDItrack].data = (char *) malloc(TRACKBUFFERSIZE) )) { FreeTracks(); return MEMALLOC; } } else { MIDIchannel = MUS2MIDchannel[MUSchannel]; MIDItrack = MIDIchan2track [MIDIchannel]; } TWriteVarLen( MIDItrack, track[MIDItrack].DeltaTime ); track[MIDItrack].DeltaTime = 0; switch (et) { case 0 : /* release note */ MidiEvent((byte)0x90 | MIDIchannel); data = *(file_mus++); TWriteByte( MIDItrack, (byte)(data & 0x7F)); TWriteByte( MIDItrack, 0 ); break; case 1 : MidiEvent((byte)0x90 | MIDIchannel); data = *(file_mus++); TWriteByte( MIDItrack, (byte)(data & 0x7F)); if (data & 0x80) track[MIDItrack].vel = (*file_mus++) & 0x7F; TWriteByte( MIDItrack, track[MIDItrack].vel ); break; case 2 : MidiEvent((byte)0xE0 | MIDIchannel); data = *(file_mus++); TWriteByte( MIDItrack, (data & 1) << 6 ); TWriteByte( MIDItrack, data >> 1 ); break; case 3 : MidiEvent((byte)0xB0 | MIDIchannel); data = *(file_mus++); TWriteByte( MIDItrack, MUS2MIDcontrol[data] ); if (data == 12 ) TWriteByte( MIDItrack, MUSh->channels+1 ); else TWriteByte( MIDItrack, 0 ); break; case 4 : data = *(file_mus++); if (data ) { MidiEvent((byte)0xB0 | MIDIchannel); TWriteByte( MIDItrack, MUS2MIDcontrol[data] ); } else /* program change */ MidiEvent((byte)0xC0 | MIDIchannel); data = *(file_mus++); TWriteByte( MIDItrack, data & 0x7F ); break; case 5 : case 7 : FreeTracks(); return MUSFILECOR; default : break; } if (last( event ) ) { DeltaTime = ReadTime( &file_mus ); TotalTime += DeltaTime; for (i = 0; i < (int) TrackCnt; i++ ) track[i].DeltaTime += DeltaTime; } event = *(file_mus++); if (event != EOF ) { et = event_type( event ); MUSchannel = channel( event ); } else ouch = 1; } if (!division) division = 89;#ifndef SDL for (i = 0; i < 16; i++) { if (track[i].current && track[i].data) { TWriteByte(i, (byte)0x00); // midi end of track code TWriteByte(i, (byte)0xFF); TWriteByte(i, (byte)0x2F); TWriteByte(i, (byte)0x00); } }#endif WriteMIDheader( TrackCnt+1, division, &file_mid ); WriteFirstTrack( &file_mid ); for (i = 0; i < (int) TrackCnt; i++ ) WriteTrack( i, &file_mid ); if (file_mid>mid+midbuffersize) return MIDTOLARGE; FreeTracks(); //faB: return lenght of Midi data *midilength = (file_mid - mid); return 0;}#endif // __OS2__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -