Пример #1
0
        public unsafe static bool Save(Song song, string filename, int sampleRate, int bitRate, int loopCount, int duration, int channelMask)
        {
            if (sampleRate < 44100)
            {
                sampleRate = 44100;
                Log.LogMessage(LogSeverity.Warning, $"Sample rate of {sampleRate}Hz is too low for MP3. Forcing 44100Hz.");
            }

            var project = song.Project;
            var player  = new WavPlayer(sampleRate, loopCount, channelMask);
            var wavData = player.GetSongSamples(song, project.PalMode, duration);
            var mp3Data = new byte[wavData.Length * sizeof(short) * 4];
            var mp3Size = 0;

            fixed(short *wavPtr = &wavData[0])
            {
                fixed(byte *mp3Ptr = &mp3Data[0])
                {
                    mp3Size = ShineMp3Encode(sampleRate, 1, wavData.Length, new IntPtr(wavPtr), bitRate, mp3Data.Length, new IntPtr(mp3Ptr));
                }
            }

            if (mp3Size <= 0)
            {
                return(false);
            }

            Array.Resize(ref mp3Data, mp3Size);
            File.WriteAllBytes(filename, mp3Data);

            return(true);
        }
Пример #2
0
        public unsafe static void Save(Song song, string filename, int sampleRate, int loopCount, int duration, int channelMask)
        {
            var project = song.Project;
            var player  = new WavPlayer(sampleRate, loopCount, channelMask);
            var samples = player.GetSongSamples(song, project.PalMode, duration);

            using (var file = new FileStream(filename, FileMode.Create))
            {
                var header = new WaveHeader();

                // RIFF WAVE Header
                header.chunkId[0] = (byte)'R';
                header.chunkId[1] = (byte)'I';
                header.chunkId[2] = (byte)'F';
                header.chunkId[3] = (byte)'F';
                header.format[0]  = (byte)'W';
                header.format[1]  = (byte)'A';
                header.format[2]  = (byte)'V';
                header.format[3]  = (byte)'E';

                // Format subchunk
                header.subChunk1Id[0] = (byte)'f';
                header.subChunk1Id[1] = (byte)'m';
                header.subChunk1Id[2] = (byte)'t';
                header.subChunk1Id[3] = (byte)' ';
                header.audioFormat    = 1;          // FOR PCM
                header.numChannels    = 1;          // 1 for MONO, 2 for stereo
                header.sampleRate     = sampleRate; // ie 44100 hertz, cd quality audio
                header.bitsPerSample  = 16;         //
                header.byteRate       = header.sampleRate * header.numChannels * header.bitsPerSample / 8;
                header.blockAlign     = (short)(header.numChannels * header.bitsPerSample / 8);

                // Data subchunk
                header.subChunk2Id[0] = (byte)'d';
                header.subChunk2Id[1] = (byte)'a';
                header.subChunk2Id[2] = (byte)'t';
                header.subChunk2Id[3] = (byte)'a';

                // All sizes for later:
                // chuckSize = 4 + (8 + subChunk1Size) + (8 + subChubk2Size)
                // subChunk1Size is constanst, i'm using 16 and staying with PCM
                // subChunk2Size = nSamples * nChannels * bitsPerSample/8
                // Whenever a sample is added:
                //    chunkSize += (nChannels * bitsPerSample/8)
                //    subChunk2Size += (nChannels * bitsPerSample/8)
                header.subChunk1Size = 16;
                header.subChunk2Size = samples.Length * sizeof(short);
                header.chunkSize     = 4 + (8 + header.subChunk1Size) + (8 + header.subChunk2Size);

                var headerBytes = new byte[sizeof(WaveHeader)];
                Marshal.Copy(new IntPtr(&header), headerBytes, 0, headerBytes.Length);
                file.Write(headerBytes, 0, headerBytes.Length);

                // So lame.
                foreach (var s in samples)
                {
                    file.Write(BitConverter.GetBytes(s), 0, sizeof(short));
                }
            }
        }
Пример #3
0
        public unsafe static void Save(Song song, string filename, int sampleRate, int loopCount, int duration, int channelMask)
        {
            var project = song.Project;
            var player  = new WavPlayer(sampleRate, loopCount, channelMask);
            var samples = player.GetSongSamples(song, project.PalMode, duration);

            Save(samples, filename, sampleRate);
        }
Пример #4
0
        public unsafe static void Save(Song song, string filename, int sampleRate, int loopCount, int duration, int channelMask, bool separateFiles, bool separateIntro, Action <short[], string> function)
        {
            var project       = song.Project;
            var introDuration = separateIntro ? GetIntroDuration(song, sampleRate) : 0;

            if (separateFiles)
            {
                for (int channelIdx = 0; channelIdx < song.Channels.Length; channelIdx++)
                {
                    var channelBit = 1 << channelIdx;
                    if ((channelBit & channelMask) != 0)
                    {
                        var player  = new WavPlayer(sampleRate, loopCount, channelBit);
                        var samples = player.GetSongSamples(song, project.PalMode, duration);

                        if (introDuration > 0)
                        {
                            var loopSamples = new short[samples.Length - introDuration];
                            Array.Copy(samples, introDuration, loopSamples, 0, loopSamples.Length);
                            Array.Resize(ref samples, introDuration);

                            var channelIntroFileName = Utils.AddFileSuffix(filename, "_" + song.Channels[channelIdx].ShortName + "_Intro");
                            var channelLoopFileName  = Utils.AddFileSuffix(filename, "_" + song.Channels[channelIdx].ShortName);

                            function(samples, channelIntroFileName);
                            function(loopSamples, channelLoopFileName);
                        }
                        else
                        {
                            var channelFileName = Utils.AddFileSuffix(filename, "_" + song.Channels[channelIdx].ShortName);
                            function(samples, channelFileName);
                        }
                    }
                }
            }
            else
            {
                var player  = new WavPlayer(sampleRate, loopCount, channelMask);
                var samples = player.GetSongSamples(song, project.PalMode, duration);

                if (introDuration > 0)
                {
                    var loopSamples = new short[samples.Length - introDuration];
                    Array.Copy(samples, introDuration, loopSamples, 0, loopSamples.Length);
                    Array.Resize(ref samples, introDuration);

                    var introFileName = Utils.AddFileSuffix(filename, "_Intro");
                    var loopFileName  = filename;

                    function(samples, introFileName);
                    function(loopSamples, loopFileName);
                }
                else
                {
                    function(samples, filename);
                }
            }
        }
