private static bool ReadMusHeader(Stream Input, musheader Header) { Input.Read(Header.id, 0, 4); Header.scorelength = GetShort(Input); Header.scorestart = GetShort(Input); Header.primarychannels = GetShort(Input); Header.secondarychannels = GetShort(Input); Header.instrumentcount = GetShort(Input); //TODO: Convert to little endian? GetShort is prepared! return(true); }
public static bool Convert(Stream In, Stream Out) { Init(); // Header for the MUS file musheader Header = new musheader(); // Descriptor for the current MUS event byte eventdescriptor; // Channel number byte channel; // Current Event musevent Event; // Bunch of vars read from MUS lump byte key; byte controllernumber = 0; byte controllervalue = 0; // Flag for when the score end marker is hit. bool hitscoreend = false; // Temp working byte byte working; // Used in building up time delays uint timedelay; for (channel = 0; channel < NUM_CHANNELS; ++channel) { channel_map[channel] = -1; } // Grab the header if (!ReadMusHeader(In, Header)) { return(true); } // Check MUS header if (Header.id[0] != 'M' || Header.id[1] != 'U' || Header.id[2] != 'S' || Header.id[3] != 0x1A) { return(true); } In.Seek(Header.scorestart, SeekOrigin.Begin); // So, we can assume the MUS file is faintly legit. Let's start // writing MIDI data... Out.Write(midiheader, 0, midiheader.Length); tracksize = 0; // Now, process the MUS file: while (!hitscoreend) { // Handle a block of events: while (!hitscoreend) { // Fetch channel number and event code: eventdescriptor = (byte)In.ReadByte(); channel = GetMIDIChannel(eventdescriptor & 0x0F); Event = (musevent)(eventdescriptor & 0x70); switch (Event) { case musevent.mus_releasekey: key = (byte)In.ReadByte(); if (WriteReleaseKey(channel, key, Out)) { return(true); } break; case musevent.mus_presskey: key = (byte)In.ReadByte(); if (key > 0x7F) { channelvelocities[channel] = (byte)In.ReadByte(); channelvelocities[channel] &= 0x7F; } if (WritePressKey(channel, key, channelvelocities[channel], Out)) { return(true); } break; case musevent.mus_pitchwheel: key = (byte)In.ReadByte(); if (WritePitchWheel(channel, (short)(key * 64), Out)) { return(true); } break; case musevent.mus_systemevent: controllernumber = (byte)In.ReadByte(); if (controllernumber < 10 || controllernumber > 14) { return(true); } if (WriteChangeController_Valueless(channel, controller_map[controllernumber], Out)) { return(true); } break; case musevent.mus_changecontroller: controllernumber = (byte)In.ReadByte(); controllervalue = (byte)In.ReadByte(); if (controllernumber == 0) { if (WriteChangePatch(channel, controllervalue, Out)) { return(true); } } else { if (controllernumber < 1 || controllernumber > 9) { return(true); } if (WriteChangeController_Valued(channel, controller_map[controllernumber], controllervalue, Out)) { return(true); } } break; case musevent.mus_scoreend: hitscoreend = true; break; default: return(true); } if (eventdescriptor > 0x7F) { break; } } //INNER // Now we need to read the time code: if (!hitscoreend) { timedelay = 0; while (true) { working = (byte)In.ReadByte(); timedelay = timedelay * 128 + (uint)(working & 0x7F); if (working < 0x80) { break; } } queuedtime += timedelay; } } //OUTER // End of track if (WriteEndTrack(Out)) { return(true); } Out.Seek(18, SeekOrigin.Begin); Out.Write(new byte[] { (byte)((tracksize >> 24) & 0xFF), (byte)((tracksize >> 16) & 0xFF), (byte)((tracksize >> 8) & 0xFF), (byte)(tracksize & 0xFF) }, 0, 4); Out.Flush(); return(false); }