Example #1
0
        public bool Save(Project originalProject, string filename, int[] songIds)
        {
            var project = originalProject.DeepClone();

            project.RemoveAllSongsBut(songIds);

            var lines = new List <string>();

            var versionString = Application.ProductVersion.Substring(0, Application.ProductVersion.LastIndexOf('.'));
            var projectLine   = $"Project Version=\"{versionString}\" TempoMode=\"{Project.TempoModeNames[project.TempoMode]}\"";

            if (project.Name != "")
            {
                projectLine += $" Name=\"{project.Name}\"";
            }
            if (project.Author != "")
            {
                projectLine += $" Author=\"{project.Author}\"";
            }
            if (project.Copyright != "")
            {
                projectLine += $" Copyright=\"{project.Copyright}\"";
            }
            if (project.UsesExpansionAudio)
            {
                projectLine += $" Expansion=\"{Project.ExpansionShortNames[project.ExpansionAudio]}\"";
            }
            if (project.PalMode)
            {
                projectLine += $" PAL=\"{true}\"";
            }

            lines.Add(projectLine);

            // DPCM samples
            foreach (var sample in project.Samples)
            {
                lines.Add($"\tDPCMSample Name=\"{sample.Name}\" Data=\"{String.Join("", sample.Data.Select(x => $"{x:x2}"))}\"");
            }

            // DPCM mappings
            for (int i = 0; i < project.SamplesMapping.Length; i++)
            {
                var mapping = project.SamplesMapping[i];

                if (mapping != null && mapping.Sample != null)
                {
                    lines.Add($"\tDPCMMapping Note=\"{Note.GetFriendlyName(i + Note.DPCMNoteMin)}\" Sample=\"{mapping.Sample.Name}\" Pitch=\"{mapping.Pitch}\" Loop=\"{mapping.Loop}\"");
                }
            }

            // Instruments
            foreach (var instrument in project.Instruments)
            {
                var instrumentLine = $"\tInstrument Name=\"{instrument.Name}\"";
                if (instrument.IsExpansionInstrument)
                {
                    instrumentLine += $" Expansion=\"{Project.ExpansionShortNames[project.ExpansionAudio]}\"";

                    if (instrument.ExpansionType == Project.ExpansionFds)
                    {
                        instrumentLine += $" FdsWavePreset=\"{Envelope.PresetNames[instrument.FdsWavePreset]}\"";
                        instrumentLine += $" FdsModPreset=\"{Envelope.PresetNames[instrument.FdsModPreset]}\"";
                        if (instrument.FdsMasterVolume != 0)
                        {
                            instrumentLine += $" FdsMasterVolume=\"{instrument.FdsMasterVolume}\"";
                        }
                        if (instrument.FdsModSpeed != 0)
                        {
                            instrumentLine += $" FdsModSpeed=\"{instrument.FdsModSpeed}\"";
                        }
                        if (instrument.FdsModDepth != 0)
                        {
                            instrumentLine += $" FdsModDepth=\"{instrument.FdsModDepth}\"";
                        }
                        if (instrument.FdsModDelay != 0)
                        {
                            instrumentLine += $" FdsModDelay=\"{instrument.FdsModDelay}\"";
                        }
                    }
                    else if (instrument.ExpansionType == Project.ExpansionN163)
                    {
                        instrumentLine += $" N163WavePreset=\"{Envelope.PresetNames[instrument.N163WavePreset]}\"";
                        instrumentLine += $" N163WaveSize=\"{instrument.N163WaveSize}\"";
                        instrumentLine += $" N163WavePos=\"{instrument.N163WavePos}\"";
                    }
                    else if (instrument.ExpansionType == Project.ExpansionVrc7)
                    {
                        instrumentLine += $" Vrc7Patch=\"{instrument.Vrc7Patch}\"";

                        if (instrument.Vrc7Patch == 0)
                        {
                            for (int i = 0; i < 8; i++)
                            {
                                instrumentLine += $" Vrc7Reg{i}=\"{instrument.Vrc7PatchRegs[i]}\"";
                            }
                        }
                    }
                }
                lines.Add(instrumentLine);

                for (int i = 0; i < Envelope.Count; i++)
                {
                    var env = instrument.Envelopes[i];
                    if (env != null && !env.IsEmpty)
                    {
                        var envelopeLine = $"\t\tEnvelope Type=\"{Envelope.EnvelopeShortNames[i]}\" Length=\"{env.Length}\"";

                        if (env.Loop >= 0)
                        {
                            envelopeLine += $" Loop=\"{env.Loop}\"";
                        }
                        if (env.Release >= 0)
                        {
                            envelopeLine += $" Release=\"{env.Release}\"";
                        }
                        if (env.Relative)
                        {
                            envelopeLine += $" Relative=\"{env.Relative}\"";
                        }

                        envelopeLine += $" Values=\"{String.Join(",", env.Values.Take(env.Length))}\"";

                        lines.Add(envelopeLine);
                    }
                }
            }

            // Songs
            foreach (var song in project.Songs)
            {
                var songStr = $"\tSong Name=\"{song.Name}\" Length=\"{song.Length}\" LoopPoint=\"{song.LoopPoint}\"";

                if (song.UsesFamiTrackerTempo)
                {
                    songStr += $" PatternLength=\"{song.PatternLength}\" BarLength=\"{song.BarLength}\" FamiTrackerTempo=\"{song.FamitrackerTempo}\" FamiTrackerSpeed=\"{song.FamitrackerSpeed}\"";
                }
                else
                {
                    songStr += $" PatternLength=\"{song.PatternLength / song.NoteLength}\" BarLength=\"{song.BarLength / song.NoteLength}\" NoteLength=\"{song.NoteLength}\"";
                }

                lines.Add(songStr);

                for (int i = 0; i < song.Length; i++)
                {
                    if (song.PatternHasCustomSettings(i))
                    {
                        var patternLength = song.GetPatternLength(i);

                        if (song.UsesFamiTrackerTempo)
                        {
                            lines.Add($"\t\tPatternCustomSettings Time=\"{i}\" Length=\"{patternLength}\"");
                        }
                        else
                        {
                            var noteLength = song.GetPatternNoteLength(i);
                            var barLength  = song.GetPatternBarLength(i);

                            lines.Add($"\t\tPatternCustomSettings Time=\"{i}\" Length=\"{patternLength / noteLength}\" NoteLength=\"{noteLength}\" BarLength=\"{barLength / noteLength}\"");
                        }
                    }
                }

                foreach (var channel in song.Channels)
                {
                    lines.Add($"\t\tChannel Type=\"{Channel.ChannelExportNames[channel.Type]}\"");

                    foreach (var pattern in channel.Patterns)
                    {
                        lines.Add($"\t\t\tPattern Name=\"{pattern.Name}\"");

                        foreach (var kv in pattern.Notes)
                        {
                            var note = kv.Value;

                            if (!note.IsEmpty)
                            {
                                var noteLine = $"\t\t\t\tNote Time=\"{kv.Key}\"";

                                if (note.IsValid)
                                {
                                    noteLine += $" Value=\"{note.FriendlyName}\"";
                                    if (note.Instrument != null)
                                    {
                                        noteLine += $" Instrument=\"{note.Instrument.Name}\"";
                                    }
                                }
                                if (!note.HasAttack)
                                {
                                    noteLine += $" Attack=\"{false.ToString()}\"";
                                }
                                if (note.HasVolume)
                                {
                                    noteLine += $" Volume=\"{note.Volume}\"";
                                }
                                if (note.HasVibrato)
                                {
                                    noteLine += $" VibratoSpeed=\"{note.VibratoSpeed}\" VibratoDepth=\"{note.VibratoDepth}\"";
                                }
                                if (note.HasSpeed)
                                {
                                    noteLine += $" Speed=\"{note.Speed}\"";
                                }
                                if (note.HasFinePitch)
                                {
                                    noteLine += $" FinePitch=\"{note.FinePitch}\"";
                                }
                                if (note.HasFdsModSpeed)
                                {
                                    noteLine += $" FdsModSpeed=\"{note.FdsModSpeed}\"";
                                }
                                if (note.HasFdsModDepth)
                                {
                                    noteLine += $" FdsModDepth=\"{note.FdsModDepth}\"";
                                }
                                if (note.IsMusical && note.IsSlideNote)
                                {
                                    noteLine += $" SlideTarget=\"{Note.GetFriendlyName(note.SlideNoteTarget)}\"";
                                }

                                lines.Add(noteLine);
                            }
                        }
                    }

                    for (int p = 0; p < song.Length; p++)
                    {
                        var pattern = channel.PatternInstances[p];

                        if (pattern != null)
                        {
                            lines.Add($"\t\t\tPatternInstance Time=\"{p}\" Pattern=\"{pattern.Name}\"");
                        }
                    }
                }
            }

            File.WriteAllLines(filename, lines);

            return(true);
        }
