private void ExportWav() { var filename = PlatformUtils.ShowSaveFileDialog("Export Wave File", "Wave Audio File (*.wav)|*.wav", ref Settings.LastExportFolder); if (filename != null) { var props = dialog.GetPropertyPage((int)ExportFormat.Wav); var songName = props.GetPropertyValue <string>(0); var sampleRate = Convert.ToInt32(props.GetPropertyValue <string>(1)); var loopCount = props.GetPropertyValue <string>(2) != "Duration" ? props.GetPropertyValue <int>(3) : -1; var duration = props.GetPropertyValue <string>(2) == "Duration" ? props.GetPropertyValue <int>(4) : -1; var selectedChannels = props.GetPropertyValue <bool[]>(5); var channelMask = 0; for (int i = 0; i < selectedChannels.Length; i++) { if (selectedChannels[i]) { channelMask |= (1 << i); } } WaveFile.Save(project.GetSong(songName), filename, sampleRate, loopCount, duration, channelMask); } }
private void ExportWavMp3() { var props = dialog.GetPropertyPage((int)ExportFormat.WavMp3); var format = props.GetPropertyValue <string>(1); var filename = ""; if (format == "MP3") { filename = lastExportFilename != null ? lastExportFilename : PlatformUtils.ShowSaveFileDialog("Export MP3 File", "MP3 Audio File (*.mp3)|*.mp3", ref Settings.LastExportFolder); } else { filename = lastExportFilename != null ? lastExportFilename : PlatformUtils.ShowSaveFileDialog("Export Wave File", "Wave Audio File (*.wav)|*.wav", ref Settings.LastExportFolder); } if (filename != null) { var songName = props.GetPropertyValue <string>(0); var sampleRate = Convert.ToInt32(props.GetPropertyValue <string>(2), CultureInfo.InvariantCulture); var bitRate = Convert.ToInt32(props.GetPropertyValue <string>(3), CultureInfo.InvariantCulture); var loopCount = props.GetPropertyValue <string>(4) != "Duration" ? props.GetPropertyValue <int>(5) : -1; var duration = props.GetPropertyValue <string>(4) == "Duration" ? props.GetPropertyValue <int>(6) : -1; var separateFiles = props.GetPropertyValue <bool>(7); var separateIntro = props.GetPropertyValue <bool>(8); var selectedChannels = props.GetPropertyValue <bool[]>(9); var song = project.GetSong(songName); var channelMask = 0; for (int i = 0; i < selectedChannels.Length; i++) { if (selectedChannels[i]) { channelMask |= (1 << i); } } WavMp3ExportUtils.Save(song, filename, sampleRate, loopCount, duration, channelMask, separateFiles, separateIntro, (samples, fn) => { if (format == "MP3") { Mp3File.Save(samples, fn, sampleRate, bitRate); } else { WaveFile.Save(samples, fn, sampleRate); } }); lastExportFilename = filename; } }
private void ExportWav() { var filename = PlatformUtils.ShowSaveFileDialog("Export Wave File", "Wave Audio File (*.wav)|*.wav"); if (filename != null) { var props = dialog.GetPropertyPage((int)ExportFormat.Wav); var songName = props.GetPropertyValue <string>(0); var sampleRate = Convert.ToInt32(props.GetPropertyValue <string>(1)); WaveFile.Save(project.GetSong(songName), filename, sampleRate); } }
public void Serialize(ref Song song) { int songId = -1; Serialize(ref songId, true); song = project.GetSong(songId); }
private void FamiTone2MusicExport(string filename, bool famiStudio) { var kernel = famiStudio ? FamiToneKernel.FamiStudio : FamiToneKernel.FamiTone2; var engineName = famiStudio ? "famistudio" : "famitone2"; var formatString = ParseOption($"{engineName}-asm-format", "nesasm"); var format = AssemblyFormat.NESASM; switch (formatString) { case "ca65": format = AssemblyFormat.CA65; break; case "asm6": format = AssemblyFormat.ASM6; break; } var extension = format == AssemblyFormat.CA65 ? ".s" : ".asm"; var seperate = HasOption($"{engineName}-asm-seperate-files"); var generateInclude = HasOption($"{engineName}-generate-list"); if (!seperate && !ValidateExtension(filename, extension)) { return; } var exportSongIds = GetExportSongIds(); if (exportSongIds != null) { if (seperate) { var songNamePattern = ParseOption($"{engineName}-asm-seperate-song-pattern", "{project}_{song}"); var dpcmNamePattern = ParseOption($"{engineName}-asm-seperate-dmc-pattern", "{project}"); foreach (var songId in exportSongIds) { var song = project.GetSong(songId); var formattedSongName = songNamePattern.Replace("{project}", project.Name).Replace("{song}", song.Name); var formattedDpcmName = dpcmNamePattern.Replace("{project}", project.Name).Replace("{song}", song.Name); var songFilename = Path.Combine(filename, Utils.MakeNiceAsmName(formattedSongName) + extension); var dpcmFilename = Path.Combine(filename, Utils.MakeNiceAsmName(formattedDpcmName) + ".dmc"); var includeFilename = generateInclude ? Path.ChangeExtension(songFilename, null) + "_songlist.inc" : null; Log.LogMessage(LogSeverity.Info, $"Exporting song '{song.Name}' as separate assembly files."); FamitoneMusicFile f = new FamitoneMusicFile(kernel, true); f.Save(project, new int[] { songId }, format, true, songFilename, dpcmFilename, includeFilename, MachineType.Dual); } } else { var includeFilename = generateInclude ? Path.ChangeExtension(filename, null) + "_songlist.inc" : null; Log.LogMessage(LogSeverity.Info, $"Exporting all songs to a single assembly file."); FamitoneMusicFile f = new FamitoneMusicFile(kernel, true); f.Save(project, exportSongIds, format, false, filename, Path.ChangeExtension(filename, ".dmc"), includeFilename, MachineType.Dual); } } }
private void FamiTone2MusicExport(string filename) { var formatString = ParseOption("famitone2-format", "nesasm"); var format = AssemblyFormat.NESASM; switch (formatString) { case "ca65": format = AssemblyFormat.CA65; break; case "asm6": format = AssemblyFormat.ASM6; break; } var extension = format == AssemblyFormat.CA65 ? ".s" : ".asm"; var seperate = HasOption("famitone2-seperate-files"); if (!seperate && !ValidateExtension(filename, extension)) { return; } var kernelString = ParseOption("famitone2-variant", "famitone2"); var kernel = FamitoneMusicFile.FamiToneKernel.FamiTone2; switch (formatString) { case "famitone2fs": kernel = FamitoneMusicFile.FamiToneKernel.FamiTone2FS; break; case "famistudio": kernel = FamitoneMusicFile.FamiToneKernel.FamiStudio; break; } var exportSongIds = GetExportSongIds(); if (exportSongIds != null) { if (seperate) { var songNamePattern = ParseOption("famitone2-seperate-song-pattern", "{project}_{song}"); var dpcmNamePattern = ParseOption("famitone2-seperate-dmc-pattern", "{project}"); foreach (var songId in exportSongIds) { var song = project.GetSong(songId); var formattedSongName = songNamePattern.Replace("{project}", project.Name).Replace("{song}", song.Name); var formattedDpcmName = dpcmNamePattern.Replace("{project}", project.Name).Replace("{song}", song.Name); var songFilename = Path.Combine(filename, Utils.MakeNiceAsmName(formattedSongName) + extension); var dpcmFilename = Path.Combine(filename, Utils.MakeNiceAsmName(formattedDpcmName) + ".dmc"); FamitoneMusicFile f = new FamitoneMusicFile(kernel); f.Save(project, new int[] { songId }, format, true, songFilename, dpcmFilename, MachineType.Dual); } } else { FamitoneMusicFile f = new FamitoneMusicFile(kernel); f.Save(project, exportSongIds, format, false, filename, Path.ChangeExtension(filename, ".dmc"), MachineType.Dual); } } }
private void ExportWav() { var sfd = new SaveFileDialog() { Filter = "Wave Audio File (*.wav)|*.wav", Title = "Export Wave File" }; if (sfd.ShowDialog() == DialogResult.OK) { var props = formatProps[(int)ExportFormat.Wav]; var songName = props.GetPropertyValue <string>(0); var sampleRate = Convert.ToInt32(props.GetPropertyValue <string>(1)); WaveFile.Save(project.GetSong(songName), sfd.FileName, sampleRate); } }
public bool Save(Project project, int[] songIds, AssemblyFormat format, MachineType mode, string filename) { SetupFormat(format); var modeStrings = new List <string>(); if (mode == MachineType.NTSC || mode == MachineType.Dual) { modeStrings.Add("ntsc"); } if (mode == MachineType.PAL || mode == MachineType.Dual) { modeStrings.Add("pal"); } var lines = new List <string>(); lines.Add($";this file for FamiTone2 libary generated by FamiStudio\n"); lines.Add($"sounds:"); lines.Add($"\t{dw} {ll}{modeStrings[0]}"); lines.Add($"\t{dw} {ll}{modeStrings[1 % modeStrings.Count]}"); foreach (var str in modeStrings) { lines.Add($"{ll}{str}:"); foreach (var songId in songIds) { var song = project.GetSong(songId); lines.Add($"\t{dw} {ll}sfx_{str}_{Utils.MakeNiceAsmName(song.Name)}"); } lines.Add(""); } foreach (var str in modeStrings) { foreach (var songId in songIds) { var song = project.GetSong(songId); var regPlayer = new RegisterPlayer(); var writes = regPlayer.GetRegisterValues(song, str == "pal"); var lastChangeFrame = 0; var lastZeroVolumeIdx = -1; var volumeAllZero = true; var volume = new int[4]; var regs = new int[32]; var effect = new List <byte>(); for (int i = 0; i < regs.Length; i++) { regs[i] = -1; } regs[0x00] = 0x30; regs[0x04] = 0x30; regs[0x08] = 0x00; regs[0x0c] = 0x30; foreach (var reg in writes) { if (reg.Register == NesApu.APU_PL1_VOL || reg.Register == NesApu.APU_PL1_LO || reg.Register == NesApu.APU_PL1_HI || reg.Register == NesApu.APU_PL2_VOL || reg.Register == NesApu.APU_PL2_LO || reg.Register == NesApu.APU_PL2_HI || reg.Register == NesApu.APU_TRI_LINEAR || reg.Register == NesApu.APU_TRI_LO || reg.Register == NesApu.APU_TRI_HI || reg.Register == NesApu.APU_NOISE_VOL || reg.Register == NesApu.APU_NOISE_LO) { if (regs[reg.Register - 0x4000] != reg.Value) { if (reg.FrameNumber != lastChangeFrame) { int numEmptyFrames = reg.FrameNumber - lastChangeFrame; while (numEmptyFrames >= 0) { effect.Add((byte)(Math.Min(numEmptyFrames, 127))); numEmptyFrames -= 127; } } switch (reg.Register) { case 0x4000: volume[0] = reg.Value & 0x0f; break; case 0x4004: volume[1] = reg.Value & 0x0f; break; case 0x4008: volume[2] = reg.Value & 0x7f; break; case 0x400c: volume[3] = reg.Value & 0x0f; break; } if (!volumeAllZero) { if (volume[0] == 0 && volume[1] == 0 && volume[2] == 0 && volume[3] == 0) { volumeAllZero = true; lastZeroVolumeIdx = effect.Count(); } } else { if (volume[0] != 0 || volume[1] != 0 || volume[2] != 0 || volume[3] != 0) { volumeAllZero = false; } } effect.Add(RegisterMap[reg.Register - 0x4000]); effect.Add((byte)reg.Value); regs[reg.Register - 0x4000] = reg.Value; lastChangeFrame = reg.FrameNumber; } } } if (!volumeAllZero) { int numEmptyFrames = writes[writes.Length - 1].FrameNumber - lastChangeFrame; while (numEmptyFrames > 0) { effect.Add((byte)(Math.Min(numEmptyFrames, 127))); numEmptyFrames -= 127; } } else { effect.RemoveRange(lastZeroVolumeIdx, effect.Count - lastZeroVolumeIdx); } // TODO: Error management! if (effect.Count > 255) { effect.RemoveRange(lastZeroVolumeIdx, effect.Count - 255); } effect.Add(0); lines.Add($"{ll}sfx_{str}_{Utils.MakeNiceAsmName(song.Name)}:"); for (int i = 0; i < (effect.Count + 15) / 16; i++) { lines.Add($"\t{db} {string.Join(",", effect.Skip(i * 16).Take(Math.Min(16, effect.Count - i * 16)).Select(x => $"${x:x2}"))}"); } } } File.WriteAllLines(filename, lines.ToArray()); return(true); }
public bool Save(Project project, int[] songIds, int format, int machine, int kernel, string filename, string includeFilename) { SetupFormat(format); var modeStrings = new List <string>(); if (machine == MachineType.NTSC || machine == MachineType.Dual) { modeStrings.Add("ntsc"); } if (machine == MachineType.PAL || machine == MachineType.Dual) { modeStrings.Add("pal"); } var lines = new List <string>(); lines.Add($";this file for FamiTone2 libary generated by FamiStudio\n"); lines.Add($"sounds:"); lines.Add($"\t{dw} {ll}{modeStrings[0]}"); lines.Add($"\t{dw} {ll}{modeStrings[1 % modeStrings.Count]}"); foreach (var str in modeStrings) { lines.Add($"{ll}{str}:"); foreach (var songId in songIds) { var song = project.GetSong(songId); lines.Add($"\t{dw} {ll}sfx_{str}_{Utils.MakeNiceAsmName(song.Name)}"); } lines.Add(""); } foreach (var str in modeStrings) { foreach (var songId in songIds) { var song = project.GetSong(songId); var writes = GetRegisterWrites(song, str == "pal"); var lastChangeFrame = 0; var lastZeroVolumeIdx = -1; var volumeAllZero = true; var volume = new int[4]; var regs = new int[32]; var effect = new List <byte>(); var lastByteIsOperand = false; for (int i = 0; i < regs.Length; i++) { regs[i] = -1; } regs[0x00] = 0x30; regs[0x04] = 0x30; regs[0x08] = 0x80; regs[0x0c] = 0x30; foreach (var reg in writes) { if (reg.Register == NesApu.APU_PL1_VOL || reg.Register == NesApu.APU_PL1_LO || reg.Register == NesApu.APU_PL1_HI || reg.Register == NesApu.APU_PL2_VOL || reg.Register == NesApu.APU_PL2_LO || reg.Register == NesApu.APU_PL2_HI || reg.Register == NesApu.APU_TRI_LINEAR || reg.Register == NesApu.APU_TRI_LO || reg.Register == NesApu.APU_TRI_HI || reg.Register == NesApu.APU_NOISE_VOL || reg.Register == NesApu.APU_NOISE_LO) { if (regs[reg.Register - 0x4000] != reg.Value) { if (reg.FrameNumber != lastChangeFrame) { int numEmptyFrames = reg.FrameNumber - lastChangeFrame; while (numEmptyFrames >= 0) { effect.Add((byte)(Math.Min(numEmptyFrames, 127))); numEmptyFrames -= 127; } } switch (reg.Register) { case 0x4000: volume[0] = reg.Value & 0x0f; break; case 0x4004: volume[1] = reg.Value & 0x0f; break; case 0x4008: volume[2] = reg.Value & 0x7f; break; case 0x400c: volume[3] = reg.Value & 0x0f; break; } if (!volumeAllZero) { if (volume[0] == 0 && volume[1] == 0 && volume[2] == 0 && volume[3] == 0) { volumeAllZero = true; lastZeroVolumeIdx = effect.Count(); } } else { if (volume[0] != 0 || volume[1] != 0 || volume[2] != 0 || volume[3] != 0) { volumeAllZero = false; } } effect.Add(RegisterMap[reg.Register - 0x4000]); effect.Add((byte)reg.Value); if (effect.Count == 255) { lastByteIsOperand = true; } regs[reg.Register - 0x4000] = reg.Value; lastChangeFrame = reg.FrameNumber; } } } if (!volumeAllZero) { int numEmptyFrames = writes[writes.Length - 1].FrameNumber - lastChangeFrame; while (numEmptyFrames > 0) { effect.Add((byte)(Math.Min(numEmptyFrames, 127))); numEmptyFrames -= 127; } } else if (lastZeroVolumeIdx >= 0) { effect.RemoveRange(lastZeroVolumeIdx, effect.Count - lastZeroVolumeIdx); } if (kernel == FamiToneKernel.FamiTone2 && effect.Count > 255) { Log.LogMessage(LogSeverity.Warning, $"Effect ({song.Name}) was longer than 256 bytes ({effect.Count}) and was truncated."); var removeStart = lastByteIsOperand ? 254 : 255; effect.RemoveRange(removeStart, effect.Count - removeStart); } effect.Add(0); lines.Add($"{ll}sfx_{str}_{Utils.MakeNiceAsmName(song.Name)}:"); for (int i = 0; i < (effect.Count + 15) / 16; i++) { lines.Add($"\t{db} {string.Join(",", effect.Skip(i * 16).Take(Math.Min(16, effect.Count - i * 16)).Select(x => $"${x:x2}"))}"); } Log.LogMessage(LogSeverity.Info, $"Effect ({song.Name}): {effect.Count} bytes."); } } if (format == AssemblyFormat.CA65) { lines.Add(""); lines.Add(".export sounds"); } File.WriteAllLines(filename, lines.ToArray()); if (includeFilename != null) { var includeLines = new List <string>(); for (int songIdx = 0; songIdx < songIds.Length; songIdx++) { var songId = songIds[songIdx]; var song = project.GetSong(songId); includeLines.Add($"sfx_{Utils.MakeNiceAsmName(song.Name)} = {songIdx}"); } includeLines.Add($"sfx_max = {songIds.Length}"); // For CA65, also include song names. if (format == AssemblyFormat.CA65) { includeLines.Add(""); includeLines.Add(".if SFX_STRINGS"); includeLines.Add("sfx_strings:"); foreach (var songId in songIds) { var song = project.GetSong(songId); includeLines.Add($".asciiz \"{song.Name}\""); } includeLines.Add(".endif"); } File.WriteAllLines(includeFilename, includeLines.ToArray()); } return(true); }
private void ExportWavMp3() { var props = dialog.GetPropertyPage((int)ExportFormat.WavMp3); var format = props.GetPropertyValue <string>(1); var filename = ""; if (format == "MP3") { filename = PlatformUtils.ShowSaveFileDialog("Export MP3 File", "MP3 Audio File (*.mp3)|*.mp3", ref Settings.LastExportFolder); } else { filename = PlatformUtils.ShowSaveFileDialog("Export Wave File", "Wave Audio File (*.wav)|*.wav", ref Settings.LastExportFolder); } if (filename != null) { var songName = props.GetPropertyValue <string>(0); var sampleRate = Convert.ToInt32(props.GetPropertyValue <string>(2)); var bitRate = Convert.ToInt32(props.GetPropertyValue <string>(3)); var loopCount = props.GetPropertyValue <string>(4) != "Duration" ? props.GetPropertyValue <int>(5) : -1; var duration = props.GetPropertyValue <string>(4) == "Duration" ? props.GetPropertyValue <int>(6) : -1; var separateFiles = props.GetPropertyValue <bool>(7); var selectedChannels = props.GetPropertyValue <bool[]>(8); var song = project.GetSong(songName); if (separateFiles) { for (int i = 0; i < selectedChannels.Length; i++) { if (selectedChannels[i]) { var channelFilename = Utils.AddFileSuffix(filename, "_" + song.Channels[i].ExportName); if (format == "MP3") { Mp3File.Save(song, channelFilename, sampleRate, bitRate, loopCount, duration, 1 << i); } else { WaveFile.Save(song, channelFilename, sampleRate, loopCount, duration, 1 << i); } } } } else { var channelMask = 0; for (int i = 0; i < selectedChannels.Length; i++) { if (selectedChannels[i]) { channelMask |= (1 << i); } } if (format == "MP3") { Mp3File.Save(song, filename, sampleRate, bitRate, loopCount, duration, channelMask); } else { WaveFile.Save(song, filename, sampleRate, loopCount, duration, channelMask); } } } }
private void ExportWavMp3() { var props = dialog.GetPropertyPage((int)ExportFormat.WavMp3); var format = props.GetSelectedIndex(1); Action <string> ExportWavMp3Action = (filename) => { if (filename != null) { var songName = props.GetPropertyValue <string>(0); var sampleRate = Convert.ToInt32(props.GetPropertyValue <string>(2), CultureInfo.InvariantCulture); var bitrate = Convert.ToInt32(props.GetPropertyValue <string>(3), CultureInfo.InvariantCulture); var loopCount = props.GetPropertyValue <string>(4) != "Duration" ? props.GetPropertyValue <int>(5) : -1; var duration = props.GetPropertyValue <string>(4) == "Duration" ? props.GetPropertyValue <int>(6) : -1; var separateFiles = props.GetPropertyValue <bool>(7); var separateIntro = props.GetPropertyValue <bool>(8); var stereo = props.GetPropertyValue <bool>(9) && !separateFiles; var song = project.GetSong(songName); var channelCount = project.GetActiveChannelCount(); var channelMask = 0; var pan = (float[])null; if (PlatformUtils.IsDesktop) { pan = new float[channelCount]; for (int i = 0; i < channelCount; i++) { if (props.GetPropertyValue <bool>(10, i, 0)) { channelMask |= (1 << i); } pan[i] = props.GetPropertyValue <int>(10, i, 2) / 100.0f; } } else { var selectedChannels = props.GetPropertyValue <bool[]>(10); for (int i = 0; i < channelCount; i++) { if (selectedChannels[i]) { channelMask |= (1 << i); } } } AudioExportUtils.Save(song, filename, sampleRate, loopCount, duration, channelMask, separateFiles, separateIntro, stereo, pan, (samples, samplesChannels, fn) => { switch (format) { case AudioFormatType.Mp3: Mp3File.Save(samples, fn, sampleRate, bitrate, samplesChannels); break; case AudioFormatType.Wav: WaveFile.Save(samples, fn, sampleRate, samplesChannels); break; case AudioFormatType.Vorbis: VorbisFile.Save(samples, fn, sampleRate, bitrate, samplesChannels); break; } }); lastExportFilename = filename; } }; if (PlatformUtils.IsMobile) { var songName = props.GetPropertyValue <string>(0); PlatformUtils.StartMobileSaveFileOperationAsync(AudioFormatType.MimeTypes[format], $"{songName}", (f) => { ExportWavMp3Action(f); PlatformUtils.FinishMobileSaveFileOperationAsync(true, () => { PlatformUtils.ShowToast("Audio Export Successful!"); }); }); } else { var filename = (string)null; if (lastExportFilename != null) { filename = lastExportFilename; } else { filename = PlatformUtils.ShowSaveFileDialog( $"Export {AudioFormatType.Names[format]} File", $"{AudioFormatType.Names[format]} Audio File (*.{AudioFormatType.Extensions[format]})|*.{AudioFormatType.Extensions[format]}", ref Settings.LastExportFolder); } ExportWavMp3Action(filename); } }