Пример #1
0
        private void OutputTempoEnvelopes()
        {
            if (project.UsesFamiStudioTempo && machine != MachineType.NTSC)
            {
                var uniqueNoteLengths = new HashSet <int>();

                foreach (var song in project.Songs)
                {
                    uniqueNoteLengths.Add(song.NoteLength);

                    for (int p = 0; p < song.Length; p++)
                    {
                        if (song.PatternHasCustomSettings(p))
                        {
                            uniqueNoteLengths.Add(song.GetPatternNoteLength(p));
                        }
                    }
                }

                foreach (var noteLength in uniqueNoteLengths)
                {
                    lines.Add($"{ll}tempo_env{noteLength}:");
                    lines.Add($"\t{db} {String.Join(",", FamiStudioTempoUtils.GetPalSkipEnvelope(noteLength).Select(i => $"${i:x2}"))}");
                }
            }
        }
Пример #2
0
        static unsafe void Main(string[] args)
        {
#if FAMISTUDIO_WINDOWS
            try
            {
                // This is only supported in Windows 8.1+.
                SetProcessDpiAwareness(1 /*Process_System_DPI_Aware*/);
            }
            catch { }
#endif

            Settings.Load();
            Cursors.Initialize();
            RenderTheme.Initialize();
            PlatformUtils.Initialize();
            ClipboardUtils.Initialize();
            FamiStudioTempoUtils.Initialize();
            NesApu.InitializeNoteTables();

#if FAMISTUDIO_WINDOWS
            PerformanceCounter.Initialize();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
#endif


            var famiStudio = new FamiStudio(args.Length > 0 ? args[0] : null);
            famiStudio.Run();

            Settings.Save();
        }
Пример #3
0
        public void AddProperties()
        {
            firstPropIdx = props.PropertyCount;

            if (song.UsesFamiTrackerTempo)
            {
                if (patternIdx < 0)
                {
                    famitrackerTempoPropIdx = props.AddNumericUpDown("Tempo :", song.FamitrackerTempo, 32, 255, TempoTooltip); // 0
                    famitrackerSpeedPropIdx = props.AddNumericUpDown("Speed :", song.FamitrackerSpeed, 1, 31, SpeedTooltip);   // 1
                }

                var notesPerBeat    = patternIdx < 0 ? song.BeatLength    : song.GetPatternBeatLength(patternIdx);
                var notesPerPattern = patternIdx < 0 ? song.PatternLength : song.GetPatternLength(patternIdx);
                var bpm             = Song.ComputeFamiTrackerBPM(song.Project.PalMode, song.FamitrackerSpeed, song.FamitrackerTempo, notesPerBeat);

                notesPerBeatPropIdx    = props.AddNumericUpDown("Notes per Beat :", notesPerBeat, 1, 256, NotesPerBeatTooltip);                        // 2
                notesPerPatternPropIdx = props.AddNumericUpDown("Notes per Pattern :", notesPerPattern, 1, Pattern.MaxLength, NotesPerPatternTooltip); // 3
                bpmLabelPropIdx        = props.AddLabel("BPM :", bpm.ToString("n1"), false, BPMTooltip);                                               // 4

                props.ShowWarnings = true;

                UpdateWarnings();
            }
            else
            {
                var noteLength      = (patternIdx < 0 ? song.NoteLength    : song.GetPatternNoteLength(patternIdx));
                var notesPerBeat    = (patternIdx < 0 ? song.BeatLength    : song.GetPatternBeatLength(patternIdx));
                var notesPerPattern = (patternIdx < 0 ? song.PatternLength : song.GetPatternLength(patternIdx));
                var groove          = (patternIdx < 0 ? song.Groove        : song.GetPatternGroove(patternIdx));

                tempoList = FamiStudioTempoUtils.GetAvailableTempos(song.Project.PalMode, notesPerBeat / noteLength);
                var tempoIndex = FamiStudioTempoUtils.FindTempoFromGroove(tempoList, groove);
                Debug.Assert(tempoIndex >= 0);
                tempoStrings = tempoList.Select(t => t.bpm.ToString("n1") + (t.groove.Length == 1 ? " *": "")).ToArray();

                var grooveList  = FamiStudioTempoUtils.GetAvailableGrooves(tempoList[tempoIndex].groove);
                var grooveIndex = Array.FindIndex(grooveList, g => Utils.CompareArrays(g, groove) == 0);
                Debug.Assert(grooveIndex >= 0);
                grooveStrings = grooveList.Select(g => string.Join("-", g)).ToArray();

                famistudioBpmPropIdx   = props.AddDropDownList("BPM : ", tempoStrings, tempoStrings[tempoIndex], BPMTooltip);                                                     // 0
                notesPerBeatPropIdx    = props.AddNumericUpDown("Notes per Beat : ", notesPerBeat / noteLength, 1, 256, NotesPerBeatTooltip);                                     // 1
                notesPerPatternPropIdx = props.AddNumericUpDown("Notes per Pattern : ", notesPerPattern / noteLength, 1, Pattern.MaxLength / noteLength, NotesPerPatternTooltip); // 2
                framesPerNotePropIdx   = props.AddLabel("Frames per Note :", noteLength.ToString(), false, FramesPerNoteTooltip);                                                 // 3

                props.ShowWarnings = true;
                props.BeginAdvancedProperties();
                groovePropIdx    = props.AddDropDownList("Groove : ", grooveStrings, grooveStrings[grooveIndex], GrooveTooltip);                                               // 4
                groovePadPropIdx = props.AddDropDownList("Groove Padding : ", GroovePaddingType.Names, GroovePaddingType.Names[song.GroovePaddingMode], GroovePaddingTooltip); // 5

                originalNoteLength   = noteLength;
                originalNotesPerBeat = notesPerBeat;

                UpdateWarnings();
            }
        }