Example #2
0
        public bool Save(Project originalProject, string filename, int[] songIds, bool deleteUnusedData)
        {
            var project = originalProject.DeepClone();

            project.DeleteAllSongsBut(songIds, deleteUnusedData);

            SetInvariantCulture();

            var lines = new List <string>();

            var versionString = Utils.SplitVersionNumber(PlatformUtils.ApplicationVersion, out _);
            var projectLine   = $"Project{GenerateAttribute("Version", versionString)}{GenerateAttribute("TempoMode", TempoType.Names[project.TempoMode])}";

            if (project.Name != "")
            {
                projectLine += GenerateAttribute("Name", project.Name);
            }
            if (project.Author != "")
            {
                projectLine += GenerateAttribute("Author", project.Author);
            }
            if (project.Copyright != "")
            {
                projectLine += GenerateAttribute("Copyright", project.Copyright);
            }
            if (project.PalMode)
            {
                projectLine += GenerateAttribute("PAL", true);
            }

            if (project.UsesAnyExpansionAudio)
            {
                var expansionStrings = new List <string>();

                for (int i = ExpansionType.Start; i <= ExpansionType.End; i++)
                {
                    if (project.UsesExpansionAudio(i))
                    {
                        expansionStrings.Add(ExpansionType.ShortNames[i]);
                    }
                }

                projectLine += GenerateAttribute("Expansions", string.Join(",", expansionStrings));

                if (project.UsesN163Expansion)
                {
                    projectLine += GenerateAttribute("NumN163Channels", project.ExpansionNumN163Channels);
                }
            }

            lines.Add(projectLine);

            // DPCM samples
            foreach (var sample in project.Samples)
            {
                // We don't include any DPCM sample source data or processing data. We simply write the final
                // processed data. Including giant WAV files or asking other importers to implement all the
                // processing options is unrealistic.
                if (sample.HasAnyProcessingOptions)
                {
                    if (sample.SourceDataIsWav)
                    {
                        Log.LogMessage(LogSeverity.Warning, $"Sample {sample.Name} has WAV data as source. Only the final processed DMC data will be exported.");
                    }
                    else
                    {
                        Log.LogMessage(LogSeverity.Warning, $"Sample {sample.Name} has processing option(s) enabled. Only the final processed DMC data will be exported.");
                    }
                }

                sample.PermanentlyApplyAllProcessing();

                Debug.Assert(!sample.HasAnyProcessingOptions);

                lines.Add($"\tDPCMSample{GenerateAttribute("Name", sample.Name)}{GenerateAttribute("Data", String.Join("", sample.ProcessedData.Select(x => $"{x:x2}")))}");
            }

            // DPCM mappings
            for (int i = 0; i < project.SamplesMapping.Length; i++)
            {
                var mapping = project.SamplesMapping[i];

                if (mapping != null)
                {
                    lines.Add($"\tDPCMMapping{GenerateAttribute("Note", Note.GetFriendlyName(i + Note.DPCMNoteMin))}{GenerateAttribute("Sample", mapping.Sample.Name)}{GenerateAttribute("Pitch", mapping.Pitch)}{GenerateAttribute("Loop", mapping.Loop)}");
                }
            }

            // Instruments
            foreach (var instrument in project.Instruments)
            {
                var instrumentLine = $"\tInstrument{GenerateAttribute("Name", instrument.Name)}";
                if (instrument.IsExpansionInstrument)
                {
                    instrumentLine += GenerateAttribute("Expansion", ExpansionType.ShortNames[instrument.Expansion]);

                    if (instrument.IsFdsInstrument)
                    {
                        instrumentLine += GenerateAttribute("FdsWavePreset", WavePresetType.Names[instrument.FdsWavePreset]);
                        instrumentLine += GenerateAttribute("FdsModPreset", WavePresetType.Names[instrument.FdsModPreset]);
                        if (instrument.FdsMasterVolume != 0)
                        {
                            instrumentLine += GenerateAttribute("FdsMasterVolume", instrument.FdsMasterVolume);
                        }
                        if (instrument.FdsModSpeed != 0)
                        {
                            instrumentLine += GenerateAttribute("FdsModSpeed", instrument.FdsModSpeed);
                        }
                        if (instrument.FdsModDepth != 0)
                        {
                            instrumentLine += GenerateAttribute("FdsModDepth", instrument.FdsModDepth);
                        }
                        if (instrument.FdsModDelay != 0)
                        {
                            instrumentLine += GenerateAttribute("FdsModDelay", instrument.FdsModDelay);
                        }
                    }
                    else if (instrument.IsN163Instrument)
                    {
                        instrumentLine += GenerateAttribute("N163WavePreset", WavePresetType.Names[instrument.N163WavePreset]);
                        instrumentLine += GenerateAttribute("N163WaveSize", instrument.N163WaveSize);
                        instrumentLine += GenerateAttribute("N163WavePos", instrument.N163WavePos);
                    }
                    else if (instrument.IsVrc6Instrument)
                    {
                        instrumentLine += GenerateAttribute("Vrc6SawMasterVolume", Vrc6SawMasterVolumeType.Names[instrument.Vrc6SawMasterVolume]);
                    }
                    else if (instrument.IsVrc7Instrument)
                    {
                        instrumentLine += GenerateAttribute("Vrc7Patch", instrument.Vrc7Patch);

                        if (instrument.Vrc7Patch == Vrc7InstrumentPatch.Custom)
                        {
                            for (int i = 0; i < 8; i++)
                            {
                                instrumentLine += GenerateAttribute($"Vrc7Reg{i}", instrument.Vrc7PatchRegs[i]);
                            }
                        }
                    }
                }
                lines.Add(instrumentLine);

                for (int i = 0; i < EnvelopeType.Count; i++)
                {
                    var env = instrument.Envelopes[i];
                    if (env != null && !env.IsEmpty(i))
                    {
                        var envelopeLine = $"\t\tEnvelope{GenerateAttribute("Type", EnvelopeType.ShortNames[i])}{GenerateAttribute("Length", env.Length)}";

                        if (env.Loop >= 0)
                        {
                            envelopeLine += GenerateAttribute("Loop", env.Loop);
                        }
                        if (env.Release >= 0)
                        {
                            envelopeLine += GenerateAttribute("Release", env.Release);
                        }
                        if (env.Relative)
                        {
                            envelopeLine += GenerateAttribute("Relative", env.Relative);
                        }

                        envelopeLine += GenerateAttribute("Values", String.Join(",", env.Values.Take(env.Length)));

                        lines.Add(envelopeLine);
                    }
                }
            }

            // Arpeggios
            foreach (var arpeggio in project.Arpeggios)
            {
                var env          = arpeggio.Envelope;
                var arpeggioLine = $"\tArpeggio{GenerateAttribute("Name", arpeggio.Name)}{GenerateAttribute("Length", env.Length)}";
                if (env.Loop >= 0)
                {
                    arpeggioLine += GenerateAttribute("Loop", env.Loop);
                }
                arpeggioLine += GenerateAttribute("Values", String.Join(",", env.Values.Take(env.Length)));
                lines.Add(arpeggioLine);
            }

            // Songs
            foreach (var song in project.Songs)
            {
                var songStr = $"\tSong{GenerateAttribute("Name", song.Name)}{GenerateAttribute("Length", song.Length)}{GenerateAttribute("LoopPoint", song.LoopPoint)}";

                if (song.UsesFamiTrackerTempo)
                {
                    songStr += $"{GenerateAttribute("PatternLength", song.PatternLength)}{GenerateAttribute("BeatLength", song.BeatLength)}{GenerateAttribute("FamiTrackerTempo", song.FamitrackerTempo)}{GenerateAttribute("FamiTrackerSpeed", song.FamitrackerSpeed)}";
                }
                else
                {
                    songStr += $"{GenerateAttribute("PatternLength", song.PatternLength / song.NoteLength)}{GenerateAttribute("BeatLength", song.BeatLength / song.NoteLength)}{GenerateAttribute("NoteLength", song.NoteLength)}{GenerateAttribute("Groove", string.Join("-", song.Groove))}{GenerateAttribute("GroovePaddingMode", GroovePaddingType.Names[song.GroovePaddingMode])}";
                }

                lines.Add(songStr);

                for (int i = 0; i < song.Length; i++)
                {
                    if (song.PatternHasCustomSettings(i))
                    {
                        var patternLength = song.GetPatternLength(i);

                        if (song.UsesFamiTrackerTempo)
                        {
                            lines.Add($"\t\tPatternCustomSettings{GenerateAttribute("Time", i)}{GenerateAttribute("Length", patternLength)}");
                        }
                        else
                        {
                            var noteLength        = song.GetPatternNoteLength(i);
                            var beatLength        = song.GetPatternBeatLength(i);
                            var groove            = song.GetPatternGroove(i);
                            var groovePaddingMode = song.GetPatternGroovePaddingMode(i);

                            lines.Add($"\t\tPatternCustomSettings{GenerateAttribute("Time", i)}{GenerateAttribute("Length", patternLength / noteLength)}{GenerateAttribute("NoteLength", noteLength)}{GenerateAttribute("Groove", string.Join("-", groove))}{GenerateAttribute("GroovePaddingMode", GroovePaddingType.Names[groovePaddingMode])}{GenerateAttribute("BeatLength", beatLength / noteLength)}");
                        }
                    }
                }

                foreach (var channel in song.Channels)
                {
                    lines.Add($"\t\tChannel{GenerateAttribute("Type", ChannelType.ShortNames[channel.Type])}");

                    foreach (var pattern in channel.Patterns)
                    {
                        lines.Add($"\t\t\tPattern{GenerateAttribute("Name", pattern.Name)}");

                        foreach (var kv in pattern.Notes)
                        {
                            var note = kv.Value;

                            if (!note.IsEmpty)
                            {
                                var noteLine = $"\t\t\t\tNote{GenerateAttribute("Time", kv.Key)}";

                                if (note.IsMusicalOrStop)
                                {
                                    noteLine += GenerateAttribute("Value", note.FriendlyName);

                                    if (note.IsMusical)
                                    {
                                        noteLine += GenerateAttribute("Duration", note.Duration);

                                        if (note.HasRelease)
                                        {
                                            noteLine += GenerateAttribute("Release", note.Release);
                                        }
                                        if (note.Instrument != null)
                                        {
                                            noteLine += GenerateAttribute("Instrument", note.Instrument.Name);
                                        }
                                        if (note.IsArpeggio)
                                        {
                                            noteLine += GenerateAttribute("Arpeggio", note.Arpeggio.Name);
                                        }
                                        if (note.IsSlideNote)
                                        {
                                            noteLine += GenerateAttribute("SlideTarget", Note.GetFriendlyName(note.SlideNoteTarget));
                                        }
                                    }
                                }

                                if (!note.HasAttack)
                                {
                                    noteLine += GenerateAttribute("Attack", false);
                                }
                                if (note.HasVolume)
                                {
                                    noteLine += GenerateAttribute("Volume", note.Volume);
                                }
                                if (note.HasVolumeSlide)
                                {
                                    noteLine += GenerateAttribute("VolumeSlideTarget", note.VolumeSlideTarget);
                                }
                                if (note.HasVibrato)
                                {
                                    noteLine += $"{GenerateAttribute("VibratoSpeed", note.VibratoSpeed)}{GenerateAttribute("VibratoDepth", note.VibratoDepth)}";
                                }
                                if (note.HasSpeed)
                                {
                                    noteLine += GenerateAttribute("Speed", note.Speed);
                                }
                                if (note.HasFinePitch)
                                {
                                    noteLine += GenerateAttribute("FinePitch", note.FinePitch);
                                }
                                if (note.HasFdsModSpeed)
                                {
                                    noteLine += GenerateAttribute("FdsModSpeed", note.FdsModSpeed);
                                }
                                if (note.HasFdsModDepth)
                                {
                                    noteLine += GenerateAttribute("FdsModDepth", note.FdsModDepth);
                                }
                                if (note.HasDutyCycle)
                                {
                                    noteLine += GenerateAttribute("DutyCycle", note.DutyCycle);
                                }
                                if (note.HasNoteDelay)
                                {
                                    noteLine += GenerateAttribute("NoteDelay", note.NoteDelay);
                                }
                                if (note.HasCutDelay)
                                {
                                    noteLine += GenerateAttribute("CutDelay", note.CutDelay);
                                }

                                lines.Add(noteLine);
                            }
                        }
                    }

                    for (int p = 0; p < song.Length; p++)
                    {
                        var pattern = channel.PatternInstances[p];

                        if (pattern != null)
                        {
                            lines.Add($"\t\t\tPatternInstance{GenerateAttribute("Time", p)}{GenerateAttribute("Pattern", pattern.Name)}");
                        }
                    }
                }
            }

            File.WriteAllLines(filename, lines);

            ResetCulture();
            return(true);
        }
        private void ReadInstrument2A03(Instrument instrument, int instIdx, ref int idx)
        {
            ReadCommonEnvelopes(instrument, instIdx, ref idx, envelopes);

            for (int i = 0; i < OctaveRange; ++i)
            {
                for (int j = 0; j < 12; ++j)
                {
                    var index = bytes[idx++];
                    var pitch = bytes[idx++];

                    if (blockVersion > 5)
                    {
                        idx++; // sample delta
                    }
                    if (index > 0 && pitch != 0)
                    {
                        var sample = samples[index - 1];
                        var note   = i * 12 + j + 1;
                        if (sample != null && sample.ProcessedData != null)
                        {
                            if (project.NoteSupportsDPCM(note))
                            {
                                if (project.GetDPCMMapping(note) == null)
                                {
                                    project.MapDPCMSample(note, sample, pitch & 0x0f, (pitch & 0x80) != 0);
                                }
                                else
                                {
                                    Log.LogMessage(LogSeverity.Warning, $"Multiple instruments assigning DPCM samples to key {Note.GetFriendlyName(note)}. Only the first one will be assigned, others will be loaded, but unassigned.");
                                }
                            }
                            else
                            {
                                Log.LogMessage(LogSeverity.Warning, $"DPCM sample assigned to key {Note.GetFriendlyName(note)}. FamiStudio only supports DPCM samples on keys {Note.GetFriendlyName(Note.DPCMNoteMin + 1)} to {Note.GetFriendlyName(Note.DPCMNoteMax)}.");
                            }
                        }
                    }
                }
            }
        }