Example #1
0
        public ITFHeader ToITF()
        {
            ITFHeader result = new ITFHeader();

            result.BeatPerMinute = Header.DefaultBPM;
            result.TickPerRow    = Header.DefaultTempo;

            foreach (var pat in Patterns)
            {
                ITFPattern itfp         = new ITFPattern();
                bool       emptypattern = true;
                for (int row = 0; row < pat.NumberOfRows; row++)
                {
                    ITFRow itfr     = new ITFRow();
                    bool   emptyrow = true;
                    for (int channel = 0; channel < Header.NumberOfChannels; channel++)
                    {
                        XMNote  xmnote = pat.PatArr[row, channel];
                        ITFNote itfn   = null;

                        if (xmnote != null)
                        {
                            emptyrow     = false;
                            emptypattern = false;
                            itfn         = new ITFNote();
                            if (xmnote.Instrument != 0)
                            {
                                itfn.Instrument = xmnote.Instrument;
                            }
                            if (xmnote.Note != 0)
                            {
                                itfn.Note = xmnote.Note;
                            }
                            itfn.Volume      = xmnote.Volume;
                            itfn.NoteOff     = xmnote.noteoff;
                            itfn.Effect      = xmnote.Effect;
                            itfn.EffectParam = xmnote.EffectParam;
                        }
                        itfr.Channels.Add(itfn);
                    }
                    if (emptyrow)
                    {
                        itfr = null;
                    }
                    itfp.Rows.Add(itfr);
                }
                if (emptypattern)
                {
                    itfp = null;
                }
                result.Patterns.Add(itfp);
            }

            foreach (byte item in Header.PatternOrderTable)
            {
                result.PlayOrder.Add(result.Patterns[item]);
            }

            return(result);
        }
Example #2
0
 public static int ym2151octave(this ITFNote itfnote)
 {
     if (itfnote.actualnote == 0)
     {
         return(Math.Max(itfnote.octave.Value - 1, 0));
     }
     return(itfnote.octave.Value);
 }
Example #3
0
        public static void NoteIntoBytes(this ITFNote cn, List <byte> bytes, int channel, Conversion conv, byte operatormask = 0b01111000)
        {
            if (channel > 7)
            {
                return;
            }
            byte register, value = 0;

            //Instrument setup for channel
            if (cn.Instrument != null)
            {
                if (conv.CYMS.LastInstrumentPerChannel[channel] != cn.Instrument)
                {
                    ResetChannel(bytes, channel, conv.CYMS);
                    YM2151Instrument ci = conv.DefinedInstruments[cn.Instrument.Value];
                    var cbs             = ci.ToControlBytes(channel);
                    foreach (var item in cbs)
                    {
                        addtobytes(bytes, item.Key, item.Value, conv.CYMS);
                    }
                    conv.CYMS.LastInstrumentPerChannel[channel] = (byte)cn.Instrument.Value;
                }
            }

            //Volume control
            if (!cn.NoteOff && cn.Note != 0 && cn.Volume == 0)
            {
                cn.Volume = 64;
            }
            if (cn.Effect == 0xC)
            {
                cn.Volume = cn.EffectParam;
            }
            if (cn.Volume != 0)
            {
                if (conv.CYMS.LastInstrumentPerChannel[channel] != 0)
                {
                    YM2151Instrument ci = conv.DefinedInstruments[conv.CYMS.LastInstrumentPerChannel[channel]];
                    //Csak a hallható operátor hangerejét kéne módosítani. Elvileg.
                    //De most még nem.

                    Dictionary <byte, byte> tempd = new Dictionary <byte, byte>();
                    ci.SetVolumeToBytes(tempd, channel, (byte)cn.Volume.Value);
                    foreach (var item in tempd)
                    {
                        addtobytes(bytes, item.Key, item.Value, conv.CYMS);
                    }
                }
            }

            if (cn.NoteOff || cn.Effect == 0x14)
            {
                //$08       -​S​S​S​S​C​C​C​    Key On(Play Sound)​ C = Channel S = Slot(C2 M2 C1 M1)​
                //Minden operátor kuss.
                register = (byte)(0x08);
                value    = 0b00000000;
                value   += (byte)(channel & 0b00000111);
                addtobytes(bytes, register, value, conv.CYMS);
            }
            else
            {
                if (cn.Note.HasValue)
                {
                    if (conv.Project.YM2151Instruments[(byte)cn.Instrument - 1].Detune.HasValue)
                    {
                        int newnote = cn.Note.Value + conv.Project.YM2151Instruments[(byte)cn.Instrument - 1].Detune.Value;
                        if (newnote <= 0)
                        {
                            throw new Exception("Detune error. Out of range downwards.");
                        }
                        cn.Note = (byte)(newnote);
                        if (cn.NoteOff)
                        {
                            throw new Exception("Detune error. Out of range upwards.");
                        }
                    }

                    //$28 -$2F -​O​O​O​N​N​N​N​     Chn0 - 7    KeyCode​  O = Octive, N = Note​
                    register = (byte)(0x28 + channel);
                    value    = 0;
                    value   += (byte)((cn.ym2151octave() & 0b00000111) << 4);
                    value   += (byte)(cn.ym2151note() & 0b00001111);
                    addtobytes(bytes, register, value, conv.CYMS);

                    //$08       -​S​S​S​S​C​C​C​    Key On(Play Sound)​ C = Channel S = Slot(C2 M2 C1 M1)​
                    //Most minden operátor szóljon.
                    register = (byte)(0x08);
                    value    = operatormask;
                    value   += (byte)(channel & 0b00000111);
                    addtobytes(bytes, register, value, conv.CYMS);
                }
            }
        }