Пример #4
0
        private void Props_PropertyChanged(PropertyPage props, int propIdx, int rowIdx, int colIdx, object value)
        {
            if (song.UsesFamiTrackerTempo)
            {
                var tempo = song.FamitrackerTempo;
                var speed = song.FamitrackerSpeed;

                if (propIdx == famitrackerTempoPropIdx ||
                    propIdx == famitrackerSpeedPropIdx)
                {
                    tempo = props.GetPropertyValue <int>(famitrackerTempoPropIdx);
                    speed = props.GetPropertyValue <int>(famitrackerSpeedPropIdx);
                }

                var beatLength = props.GetPropertyValue <int>(notesPerBeatPropIdx);

                props.SetLabelText(bpmLabelPropIdx, Song.ComputeFamiTrackerBPM(song.Project.PalMode, speed, tempo, beatLength).ToString("n1"));
            }
            else
            {
                var notesPerBeat = props.GetPropertyValue <int>(notesPerBeatPropIdx);

                // Changing the number of notes in a beat will affect the list of available BPMs.
                if (propIdx == notesPerBeatPropIdx)
                {
                    tempoList    = FamiStudioTempoUtils.GetAvailableTempos(song.Project.PalMode, notesPerBeat);
                    tempoStrings = tempoList.Select(t => t.bpm.ToString("n1") + (t.groove.Length == 1 ? " *" : "")).ToArray();
                    props.UpdateDropDownListItems(famistudioBpmPropIdx, tempoStrings);
                }

                // Changing the BPM affects the grooves and note length.
                if (propIdx == famistudioBpmPropIdx ||
                    propIdx == notesPerBeatPropIdx)
                {
                    var tempoIndex    = Array.IndexOf(tempoStrings, props.GetPropertyValue <string>(famistudioBpmPropIdx));
                    var tempoInfo     = tempoList[tempoIndex];
                    var framesPerNote = Utils.Min(tempoInfo.groove);

                    props.UpdateIntegerRange(notesPerPatternPropIdx, 1, Pattern.MaxLength / framesPerNote);

                    var grooveList = FamiStudioTempoUtils.GetAvailableGrooves(tempoInfo.groove);
                    grooveStrings = grooveList.Select(g => string.Join("-", g)).ToArray();

                    props.UpdateDropDownListItems(groovePropIdx, grooveStrings);
                    props.SetLabelText(framesPerNotePropIdx, framesPerNote.ToString());
                }
            }

            UpdateWarnings();
        }
Пример #5
0
        private void ResetFamiStudioTempo(bool force)
        {
            if (!famitrackerTempo)
            {
                var newNoteLength      = song.GetPatternNoteLength(playPattern);
                var newPalSkipEnvelope = FamiStudioTempoUtils.GetPalSkipEnvelope(newNoteLength);

                if (newPalSkipEnvelope != palSkipEnvelope || force)
                {
                    palSkipEnvelope        = newPalSkipEnvelope;
                    palSkipEnvelopeCounter = palSkipEnvelope[0];
                    palSkipEnvelopeIndex   = 0;
                }
            }
        }
Пример #6
0
        private void ResetFamiStudioTempo(bool force)
        {
            if (!famitrackerTempo)
            {
                var newNoteLength    = song.GetPatternNoteLength(playPattern);
                var newTempoEnvelope = FamiStudioTempoUtils.GetTempoEnvelope(newNoteLength, song.Project.PalMode);

                if (newTempoEnvelope != tempoEnvelope || force)
                {
                    tempoEnvelope        = newTempoEnvelope;
                    tempoEnvelopeCounter = tempoEnvelope[0];
                    tempoEnvelopeIndex   = 0;
                }
            }
        }
