Beispiel #1
0
        public static S3MFile Parse(string path)
        {
            FileStream stream = new FileStream(path, FileMode.Open);
            using (BinaryReader reader = new BinaryReader(stream))
            {
                S3MFile file = new S3MFile();
                file.Name = ReadFileName(reader);
                CheckStreamPosition(stream, 28);
                // skip one byte (it's always 1A)
                stream.ReadByte();
                file.Type = reader.ReadBytesAsInt(1);
                CheckStreamPosition(stream, 30);
                // skip to next row
                stream.Seek(2, SeekOrigin.Current);
                CheckStreamPosition(stream, 0x20);
                //file.OrderCount = ReadByteAsInt(reader);
                file.OrderCount = reader.ReadInt16();
                file.InstrumentCount = reader.ReadInt16();
                file.PatternCount = reader.ReadInt16();
                // skip flags
                reader.ReadInt16();
                // skip version info
                reader.ReadInt16();
                // skip file format info
                reader.ReadInt16();
                ReadSCRM(reader);
                CheckStreamPosition(stream, 0x30);
                file.GlobalVolume = reader.ReadBytesAsInt(1);
                file.InitialSpeed = reader.ReadBytesAsInt(1);
                file.InitialTempo = reader.ReadBytesAsInt(1);
                file.MasterVolume = reader.ReadBytesAsInt(1);
                file.UltraClickRemoval = reader.ReadBytesAsInt(1);
                file.LoadChannelPanSettings = reader.ReadBytesAsInt(1);
                stream.Seek(0x40, SeekOrigin.Begin);
                file.ChannelSettings = ReadByteArrayAsIntArray(32, reader);
                file.Orders = ReadByteArrayAsIntArray(file.OrderCount, reader);
                file.InstrumentPointers = ReadParapointers(file.InstrumentCount, reader);
                file.PatternPointers = ReadParapointers(file.PatternCount, reader);

                file.Patterns.AddRange(ReadPatterns(file.PatternPointers, stream, reader));

                return file;
            }
        }
Beispiel #2
0
        public static List<List<Event>> Generate(S3MFile file)
        {
            Dictionary<int, Channel> channels = new Dictionary<int, Channel>();

            int speed = file.InitialSpeed;
            int tick = 0;
            int rowSkip = 0;

            Channel firstChannel = GetChannel(channels, 1);
            TempoEvent tempoEvent = new TempoEvent(tick, file.InitialTempo);
            firstChannel.AddNoteEvent(tempoEvent);

            TimeSignatureEvent currentTimeSignatureEvent = new TimeSignatureEvent(tick, 4, 4);
            firstChannel.AddNoteEvent(currentTimeSignatureEvent);

            foreach (var order in file.Orders)
            {
                if (order == 255)
                {
                    break;
                }

                var pattern = file.Patterns[order];
                int patternStartTick = tick;
                int rowIndex = rowSkip;
                for (; rowIndex < pattern.Rows.Count; rowIndex++)
                {
                    rowSkip = 0;
                    bool breakPatternToRow = false;
                    Row row = pattern.Rows[rowIndex];

                    foreach (var channelEvent in row.ChannelEvents)
                    {
                        Channel channel = GetChannel(channels, channelEvent.ChannelNumber);

                        bool needNoteOff = channel.IsPlayingNote && channelEvent.NoteAction != NoteAction.None;

                        if (needNoteOff)
                        {
                            channel.AddNoteEvent(GenerateNoteOffEvent(channel, tick));
                        }

                        if (channelEvent.NoteAction == NoteAction.Start)
                        {
                            var delay = 0;

                            if (pattern.PatternNumber == 8 && channelEvent.Command != CommandType.None)
                            {
                                Console.WriteLine("Pattern {0} Row {1} Channel {2} {3}", pattern.PatternNumber, row.RowNumber, channelEvent.ChannelNumber, channelEvent.Command);
                            }

                            if (channelEvent.Command == CommandType.Notedelay)
                            {
                                if (208 <= channelEvent.Data && channelEvent.Data <= 214)  // HACK: 214 is a guess at the top range of SD commands
                                {
                                    delay = channelEvent.Data - 208;
                                    Debug.Assert(delay >= 0);
                                }
                            }
                            channel.AddNoteEvent(GenerateNoteOnEvent(channel, channelEvent, tick + delay));
                        }

                        if (channelEvent.Data != 0)
                        {
                            channel.Data = channelEvent.Data;
                        }

                        if (channelEvent.Command == CommandType.BreakPatternToRow)
                        {
                            breakPatternToRow = true;
                            rowSkip = channelEvent.Data;

                            break;
                        }
                        else if (channelEvent.Command == CommandType.SetSpeed)
                        {
                            speed = channelEvent.Data;
                        }
                    }

                    tick += speed;

                    if (breakPatternToRow)
                    {
                        // just finished last row in this pattern
                        // because we are jumping to a new patter
                        var modulo = (rowIndex + 1) % 32;
                        if (modulo != 0)
                        {
                            // sad to say, not sure why mod 8 but divide by 16 works
                            var m8 = (rowIndex + 1) % 8;
                            if (m8 == 0)
                            {
                                firstChannel.AddNoteEvent(new TimeSignatureEvent(patternStartTick, (rowIndex + 1) / 16, 4));
                                firstChannel.AddNoteEvent(new TimeSignatureEvent(tick, 4, 4));
                            }

                        }

                        // now go to next pattern
                        break;
                    }
                }
            }

            // finalize any leftover note on events
            foreach (var key in channels.Keys)
            {
                Channel channel = channels[key];
                if (channel.CurrentNote != null)
                {
                    channel.AddNoteEvent(GenerateNoteOffEvent(channel, tick));
                }
            }

            List<List<Event>> allEvents = new List<List<Event>>();
            foreach (var key in channels.Keys.OrderBy(i => i))
            {
                allEvents.Add(channels[key].NoteEvents);
            }
            return allEvents;
        }