Example #4
0
        public static List <byte> PatternToBytes(this ITFPattern itfpattern, Conversion conv, bool[] channelson = null, int?FromRow = null, int?ToRow = null)
        {
            int usedchannels = Math.Min(itfpattern.Rows.Max(x => x.Channels.Count), 8);

            if (channelson == null)
            {
                channelson = new bool[usedchannels];
                for (int i = 0; i < channelson.Length; i++)
                {
                    channelson[i] = true;
                }
            }

            List <byte> bytes = new List <byte>();
            byte        register, value = 0;

            for (int rows = 0; rows < itfpattern.Rows.Count; rows++)
            {
                if (FromRow.HasValue && FromRow.Value > rows)
                {
                    continue;
                }
                if (ToRow.HasValue && ToRow.Value < rows)
                {
                    continue;
                }

                //Is there any effects needs ticking here?
                bool tickingneeded = false;
                for (int channels = 0; channels < itfpattern.Rows[rows].Channels.Count; channels++)
                {
                    ITFNote cn = itfpattern.Rows[rows].Channels[channels];
                    //Tempo determination. This can come from all available channels.
                    if (cn.Effect == 0xF)
                    {
                        if (cn.EffectParam < 32)
                        {
                            conv.CurrentTickPerRow = cn.EffectParam.Value;
                        }
                        else
                        {
                            conv.CurrentBPM = cn.EffectParam.Value;
                        }
                    }

                    //Ticking will apply only for the phisycally converted channels.
                    if (channels > usedchannels)
                    {
                        continue;
                    }
                    int epu = ((byte)cn.EffectParam.Value >> 4) & 0xF;
                    int epd = (byte)cn.EffectParam.Value & 0xF;
                    tickingneeded =
                        tickingneeded ||
                        (cn.Effect == 0xE && epu == 0xD) ||
                        (cn.Effect == 0xE && epu == 0xC) ||
                        (cn.Effect == 0xA && cn.EffectParam != 0);
                }

                if (tickingneeded)
                {
                    ITFNote[,] tickarr = new ITFNote[conv.CurrentTickPerRow, usedchannels];

                    for (int channel = 0; channel < usedchannels; channel++)
                    {
                        if (!channelson[channel])
                        {
                            continue;
                        }

                        ITFNote cn  = itfpattern.Rows[rows].Channels[channel];
                        int     epu = ((byte)cn.EffectParam.Value >> 4) & 0xF;
                        int     epd = (byte)cn.EffectParam.Value & 0xF;

                        if (cn.Effect == 0xA && cn.EffectParam != 0) //Volume slide
                        {
                            tickarr[0, channel] = cn;
                            int volume = cn.Volume.Value;
                            int diff   = -epd;
                            if (epu != 0)
                            {
                                diff = epu;
                            }

                            for (int i = 1; i < conv.CurrentTickPerRow; i++)
                            {
                                volume += diff;
                                if (volume < 0)
                                {
                                    volume = 0;
                                }
                                if (volume > 64)
                                {
                                    volume = 64;
                                }
                                tickarr[i, channel] = new ITFNote()
                                {
                                    Volume = (byte)volume
                                };
                            }
                        }
                        else if (cn.Effect == 0xE && epu == 0xD)
                        {
                            if (epd > 5)
                            {
                                epd = 5;
                            }
                            tickarr[epd, channel] = cn;
                        }
                        else if (cn.Effect == 0xE && epu == 0xC) //Note cut
                        {
                            if (epd > 5)
                            {
                                epd = 5;
                            }
                            tickarr[0, channel]   = cn;
                            tickarr[epd, channel] = new ITFNote()
                            {
                                NoteOff = true
                            };
                        }
                        else
                        {
                            tickarr[0, channel] = cn;
                        }
                    }

                    for (int ticks = 0; ticks < conv.CurrentTickPerRow; ticks++)
                    {
                        for (int channel = 0; channel < usedchannels; channel++)
                        {
                            if (!channelson[channel])
                            {
                                continue;
                            }
                            ITFNote cn = tickarr[ticks, channel];
                            if (cn != null)
                            {
                                NoteIntoBytes(cn, bytes, channel, conv);
                            }
                        }
                        //Timing
                        register = 0;
                        value    = (byte)bpmtoplayertick(conv);
                        addtobytes(bytes, register, value, conv.CYMS);
                    }
                }
                else
                {
                    for (int channel = 0; channel < usedchannels; channel++)
                    {
                        if (!channelson[channel])
                        {
                            continue;
                        }
                        ITFNote cn = itfpattern.Rows[rows].Channels[channel];
                        NoteIntoBytes(cn, bytes, channel, conv);
                    }
                    //Timing
                    register = 0;
                    value    = (byte)bpmtoplayertickrow(conv);
                    addtobytes(bytes, register, value, conv.CYMS);
                }
            }
            return(bytes);
        }