Пример #7
0
        private void ResetFamiStudioTempo()
        {
            if (!famitrackerTempo)
            {
                var newGroove        = song.GetPatternGroove(playLocation.PatternIndex);
                var newGroovePadMode = song.GetPatternGroovePaddingMode(playLocation.PatternIndex);

                FamiStudioTempoUtils.ValidateGroove(newGroove);

                grooveIterator = new GrooveIterator(newGroove, newGroovePadMode);

                tempoEnvelope        = FamiStudioTempoUtils.GetTempoEnvelope(newGroove, newGroovePadMode, song.Project.PalMode);
                tempoEnvelopeCounter = tempoEnvelope[0];
                tempoEnvelopeIndex   = 0;
            }
        }
Пример #8
0
        static unsafe void Main(string[] args)
        {
#if FAMISTUDIO_WINDOWS
            try
            {
                // This is only supported in Windows 8.1+.
                SetProcessDpiAwareness(1 /*Process_System_DPI_Aware*/);
            }
            catch { }
#endif

            Settings.Load();
            RenderTheme.Initialize();
            PlatformUtils.Initialize();
            Cursors.Initialize();
            FamiStudioTempoUtils.Initialize();
            NesApu.InitializeNoteTables();

#if FAMISTUDIO_WINDOWS
            WinUtils.Initialize();
            PerformanceCounter.Initialize();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
#endif
#if FAMISTUDIO_LINUX
            LinuxUtils.SetProcessName("FamiStudio");
#endif

            var cli = new CommandLineInterface(args);

            if (!cli.Run())
            {
                var famiStudio = new FamiStudio(args.Length > 0 ? args[0] : null);
                famiStudio.Run();
            }

            Settings.Save();

#if FAMISTUDIO_LINUX
            // We sometimes gets stuck here on Linux, lets abort.
            Environment.Exit(0);
#endif
        }