Beispiel #3
0
        public static void SaveXml(S3MFile file, string path)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<score-partwise version=\"1.1\"><part-list/></score-partwise>");
            // add part for each instrument
            for (int instrumentIndex = 0; instrumentIndex < file.InstrumentCount; instrumentIndex++)
            {
                XmlElement part = doc.CreateElement("score-part");
                XmlElement partList = (XmlElement)doc.DocumentElement.SelectSingleNode("part-list");
                partList.AppendChild(part);
                part.SetAttribute("id", instrumentIndex.ToString());
                XmlElement partName = doc.CreateElement("part-name");
                partName.InnerText = String.Format("Part {0}", instrumentIndex);
                part.AppendChild(partName);
            }

            foreach (Pattern pattern in file.Patterns)
            {
                foreach (ChannelEvent evt in pattern.EventsByChannel)
                {
                    //Console.Out.WriteLine(evt);
                }
                break;
            }

            Pattern p1 = file.Patterns[0];
            var c = from evt in p1.EventsByChannel
                    where evt.ChannelNumber == 1 && evt.Instrument == 2 && evt.Volume > 20
                    select evt;
            XmlElement part1 = doc.CreateElement("part");
            part1.SetAttribute("id", "1");
            doc.DocumentElement.AppendChild(part1);
            XmlElement measure = doc.CreateElement("measure");
            part1.AppendChild(measure);
            measure.SetAttribute("number", "1");
            measure.SetAttribute("width", "800");
            measure.InnerXml = "      <attributes>        <divisions>32</divisions>        <key>          <fifths>0</fifths>          <mode>major</mode>        </key>        <time>          <beats>4</beats>          <beat-type>4</beat-type>        </time>        <clef>          <sign>G</sign>          <line>2</line>        </clef>        <staff-details print-object=\"no\"/>      </attributes>";
            XmlElement beam = null;
            XmlElement lastNote = null;
            XmlElement firstNote = null;
            foreach (var evt in c)
            {
                Console.Out.WriteLine(evt);
                XmlElement note = doc.CreateElement("note");
                measure.AppendChild(note);
                lastNote = note;
                if (firstNote == null)
                {
                    firstNote = note;
                }
                XmlElement pitch = doc.CreateElement("pitch");
                note.AppendChild(pitch);
                int step = evt.Note & 15;
                int octave = evt.Note >> 4;

                bool alter = Alter[step] != 0;

                pitch.InnerXml = String.Format("<step>{0}</step><alter>{2}</alter><octave>{1}</octave>", Notes[step], octave, Alter[step]);
                Console.Out.WriteLine(pitch.InnerXml);
                XmlElement duration = doc.CreateElement("duration");
                note.AppendChild(duration);
                duration.InnerText = "1";
                XmlElement type = doc.CreateElement("type");
                note.AppendChild(type);
                type.InnerText = "eighth";
                XmlElement stem = doc.CreateElement("stem");
                note.AppendChild(stem);
                stem.InnerText = "up";
                if (beam == null)
                {
                    beam = doc.CreateElement("beam");
                    beam.SetAttribute("number", "1");
                    beam.InnerText = "begin";
                    note.AppendChild(beam);
                }
                else
                {
                    beam = doc.CreateElement("beam");
                    beam.SetAttribute("number", "1");
                    beam.InnerText = "end";
                }

                //break;
            }
            if (lastNote != firstNote)
            {
                lastNote.AppendChild(beam);
            }

            //Console.Out.WriteLine(doc.OuterXml);

            doc.Save(path);
        }