123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code 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.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "Precompiled.h"
- #include "globaldata.h"
- #include <assert.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include "idlib/sys/sys_defines.h"
- // mus header
- // reads a variable length integer
- unsigned long ReadVarLen( char* buffer ) {
- unsigned long value;
- byte c;
- if ((value = *buffer++) & 0x80) {
- value &= 0x7f;
- do {
- value = (value << 7) + ((c = *buffer++) & 0x7f);
- } while (c & 0x80);
- }
- return value;
- }
- // Writes a variable length integer to a buffer, and returns bytes written
- int WriteVarLen( long value, byte* out )
- {
- long buffer, count = 0;
- buffer = value & 0x7f;
- while ((value >>= 7) > 0) {
- buffer <<= 8;
- buffer += 0x80;
- buffer += (value & 0x7f);
- }
- while (1) {
- ++count;
- *out = (byte)buffer;
- ++out;
- if (buffer & 0x80)
- buffer >>= 8;
- else
- break;
- }
- return count;
- }
- // writes a byte, and returns the buffer
- unsigned char* WriteByte(void* buf, byte b)
- {
- unsigned char* buffer = (unsigned char*)buf;
- *buffer++ = b;
- return buffer;
- }
- unsigned char* WriteShort(void* b, unsigned short s)
- {
- unsigned char* buffer = (unsigned char*)b;
- *buffer++ = (s >> 8);
- *buffer++ = (s & 0x00FF);
- return buffer;
- }
- unsigned char* WriteInt(void* b, unsigned int i)
- {
- unsigned char* buffer = (unsigned char*)b;
- *buffer++ = (i & 0xff000000) >> 24;
- *buffer++ = (i & 0x00ff0000) >> 16;
- *buffer++ = (i & 0x0000ff00) >> 8;
- *buffer++ = (i & 0x000000ff);
- return buffer;
- }
- // Format - 0(1 track only), 1(1 or more tracks, each play same time), 2(1 or more, each play seperatly)
- void Midi_CreateHeader(MidiHeaderChunk_t* header, short format, short track_count, short division)
- {
- WriteInt(header->name, 'MThd');
- WriteInt(&header->length, 6);
- WriteShort(&header->format, format);
- WriteShort(&header->ntracks, track_count);
- WriteShort(&header->division, division);
- }
- unsigned char* Midi_WriteTempo(unsigned char* buffer, int tempo)
- {
- buffer = WriteByte(buffer, 0x00); // delta time
- buffer = WriteByte(buffer, 0xff); // sys command
- buffer = WriteShort(buffer, 0x5103); // command - set tempo
-
- buffer = WriteByte(buffer, tempo & 0x000000ff);
- buffer = WriteByte(buffer, (tempo & 0x0000ff00) >> 8);
- buffer = WriteByte(buffer, (tempo & 0x00ff0000) >> 16);
- return buffer;
- }
- int Midi_UpdateBytesWritten(int* bytes_written, int to_add, int max)
- {
- *bytes_written += to_add;
- if (max && *bytes_written > max)
- {
- assert(0);
- return 0;
- }
- return 1;
- }
- unsigned char MidiMap[] =
- {
- 0, // prog change
- 0, // bank sel
- 1, //2 // mod pot
- 0x07, //3 // volume
- 0x0A, //4 // pan pot
- 0x0B, //5 // expression pot
- 0x5B, //6 // reverb depth
- 0x5D, //7 // chorus depth
- 0x40, //8 // sustain pedal
- 0x43, //9 // soft pedal
- 0x78, //10 // all sounds off
- 0x7B, //11 // all notes off
- 0x7E, //12 // mono(use numchannels + 1)
- 0x7F, //13 // poly
- 0x79, //14 // reset all controllers
- };
- // The MUS data is stored in little-endian.
- namespace {
- unsigned short LittleToNative( const unsigned short value ) {
- return value;
- }
- }
- int Mus2Midi(unsigned char* bytes, unsigned char* out, int* len)
- {
- // mus header and instruments
- MUSheader_t header;
-
- // current position in read buffer
- unsigned char* cur = bytes,* end;
- // Midi header(format 0)
- MidiHeaderChunk_t midiHeader;
- // Midi track header, only 1 needed(format 0)
- MidiTrackChunk_t midiTrackHeader;
- // Stores the position of the midi track header(to change the size)
- byte* midiTrackHeaderOut;
-
- // Delta time for midi event
- int delta_time = 0;
- int temp;
- int channel_volume[MIDI_MAXCHANNELS] = {0};
- int bytes_written = 0;
- int channelMap[MIDI_MAXCHANNELS], currentChannel = 0;
- byte last_status = 0;
- // read the mus header
- memcpy(&header, cur, sizeof(header));
- cur += sizeof(header);
- header.scoreLen = LittleToNative( header.scoreLen );
- header.scoreStart = LittleToNative( header.scoreStart );
- header.channels = LittleToNative( header.channels );
- header.sec_channels = LittleToNative( header.sec_channels );
- header.instrCnt = LittleToNative( header.instrCnt );
- header.dummy = LittleToNative( header.dummy );
-
- // only 15 supported
- if (header.channels > MIDI_MAXCHANNELS - 1)
- return 0;
- // Map channel 15 to 9(percussions)
- for (temp = 0; temp < MIDI_MAXCHANNELS; ++temp) {
- channelMap[temp] = -1;
- channel_volume[temp] = 0x40;
- }
- channelMap[15] = 9;
- // Get current position, and end of position
- cur = bytes + header.scoreStart;
- end = cur + header.scoreLen;
- // Write out midi header
- Midi_CreateHeader(&midiHeader, 0, 1, 0x0059);
- Midi_UpdateBytesWritten(&bytes_written, MIDIHEADERSIZE, *len);
- memcpy(out, &midiHeader, MIDIHEADERSIZE); // cannot use sizeof(packs it to 16 bytes)
- out += MIDIHEADERSIZE;
-
- // Store this position, for later filling in the midiTrackHeader
- Midi_UpdateBytesWritten(&bytes_written, sizeof(midiTrackHeader), *len);
- midiTrackHeaderOut = out;
- out += sizeof(midiTrackHeader);
-
- // microseconds per quarter note(yikes)
- Midi_UpdateBytesWritten(&bytes_written, 7, *len);
- out = Midi_WriteTempo(out, 0x001aa309);
-
- // Percussions channel starts out at full volume
- Midi_UpdateBytesWritten(&bytes_written, 4, *len);
- out = WriteByte(out, 0x00);
- out = WriteByte(out, 0xB9);
- out = WriteByte(out, 0x07);
- out = WriteByte(out, 127);
-
- // Main Loop
- while (cur < end) {
- byte channel;
- byte event;
- byte temp_buffer[32]; // temp buffer for current iterator
- byte *out_local = temp_buffer;
- byte status, bit1, bit2, bitc = 2;
-
- // Read in current bit
- event = *cur++;
- channel = (event & 15); // current channel
-
- // Write variable length delta time
- out_local += WriteVarLen(delta_time, out_local);
-
- if (channelMap[channel] < 0) {
- // Set all channels to 127 volume
- out_local = WriteByte(out_local, 0xB0 + currentChannel);
- out_local = WriteByte(out_local, 0x07);
- out_local = WriteByte(out_local, 127);
- out_local = WriteByte(out_local, 0x00);
- channelMap[channel] = currentChannel++;
- if (currentChannel == 9)
- ++currentChannel;
- }
- status = channelMap[channel];
- // Handle ::g->events
- switch ((event & 122) >> 4)
- {
- default:
- assert(0);
- break;
- case MUSEVENT_KEYOFF:
- status |= 0x80;
- bit1 = *cur++;
- bit2 = 0x40;
- break;
- case MUSEVENT_KEYON:
- status |= 0x90;
- bit1 = *cur & 127;
- if (*cur++ & 128) // volume bit?
- channel_volume[channelMap[channel]] = *cur++;
- bit2 = channel_volume[channelMap[channel]];
- break;
- case MUSEVENT_PITCHWHEEL:
- status |= 0xE0;
- bit1 = (*cur & 1) >> 6;
- bit2 = (*cur++ >> 1) & 127;
- break;
- case MUSEVENT_CHANNELMODE:
- status |= 0xB0;
- assert(*cur < sizeof(MidiMap) / sizeof(MidiMap[0]));
- bit1 = MidiMap[*cur++];
- bit2 = (*cur++ == 12) ? header.channels + 1 : 0x00;
- break;
- case MUSEVENT_CONTROLLERCHANGE:
- if (*cur == 0) {
- cur++;
- status |= 0xC0;
- bit1 = *cur++;
- bitc = 1;
- } else {
- status |= 0xB0;
- assert(*cur < sizeof(MidiMap) / sizeof(MidiMap[0]));
- bit1 = MidiMap[*cur++];
- bit2 = *cur++;
- }
- break;
- case 5: // Unknown
- assert(0);
- break;
- case MUSEVENT_END: // End
- status = 0xff;
- bit1 = 0x2f;
- bit2 = 0x00;
- assert(cur == end);
- break;
- case 7: // Unknown
- assert(0);
- break;
- }
- // Write it out
- out_local = WriteByte(out_local, status);
- out_local = WriteByte(out_local, bit1);
- if (bitc == 2)
- out_local = WriteByte(out_local, bit2);
-
- // Write out temp stuff
- if (out_local != temp_buffer)
- {
- Midi_UpdateBytesWritten(&bytes_written, out_local - temp_buffer, *len);
- memcpy(out, temp_buffer, out_local - temp_buffer);
- out += out_local - temp_buffer;
- }
- if (event & 128) {
- delta_time = 0;
- do {
- delta_time = delta_time * 128 + (*cur & 127);
- } while ((*cur++ & 128));
- } else {
- delta_time = 0;
- }
- }
- // Write out track header
- WriteInt(midiTrackHeader.name, 'MTrk');
- WriteInt(&midiTrackHeader.length, out - midiTrackHeaderOut - sizeof(midiTrackHeader));
- memcpy(midiTrackHeaderOut, &midiTrackHeader, sizeof(midiTrackHeader));
-
- // Store length written
- *len = bytes_written;
- /*{
- FILE* file = f o pen("d:\\test.midi", "wb");
- fwrite(midiTrackHeaderOut - sizeof(MidiHeaderChunk_t), bytes_written, 1, file);
- fclose(file);
- }*/
- return 1;
- }
|