Пример #9
0
        static unsafe void Main(string[] args)
        {
#if FAMISTUDIO_WINDOWS
            try
            {
                // This is only supported in Windows 8.1+.
                SetProcessDpiAwareness(1 /*Process_System_DPI_Aware*/);
            }
            catch { }

            if (!PlatformUtils.IsVS2015RuntimeInstalled())
            {
                if (MessageBox.Show("You seem to be missing the VS 2015 C++ Runtime which is required to run FamiStudio, would you like to visit the FamiStudio website for instruction on how to install it?", "Missing Component", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    Utils.OpenUrl("https://famistudio.org/doc/#windows");
                }

                return;
            }

            if (!XAudio2Stream.TryDetectXAudio2())
            {
                if (MessageBox.Show("You seem to be missing parts of DirectX which is required to run FamiStudio, would you like to visit the FamiStudio website for instruction on how to install it?", "Missing Component", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    Utils.OpenUrl("https://famistudio.org/doc/#windows");
                }

                return;
            }
#endif

            Settings.Load();
            RenderTheme.Initialize();
            PlatformUtils.Initialize();
#if !FAMISTUDIO_MACOS
            Cursors.Initialize();
#endif
            FamiStudioTempoUtils.Initialize();
            NesApu.InitializeNoteTables();

#if FAMISTUDIO_WINDOWS
            WinUtils.Initialize();
            PerformanceCounter.Initialize();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
#endif
#if FAMISTUDIO_LINUX
            LinuxUtils.SetProcessName("FamiStudio");
#endif

            var cli = new CommandLineInterface(args);

            if (!cli.Run())
            {
                var famiStudio = new FamiStudio(args.Length > 0 ? args[0] : null);
                famiStudio.Run();
            }

            Settings.Save();

#if FAMISTUDIO_LINUX
            // We sometimes gets stuck here on Linux, lets abort.
            Environment.Exit(0);
#endif
        }
Пример #10
0
 public TempoInfo(int[] groove, bool pal, int notesPerBeat)
 {
     this.bpm    = FamiStudioTempoUtils.ComputeBpmForGroove(pal, groove, notesPerBeat);
     this.groove = groove;
 }
Пример #11
0
        public Project Load(string filename)
        {
#if !DEBUG
            try
#endif
            {
                var lines      = File.ReadAllLines(filename);
                var parameters = new Dictionary <string, string>();
                var project    = (Project)null;
                var instrument = (Instrument)null;
                var arpeggio   = (Arpeggio)null;
                var song       = (Song)null;
                var channel    = (Channel)null;
                var pattern    = (Pattern)null;

                SetInvariantCulture();

                foreach (var line in lines)
                {
                    var cmd = SplitLine(line.Trim(), ref parameters);

                    switch (cmd)
                    {
                    case "Project":
                    {
                        project = new Project();
                        parameters.TryGetValue("Version", out var version);
                        if (parameters.TryGetValue("Name", out var name))
                        {
                            project.Name = name;
                        }
                        if (parameters.TryGetValue("Author", out var author))
                        {
                            project.Author = author;
                        }
                        if (parameters.TryGetValue("Copyright", out var copyright))
                        {
                            project.Copyright = copyright;
                        }
                        if (parameters.TryGetValue("TempoMode", out var tempoMode))
                        {
                            project.TempoMode = TempoType.GetValueForName(tempoMode);
                        }
                        if (parameters.TryGetValue("PAL", out var pal))
                        {
                            project.PalMode = bool.Parse(pal);
                        }
                        if (parameters.TryGetValue("Expansions", out var expansions))
                        {
                            var expansionMask    = 0;
                            var expansionStrings = expansions.Split(',');

                            foreach (var s in expansionStrings)
                            {
                                var exp = ExpansionType.GetValueForShortName(s.Trim());
                                expansionMask |= ExpansionType.GetMaskFromValue(exp);
                            }

                            var numN163Channels = 1;
                            if ((expansionMask & ExpansionType.N163Mask) != 0 && parameters.TryGetValue("NumN163Channels", out var numN163ChannelsStr))
                            {
                                numN163Channels = int.Parse(numN163ChannelsStr);
                            }

                            project.SetExpansionAudioMask(expansionMask, numN163Channels);
                        }

                        if (!version.StartsWith("3.2"))
                        {
                            Log.LogMessage(LogSeverity.Error, "File was created with an incompatible version of FamiStudio. The text format is only compatible with the current version.");
                            return(null);
                        }
                        break;
                    }

                    case "DPCMSample":
                    {
                        var str  = parameters["Data"];
                        var data = new byte[str.Length / 2];
                        for (int i = 0; i < data.Length; i++)
                        {
                            data[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
                        }
                        var sample = project.CreateDPCMSampleFromDmcData(parameters["Name"], data);
                        break;
                    }

                    case "DPCMMapping":
                    {
                        var pitch = 15;
                        var loop  = false;
                        if (parameters.TryGetValue("Pitch", out var pitchStr))
                        {
                            pitch = int.Parse(pitchStr);
                        }
                        if (parameters.TryGetValue("Loop", out var loopStr))
                        {
                            loop = bool.Parse(loopStr);
                        }
                        project.MapDPCMSample(Note.FromFriendlyName(parameters["Note"]), project.GetSample(parameters["Sample"]), pitch, loop);
                        break;
                    }

                    case "Instrument":
                    {
                        var instrumentExp = ExpansionType.None;
                        if (parameters.TryGetValue("Expansion", out var instrumentExpStr))
                        {
                            instrumentExp = ExpansionType.GetValueForShortName(instrumentExpStr);
                        }
                        instrument = project.CreateInstrument(instrumentExp, parameters["Name"]);

                        if (instrument.IsFdsInstrument)
                        {
                            if (parameters.TryGetValue("FdsWavePreset", out var wavPresetStr))
                            {
                                instrument.FdsWavePreset = (byte)WavePresetType.GetValueForName(wavPresetStr);
                            }
                            if (parameters.TryGetValue("FdsModPreset", out var modPresetStr))
                            {
                                instrument.FdsWavePreset = (byte)WavePresetType.GetValueForName(modPresetStr);
                            }
                            if (parameters.TryGetValue("FdsMasterVolume", out var masterVolumeStr))
                            {
                                instrument.FdsMasterVolume = byte.Parse(masterVolumeStr);
                            }
                            if (parameters.TryGetValue("FdsModSpeed", out var fdsModSpeedStr))
                            {
                                instrument.FdsModSpeed = ushort.Parse(fdsModSpeedStr);
                            }
                            if (parameters.TryGetValue("FdsModDepth", out var fdsModDepthStr))
                            {
                                instrument.FdsModDepth = byte.Parse(fdsModDepthStr);
                            }
                            if (parameters.TryGetValue("FdsModDelay", out var fdsModDelayStr))
                            {
                                instrument.FdsModDelay = byte.Parse(fdsModDelayStr);
                            }
                        }
                        else if (instrument.IsN163Instrument)
                        {
                            if (parameters.TryGetValue("N163WavePreset", out var wavPresetStr))
                            {
                                instrument.N163WavePreset = (byte)WavePresetType.GetValueForName(wavPresetStr);
                            }
                            if (parameters.TryGetValue("N163WaveSize", out var n163WavSizeStr))
                            {
                                instrument.N163WaveSize = byte.Parse(n163WavSizeStr);
                            }
                            if (parameters.TryGetValue("N163WavePos", out var n163WavPosStr))
                            {
                                instrument.N163WavePos = byte.Parse(n163WavPosStr);
                            }
                        }
                        else if (instrument.IsVrc6Instrument)
                        {
                            if (parameters.TryGetValue("Vrc6SawMasterVolume", out var vrc6SawVolumeStr))
                            {
                                instrument.Vrc6SawMasterVolume = (byte)Vrc6SawMasterVolumeType.GetValueForName(vrc6SawVolumeStr);
                            }
                        }
                        else if (instrument.IsVrc7Instrument)
                        {
                            if (parameters.TryGetValue("Vrc7Patch", out var vrc7PatchStr))
                            {
                                instrument.Vrc7Patch = byte.Parse(vrc7PatchStr);
                            }

                            if (instrument.Vrc7Patch == Vrc7InstrumentPatch.Custom)
                            {
                                for (int i = 0; i < 8; i++)
                                {
                                    if (parameters.TryGetValue($"Vrc7Reg{i}", out var regStr))
                                    {
                                        instrument.Vrc7PatchRegs[i] = byte.Parse(regStr);
                                    }
                                }
                            }
                        }

                        break;
                    }

                    case "Arpeggio":
                    {
                        arpeggio = project.CreateArpeggio(parameters["Name"]);
                        arpeggio.Envelope.Length = int.Parse(parameters["Length"]);

                        if (parameters.TryGetValue("Loop", out var loopStr))
                        {
                            arpeggio.Envelope.Loop = int.Parse(loopStr);
                        }

                        var values = parameters["Values"].Split(',');
                        for (int j = 0; j < values.Length; j++)
                        {
                            arpeggio.Envelope.Values[j] = sbyte.Parse(values[j]);
                        }

                        break;
                    }

                    case "Envelope":
                    {
                        var env = instrument.Envelopes[EnvelopeType.GetValueForShortName(parameters["Type"])];
                        if (env != null)
                        {
                            if (env.CanResize)
                            {
                                env.Length = int.Parse(parameters["Length"]);
                            }

                            if (parameters.TryGetValue("Loop", out var loopStr))
                            {
                                env.Loop = int.Parse(loopStr);
                            }
                            if (parameters.TryGetValue("Release", out var releaseStr))
                            {
                                env.Release = int.Parse(releaseStr);
                            }
                            if (parameters.TryGetValue("Relative", out var relativeStr))
                            {
                                env.Relative = bool.Parse(relativeStr);
                            }

                            var values = parameters["Values"].Split(',');
                            for (int j = 0; j < values.Length; j++)
                            {
                                env.Values[j] = sbyte.Parse(values[j]);
                            }
                        }
                        break;
                    }

                    case "Song":
                    {
                        song = project.CreateSong(parameters["Name"]);
                        song.SetLength(int.Parse(parameters["Length"]));
                        song.SetBeatLength(int.Parse(parameters["BeatLength"]));
                        song.SetLoopPoint(int.Parse(parameters["LoopPoint"]));

                        if (song.UsesFamiTrackerTempo)
                        {
                            song.SetDefaultPatternLength(int.Parse(parameters["PatternLength"]));
                            song.FamitrackerTempo = int.Parse(parameters["FamiTrackerTempo"]);
                            song.FamitrackerSpeed = int.Parse(parameters["FamiTrackerSpeed"]);
                        }
                        else
                        {
                            var noteLength = int.Parse(parameters["NoteLength"]);

                            var groove            = parameters["Groove"].Split('-').Select(Int32.Parse).ToArray();
                            var groovePaddingMode = GroovePaddingType.GetValueForName(parameters["GroovePaddingMode"]);

                            if (!FamiStudioTempoUtils.ValidateGroove(groove) || Utils.Min(groove) != noteLength)
                            {
                                Log.LogMessage(LogSeverity.Error, "Invalid tempo settings.");
                                return(null);
                            }

                            song.ChangeFamiStudioTempoGroove(groove, false);
                            song.SetBeatLength(song.BeatLength * noteLength);
                            song.SetDefaultPatternLength(int.Parse(parameters["PatternLength"]) * noteLength);
                            song.SetGroovePaddingMode(groovePaddingMode);
                        }
                        break;
                    }

                    case "PatternCustomSettings":
                    {
                        if (project.UsesFamiTrackerTempo)
                        {
                            var beatLength = song.BeatLength;
                            if (parameters.TryGetValue("BeatLength", out var beatLengthStr))
                            {
                                beatLength = int.Parse(beatLengthStr);
                            }

                            song.SetPatternCustomSettings(int.Parse(parameters["Time"]), int.Parse(parameters["Length"]), beatLength);
                        }
                        else
                        {
                            var patternLength = int.Parse(parameters["Length"]);
                            var noteLength    = int.Parse(parameters["NoteLength"]);
                            var beatLength    = int.Parse(parameters["BeatLength"]);

                            var groove            = parameters["Groove"].Split('-').Select(Int32.Parse).ToArray();
                            var groovePaddingMode = GroovePaddingType.GetValueForName(parameters["GroovePaddingMode"]);

                            if (!FamiStudioTempoUtils.ValidateGroove(groove) || Utils.Min(groove) != noteLength)
                            {
                                Log.LogMessage(LogSeverity.Error, "Invalid tempo settings.");
                                return(null);
                            }

                            song.SetPatternCustomSettings(int.Parse(parameters["Time"]), patternLength * noteLength, beatLength * noteLength, groove, groovePaddingMode);
                        }
                        break;
                    }

                    case "Channel":
                    {
                        var channelType = ChannelType.GetValueForShortName(parameters["Type"]);
                        channel = song.GetChannelByType(channelType);
                        break;
                    }

                    case "Pattern":
                    {
                        pattern = channel.CreatePattern(parameters["Name"]);
                        break;
                    }

                    case "Note":
                    {
                        var time = int.Parse(parameters["Time"]);
                        var note = pattern.GetOrCreateNoteAt(time);

                        if (parameters.TryGetValue("Value", out var valueStr))
                        {
                            note.Value = (byte)Note.FromFriendlyName(valueStr);
                        }
                        if (note.IsMusical && parameters.TryGetValue("Duration", out var durationStr))
                        {
                            note.Duration = int.Parse(durationStr);
                        }
                        else if (note.IsStop)
                        {
                            note.Duration = 1;
                        }
                        if (note.IsMusical && parameters.TryGetValue("Release", out var releaseStr))
                        {
                            note.Release = int.Parse(releaseStr);
                        }
                        if (note.IsMusical && parameters.TryGetValue("Instrument", out var instStr) && channel.SupportsInstrument(project.GetInstrument(instStr)))
                        {
                            note.Instrument = project.GetInstrument(instStr);
                        }
                        if (note.IsMusical && parameters.TryGetValue("Arpeggio", out var arpStr) && channel.SupportsArpeggios)
                        {
                            note.Arpeggio = project.GetArpeggio(arpStr);
                        }
                        if (note.IsMusical && parameters.TryGetValue("SlideTarget", out var slideStr) && channel.SupportsSlideNotes)
                        {
                            note.SlideNoteTarget = (byte)Note.FromFriendlyName(slideStr);
                        }
                        if (note.IsMusical && parameters.TryGetValue("Attack", out var attackStr))
                        {
                            note.HasAttack = bool.Parse(attackStr);
                        }

                        if (parameters.TryGetValue("Volume", out var volumeStr) && channel.SupportsEffect(Note.EffectVolume))
                        {
                            note.Volume = byte.Parse(volumeStr);
                        }
                        if (parameters.TryGetValue("VolumeSlideTarget", out var volumeSlideStr) && channel.SupportsEffect(Note.EffectVolumeSlide))
                        {
                            note.VolumeSlideTarget = byte.Parse(volumeSlideStr);
                        }
                        if (parameters.TryGetValue("VibratoSpeed", out var vibSpeedStr) && channel.SupportsEffect(Note.EffectVibratoSpeed))
                        {
                            note.VibratoSpeed = byte.Parse(vibSpeedStr);
                        }
                        if (parameters.TryGetValue("VibratoDepth", out var vibDepthStr) && channel.SupportsEffect(Note.EffectVibratoDepth))
                        {
                            note.VibratoDepth = byte.Parse(vibDepthStr);
                        }
                        if (parameters.TryGetValue("Speed", out var speedStr) && channel.SupportsEffect(Note.EffectSpeed))
                        {
                            note.Speed = byte.Parse(speedStr);
                        }
                        if (parameters.TryGetValue("FinePitch", out var finePitchStr) && channel.SupportsEffect(Note.EffectFinePitch))
                        {
                            note.FinePitch = sbyte.Parse(finePitchStr);
                        }
                        if (parameters.TryGetValue("FdsModSpeed", out var modSpeedStr) && channel.SupportsEffect(Note.EffectFdsModSpeed))
                        {
                            note.FdsModSpeed = ushort.Parse(modSpeedStr);
                        }
                        if (parameters.TryGetValue("FdsModDepth", out var modDepthStr) && channel.SupportsEffect(Note.EffectFdsModDepth))
                        {
                            note.FdsModDepth = byte.Parse(modDepthStr);
                        }
                        if (parameters.TryGetValue("DutyCycle", out var dutyCycleStr) && channel.SupportsEffect(Note.EffectDutyCycle))
                        {
                            note.DutyCycle = byte.Parse(dutyCycleStr);
                        }
                        if (parameters.TryGetValue("NoteDelay", out var noteDelayStr) && channel.SupportsEffect(Note.EffectNoteDelay))
                        {
                            note.NoteDelay = byte.Parse(noteDelayStr);
                        }
                        if (parameters.TryGetValue("CutDelay", out var cutDelayStr) && channel.SupportsEffect(Note.EffectCutDelay))
                        {
                            note.CutDelay = byte.Parse(cutDelayStr);
                        }

                        break;
                    }

                    case "PatternInstance":
                    {
                        var time = int.Parse(parameters["Time"]);
                        channel.PatternInstances[time] = channel.GetPattern(parameters["Pattern"]);
                        break;
                    }
                    }
                }

                project.SortEverything(false);
                ResetCulture();

                return(project);
            }
#if !DEBUG
            catch (Exception e)
            {
                Log.LogMessage(LogSeverity.Error, "Please contact the developer on GitHub!");
                Log.LogMessage(LogSeverity.Error, e.Message);
                Log.LogMessage(LogSeverity.Error, e.StackTrace);
                ResetCulture();
                return(null);
            }
#endif
        }
Пример #12
0
        public void ApplyAsync(bool custom, Action callback)
        {
            if (song.UsesFamiTrackerTempo)
            {
                if (patternIdx == -1)
                {
                    if (famitrackerTempoPropIdx >= 0)
                    {
                        song.FamitrackerTempo = props.GetPropertyValue <int>(famitrackerTempoPropIdx);
                        song.FamitrackerSpeed = props.GetPropertyValue <int>(famitrackerSpeedPropIdx);
                    }

                    song.SetBeatLength(props.GetPropertyValue <int>(notesPerBeatPropIdx));
                    song.SetDefaultPatternLength(props.GetPropertyValue <int>(notesPerPatternPropIdx));
                }
                else
                {
                    for (int i = minPatternIdx; i <= maxPatternIdx; i++)
                    {
                        var beatLength    = props.GetPropertyValue <int>(notesPerBeatPropIdx);
                        var patternLength = props.GetPropertyValue <int>(notesPerPatternPropIdx);

                        if (custom)
                        {
                            song.SetPatternCustomSettings(i, patternLength, beatLength);
                        }
                        else
                        {
                            song.ClearPatternCustomSettings(i);
                        }
                    }
                }

                FinishApply(callback);
            }
            else
            {
                var tempoIndex = Array.IndexOf(tempoStrings, props.GetPropertyValue <string>(famistudioBpmPropIdx));
                var tempoInfo  = tempoList[tempoIndex];

                var beatLength    = props.GetPropertyValue <int>(notesPerBeatPropIdx);
                var patternLength = props.GetPropertyValue <int>(notesPerPatternPropIdx);
                var noteLength    = Utils.Min(tempoInfo.groove);

                var grooveIndex   = Array.IndexOf(grooveStrings, props.GetPropertyValue <string>(groovePropIdx));
                var groovePadMode = GroovePaddingType.GetValueForName(props.GetPropertyValue <string>(groovePadPropIdx));
                var grooveList    = FamiStudioTempoUtils.GetAvailableGrooves(tempoInfo.groove);
                var groove        = grooveList[grooveIndex];

                props.UpdateIntegerRange(notesPerPatternPropIdx, 1, Pattern.MaxLength / noteLength);
                props.SetLabelText(framesPerNotePropIdx, noteLength.ToString());

                if (patternIdx == -1)
                {
                    ShowConvertTempoDialogAsync(noteLength != originalNoteLength, (c) =>
                    {
                        song.ChangeFamiStudioTempoGroove(groove, c);
                        song.SetBeatLength(beatLength * song.NoteLength);
                        song.SetDefaultPatternLength(patternLength * song.NoteLength);
                        song.SetGroovePaddingMode(groovePadMode);

                        FinishApply(callback);
                    });
                }
                else
                {
                    var actualNoteLength    = song.NoteLength;
                    var actualPatternLength = song.PatternLength;
                    var actualBeatLength    = song.BeatLength;

                    if (custom)
                    {
                        actualNoteLength    = noteLength;
                        actualBeatLength    = beatLength * noteLength;
                        actualPatternLength = patternLength * noteLength;
                    }

                    var patternsToResize = new List <int>();
                    for (int i = minPatternIdx; i <= maxPatternIdx; i++)
                    {
                        if (actualNoteLength != song.GetPatternNoteLength(patternIdx))
                        {
                            patternsToResize.Add(i);
                        }
                    }

                    ShowConvertTempoDialogAsync(patternsToResize.Count > 0, (c) =>
                    {
                        if (c)
                        {
                            foreach (var p in patternsToResize)
                            {
                                song.ResizePatternNotes(p, actualNoteLength);
                            }
                        }

                        for (int i = minPatternIdx; i <= maxPatternIdx; i++)
                        {
                            if (custom)
                            {
                                song.SetPatternCustomSettings(i, actualPatternLength, actualBeatLength, groove, groovePadMode);
                            }
                            else
                            {
                                song.ClearPatternCustomSettings(i);
                            }
                        }

                        FinishApply(callback);
                    });
                }
            }
        }
Пример #13
0
        private void UpdateWarnings()
        {
            var numFramesPerPattern = 0;

            if (song.UsesFamiStudioTempo)
            {
                var tempoIndex      = Array.IndexOf(tempoStrings, props.GetPropertyValue <string>(famistudioBpmPropIdx));
                var tempoInfo       = tempoList[tempoIndex];
                var notesPerBeat    = props.GetPropertyValue <int>(notesPerBeatPropIdx);
                var notesPerPattern = props.GetPropertyValue <int>(notesPerPatternPropIdx);

                if (tempoInfo.groove.Length == 1)
                {
                    props.SetPropertyWarning(famistudioBpmPropIdx, CommentType.Good, "Ideal tempo : notes will be perfectly evenly divided.");
                }
                else if ((tempoInfo.groove.Length % notesPerBeat) == 0 ||
                         (notesPerBeat % tempoInfo.groove.Length) == 0)
                {
                    props.SetPropertyWarning(famistudioBpmPropIdx, CommentType.Warning, "Beat-aligned groove : notes will be slightly uneven, but well aligned with the beat.");
                }
                else
                {
                    props.SetPropertyWarning(famistudioBpmPropIdx, CommentType.Error, "Unaligned groove : notes will be slightly uneven and not aligned to the beat.");
                }

                if (notesPerBeat != 4)
                {
                    props.SetPropertyWarning(notesPerBeatPropIdx, CommentType.Error, "A value of 4 is strongly recommended as it gives the best range of available BPMs.");
                }
                else
                {
                    props.SetPropertyWarning(notesPerBeatPropIdx, CommentType.Good, "4 is the recommended value.");
                }

                var groovePadMode = GroovePaddingType.GetValueForName(props.GetPropertyValue <string>(groovePadPropIdx));
                numFramesPerPattern = FamiStudioTempoUtils.ComputeNumberOfFrameForGroove(notesPerPattern * Utils.Min(tempoInfo.groove), tempoInfo.groove, groovePadMode);
            }
            else if (famitrackerSpeedPropIdx >= 0)
            {
                var speed = props.GetPropertyValue <int>(famitrackerSpeedPropIdx);
                var tempo = props.GetPropertyValue <int>(famitrackerTempoPropIdx);

                if (speed == 1)
                {
                    props.SetPropertyWarning(famitrackerSpeedPropIdx, CommentType.Warning, $"A speed of 1 will not produce the same BPM between platforms (PAL/NTSC).");
                }
                else
                {
                    props.SetPropertyWarning(famitrackerSpeedPropIdx, CommentType.Good, "");
                }

                if (tempo != 150)
                {
                    props.SetPropertyWarning(famitrackerTempoPropIdx, CommentType.Warning, "A tempo of 150 is strongly recommended as it produces even notes on all platforms (NTSC/PAL).");
                }
                else
                {
                    props.SetPropertyWarning(famitrackerTempoPropIdx, CommentType.Good, "150 is the recommended value.");
                }
            }

            if (patternIdx >= 0 && numFramesPerPattern > song.PatternLength)
            {
                props.SetPropertyWarning(notesPerPatternPropIdx, CommentType.Warning, $"Pattern is longer than the song pattern length and FamiTracker does not support this. Ignore this if you are not planning to export to FamiTracker.");
            }
            else if (numFramesPerPattern >= 256)
            {
                props.SetPropertyWarning(notesPerPatternPropIdx, CommentType.Warning, $"Pattern is longer than what FamiTracker supports. Ignore this if you are not planning to export to FamiTracker.");
            }
            else
            {
                props.SetPropertyWarning(notesPerPatternPropIdx, CommentType.Good, "");
            }
        }