Example #5
0
 public static int ym2151note(this ITFNote itfnote)
 {
     return(Normal2YMNote[itfnote.actualnote.Value]);
 }
Example #6
0
        public static void ToDMF(Conversion conv)
        {
            List <byte> outfile = new List <byte>();

            ////START OF DMF FORMAT
            ////FORMAT FLAGS
            //16 Bytes: Format String, must be ".DelekDefleMask."
            outfile.AddRange(Encoding.ASCII.GetBytes(".DelekDefleMask."));
            //1  Byte: File Version, must be 24(0x18) for DefleMask v0.12.0
            outfile.Add(0x18);

            ////SYSTEM SET
            //1  Byte:  System:
            //	SYSTEM_GENESIS 0x02(SYSTEM_TOTAL_CHANNELS 10)
            //	SYSTEM_GENESIS(EXT.CH3) 0x12(SYSTEM_TOTAL_CHANNELS 13)
            //	SYSTEM_SMS 0x03(SYSTEM_TOTAL_CHANNELS 4)
            //	SYSTEM_GAMEBOY 0x04(SYSTEM_TOTAL_CHANNELS 4)
            //	SYSTEM_PCENGINE 0x05(SYSTEM_TOTAL_CHANNELS 6)
            //	SYSTEM_NES 0x06(SYSTEM_TOTAL_CHANNELS 5)
            //	SYSTEM_C64(SID 8580) 0x07(SYSTEM_TOTAL_CHANNELS 3)
            //	SYSTEM_C64(SID 6581) 0x17(SYSTEM_TOTAL_CHANNELS 3)
            //	SYSTEM_YM2151 0x08(SYSTEM_TOTAL_CHANNELS 13)
            outfile.Add(0x08); //YM2151 for now.

            ////VISUAL INFORMATION
            //1 Byte:   Song Name Chars Count(0 - 255)
            outfile.Add((byte)conv.XM.Header.Modulename.Length);
            //N Bytes:  Song Name Chars
            outfile.AddRange(Encoding.ASCII.GetBytes(conv.XM.Header.Modulename));
            //1 Byte:	  Song Author Chars Count(0 - 255)
            outfile.Add(9);
            //N Bytes:  Song Author Chars
            outfile.AddRange(Encoding.ASCII.GetBytes("TrackConv"));
            //1 Byte:	  Highlight A in patterns
            outfile.Add(0x00);
            //1 Byte:   Highlight B in patterns
            outfile.Add(0x00);

            ////MODULE INFORMATION
            //1 Byte:	Time Base
            outfile.Add((byte)conv.CurrentBPM);
            //1 Byte:   Tick Time 1
            outfile.Add((byte)conv.CurrentRowPerBeat);
            //1 Byte:   Tick Time 2
            outfile.Add((byte)conv.CurrentTickPerRow);
            //1 Byte:   Frames Mode(0 = PAL, 1 = NTSC)
            outfile.Add(1); //Probably
            //1 Byte:   Using Custom HZ(If set to 1, NTSC or PAL is ignored)
            outfile.Add(1); //CX16 60 Hz
            //1 Byte:   Custom HZ value 1
            outfile.Add(60);
            //1 Byte:   Custom HZ value 2
            outfile.Add(0);
            //1 Byte:   Custom HZ value 3
            outfile.Add(0);
            //4 Bytes:  TOTAL_ROWS_PER_PATTERN
            int totalrowsperpattern = conv.ITF.Patterns.Max(x => x == null ? 0 : x.Rows.Count);

            outfile.AddRange(BitConverter.GetBytes(totalrowsperpattern));
            //1 Byte:   TOTAL_ROWS_IN_PATTERN_MATRIX
            outfile.Add((byte)conv.XM.Header.SongLengthInPatterns);

            //(Arpeggio Tick speed was here in previous version(1 Byte), it was REMOVED since ver 11.1)

            ////PATTERN MATRIX VALUES (A matrix of SYSTEM_TOTAL_CHANNELS x TOTAL_ROWS_IN_PATTERN_MATRIX)
            //Repeat this SYSTEM_TOTAL_CHANNELS times
            for (int i = 0; i < 13; i++)
            {
                //  Repeat this TOTAL_ROWS_IN_PATTERN_MATRIX times
                for (int j = 0; j < conv.XM.Header.SongLengthInPatterns; j++)
                {
                    //	  1 Byte: Pattern Matrix Value: (Index from SYSTEM_TOTAL_CHANNELS loop, Index from TOTAL_ROWS_IN_PATTERN_MATRIX loop)
                    outfile.Add(conv.XM.Header.PatternOrderTable[j]);
                }
            }

            ////INSTRUMENTS DATA (.DMP format is similar to this part, but there are some discrepancies, please read DMP_Specs.txt for more details)
            //	1 Byte: TOTAL_INSTRUMENTS
            outfile.Add((byte)conv.DefinedInstruments.Count);
            //Repeat this TOTAL_INSTRUMENTS times
            for (int i = 1; i <= conv.DefinedInstruments.Count; i++)
            {
                //	1 Byte: Instrument Name Chars Count(0 - 255)
                outfile.Add((byte)conv.DefinedInstruments[i].NAME.Length);
                //	N Bytes:  Instrument Name Chars
                outfile.AddRange(Encoding.ASCII.GetBytes(conv.DefinedInstruments[i].NAME));
                //	1 Byte: Instrument Mode(0 = STANDARD INS, 1 = FM INS)
                outfile.Add(1);
                //	//PER INSTRUMENT MODE DATA

                //		//IF INSTRUMENT MODE IS FM ( = 1)
                //			1 Byte: ALG
                outfile.Add(conv.DefinedInstruments[i].CON);
                //			1 Byte: FB
                outfile.Add(conv.DefinedInstruments[i].FB);
                //			1 Byte: LFO(FMS on YM2612, PMS on YM2151)
                outfile.Add(conv.DefinedInstruments[i].PMS);
                //			1 Byte: LFO2(AMS on YM2612, AMS on YM2151)
                outfile.Add(conv.DefinedInstruments[i].AMS);
                //			Repeat this TOTAL_OPERATORS times
                for (int o = 0; o < 4; o++)
                {
                    //				1 Byte: AM
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].AM);
                    //				1 Byte: AR
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].AR);
                    //				1 Byte: DR
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].D1R);
                    //				1 Byte: MULT
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].MULT);
                    //				1 Byte: RR
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].RR);
                    //				1 Byte: SL
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].KS);
                    //				1 Byte: TL
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].TL);
                    //				1 Byte: DT2
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].DT2);
                    //				1 Byte: RS
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].D1L);
                    //				1 Byte: DT
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].DT);
                    //				1 Byte: D2R
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].D2R);
                    //				1 Byte: SSGMODE(BIT 4 = 0 Disabled, 1 Enabled, BITS 0, 1, 2 SSG_MODE)
                    outfile.Add(conv.DefinedInstruments[i].OPS[o].SSGEG_Enabled);
                }
            }
            ////END OF INSTRUMENTS DATA
            ////WAVETABLES DATA
            //	1 Byte: TOTAL_WAVETABLES
            outfile.Add(0); //Nope
                            //Repeat this TOTAL_WAVETABLES times
                            //	4 Bytes: WAVETABLE_SIZE
                            //	Repeat this WAVETABLE_SIZE times
                            //		4 Bytes: Wavetable Data
            ////PATTERNS DATA

            //	Repeat this SYSTEM_TOTAL_CHANNELS times
            for (int i = 0; i < 13; i++)
            {
                //	1 Byte: CHANNEL_EFFECTS_COLUMNS_COUNT
                outfile.Add(1);
                //	Repeat this TOTAL_ROWS_IN_PATTERN_MATRIX times
                for (int j = 0; j < conv.ITF.PlayOrder.Count; j++)
                {
                    //		Repeat this TOTAL_ROWS_PER_PATTERN times
                    for (int k = 0; k < totalrowsperpattern; k++)
                    {
                        ITFNote note;
                        if (i >= conv.XM.Header.NumberOfChannels)
                        {
                            note = new ITFNote();
                        }
                        else
                        {
                            if (k >= conv.ITF.PlayOrder[j].Rows.Count)
                            {
                                continue;
                            }
                            note = conv.ITF.PlayOrder[j].Rows[k].Channels[i];
                        }
                        //			2 Bytes: Note for this index
                        outfile.AddRange(BitConverter.GetBytes((Int16)(note.actualnote.HasValue ? note.actualnote.Value : 0)));
                        //			2 Bytes: Octave for this index
                        outfile.AddRange(BitConverter.GetBytes((Int16)(note.octave.HasValue ? note.octave.Value : 0)));
                        //			//Note values:
                        //			//01 C#
                        //			//02 D-
                        //			//03 D#
                        //			//04 E-
                        //			//05 F-
                        //			//06 F#
                        //			//07 G-
                        //			//08 G#
                        //			//09 A-
                        //			//10 A#
                        //			//11 B-
                        //			//12 C-

                        //			//Special cases:
                        //			//Note = 0 and octave = 0 means empty.
                        //			//Note = 100 means NOTE OFF, no matter what is inside the octave value.

                        //			2 Bytes: Volume for this index(-1 = Empty)
                        outfile.AddRange(BitConverter.GetBytes((Int16)(note.Volume.HasValue ? note.Volume.Value : 0)));
                        //			Repeat this CHANNEL_EFFECTS_COLUMNS_COUNT times
                        //				2 Bytes: Effect Code for this index(-1 = Empty)
                        outfile.AddRange(BitConverter.GetBytes((Int16)(note.Effect.HasValue ? note.Effect.Value : 0)));
                        //				2 Bytes: Effect Value for this index(-1 = Empty)
                        outfile.AddRange(BitConverter.GetBytes((Int16)(note.EffectParam.HasValue ? note.EffectParam.Value : 0)));
                        //			2 Bytes: Instrument for this index(-1 = Empty)
                        outfile.AddRange(BitConverter.GetBytes((Int16)(note.Instrument.HasValue ? note.Instrument.Value : 0)));
                    }
                }
            }
            ////PCM SAMPLES DATA
            //1 Byte: TOTAL_SAMPLES
            outfile.Add(0); //Nope
                            //Repeat this TOTAL_SAMPLES times
                            //	4 Bytes: SAMPLE_SIZE
                            //	1 Byte:   Sample Name Chars Count(0 - 255)
                            //	N Bytes:  Sample Name Chars
                            //	1 Byte: Sample Rate
                            //	1 Byte: Sample Pitch
                            //	1 Byte: Sample Amp
                            //	1 Byte: Sample Bits(8 or 16)
                            //	Repeat this SAMPLE_SIZE times
                            //		2 Bytes: Actual Sample Data

            ////END OF DMF FORMAT
            ///

            //MemoryStream stream = new MemoryStream(outfile.ToArray());
            //using (FileStream compressedFileStream = File.Create("music.dmf"))
            //{
            //    using (DeflateStream compressionStream = new DeflateStream(compressedFileStream, CompressionMode.Compress))
            //    {
            //        stream.CopyTo(compressionStream);
            //    }
            //}

            var output2 = CreateToMemoryStream(outfile.ToArray());
            var arr2    = output2.ToArray();

            File.WriteAllBytes("music.dmf", arr2);
        }