Пример #5
0
        public static int GetIntroDuration(Song song, int sampleRate)
        {
            if (song.LoopPoint > 0)
            {
                // Create a shorter version of the song.
                var songIndex     = song.Project.Songs.IndexOf(song);
                var clonedProject = song.Project.DeepClone();
                var clonedSong    = clonedProject.Songs[songIndex];

                clonedSong.SetLength(song.LoopPoint);

                var player  = new WavPlayer(sampleRate, 1, 0x7fffffff);
                var samples = player.GetSongSamples(clonedSong, song.Project.PalMode, -1);

                return(samples.Length);
            }
            else
            {
                return(0);
            }
        }
Пример #6
0
        public unsafe static void Save(Song song, string filename, int sampleRate, int loopCount, int duration, int channelMask, bool separateFiles, bool separateIntro, bool stereo, float[] pan, Action <short[], int, string> function)
        {
            var project       = song.Project;
            var introDuration = separateIntro ? GetIntroDuration(song, sampleRate) : 0;

            if (channelMask == 0)
            {
                return;
            }

            if (separateFiles)
            {
                for (int channelIdx = 0; channelIdx < song.Channels.Length; channelIdx++)
                {
                    var channelBit = 1 << channelIdx;
                    if ((channelBit & channelMask) != 0)
                    {
                        var player  = new WavPlayer(sampleRate, loopCount, channelBit, Settings.SeparateChannelsExportTndMode);
                        var samples = player.GetSongSamples(song, project.PalMode, duration);

                        if (introDuration > 0)
                        {
                            var loopSamples = new short[samples.Length - introDuration];
                            Array.Copy(samples, introDuration, loopSamples, 0, loopSamples.Length);
                            Array.Resize(ref samples, introDuration);

                            var channelIntroFileName = Utils.AddFileSuffix(filename, "_" + song.Channels[channelIdx].ShortName + "_Intro");
                            var channelLoopFileName  = Utils.AddFileSuffix(filename, "_" + song.Channels[channelIdx].ShortName);

                            function(samples, 1, channelIntroFileName);
                            function(loopSamples, 1, channelLoopFileName);
                        }
                        else
                        {
                            var channelFileName = Utils.AddFileSuffix(filename, "_" + song.Channels[channelIdx].ShortName);
                            function(samples, 1, channelFileName);
                        }
                    }
                }
            }
            else
            {
                var numChannels = 1;
                var samples     = (short[])null;

                if (stereo)
                {
                    // Get all the samples for all channels.
                    var channelSamples   = new short[song.Channels.Length][];
                    var numStereoSamples = 0;

                    for (int channelIdx = 0; channelIdx < song.Channels.Length; channelIdx++)
                    {
                        var channelBit = 1 << channelIdx;
                        if ((channelBit & channelMask) != 0)
                        {
                            var player = new WavPlayer(sampleRate, loopCount, channelBit, NesApu.TND_MODE_SEPARATE);
                            channelSamples[channelIdx] = player.GetSongSamples(song, project.PalMode, duration);
                            numStereoSamples           = Math.Max(numStereoSamples, channelSamples[channelIdx].Length);
                        }
                    }

                    // Mix and interleave samples.
                    samples = new short[numStereoSamples * 2];

                    for (int i = 0; i < numStereoSamples; i++)
                    {
                        float l = 0;
                        float r = 0;

                        for (int j = 0; j < channelSamples.Length; j++)
                        {
                            if (channelSamples[j] != null)
                            {
                                float sl = 1.0f - Utils.Clamp(2.0f * (pan[j] - 0.5f), 0.0f, 1.0f);
                                float sr = 1.0f - Utils.Clamp(-2.0f * (pan[j] - 0.5f), 0.0f, 1.0f);

                                l += channelSamples[j][i] * sl;
                                r += channelSamples[j][i] * sr;
                            }
                        }

                        samples[i * 2 + 0] = (short)Utils.Clamp((int)Math.Round(l), short.MinValue, short.MaxValue);
                        samples[i * 2 + 1] = (short)Utils.Clamp((int)Math.Round(r), short.MinValue, short.MaxValue);
                    }

                    numChannels    = 2;
                    introDuration *= 2;
                }
                else
                {
                    var player = new WavPlayer(sampleRate, loopCount, channelMask);
                    samples = player.GetSongSamples(song, project.PalMode, duration);
                }

                if (introDuration > 0)
                {
                    var loopSamples = new short[samples.Length - introDuration];
                    Array.Copy(samples, introDuration, loopSamples, 0, loopSamples.Length);
                    Array.Resize(ref samples, introDuration);

                    var introFileName = Utils.AddFileSuffix(filename, "_Intro");
                    var loopFileName  = filename;

                    function(samples, numChannels, introFileName);
                    function(loopSamples, numChannels, loopFileName);
                }
                else
                {
                    function(samples, numChannels, filename);
                }
            }
        }