Пример #1
0
        public int Read(float[] buffer, int offset, int count)
        {
            //if (audioInput.BufferedBytes < count && decoder != null)              //Packet loss concealment. Don't use as is - need to check the logic of any audioInput.BufferedBytes == 0 usage
            //{
            //    decoder.Decode(null, 0, 0, decoderShortBuffer, 0, frameCount, false);
            //    //Optimise the following at some point.
            //    for (int i = 0; i < 960; i++)
            //    {
            //        var bytes = BitConverter.GetBytes(decoderShortBuffer[i]);
            //        decoderByteBuffer[i * 2] = bytes[0];
            //        decoderByteBuffer[(i * 2) + 1] = bytes[1];
            //    }
            //    audioInput.AddSamples(decoderByteBuffer, 0, frameCount * 2);
            //}
            var samples = mixer.Read(buffer, offset, count);

            if (InUse && lastPacketLatch && audioInput.BufferedBytes == 0)
            {
                Idle();
                lastPacketLatch = false;
            }

            if (InUse && !underflow && audioInput.BufferedBytes == 0)
            {
                Debug.WriteLine("[" + Callsign + "] [Delay++]");
                CallsignDelayCache.Instance.Underflow(Callsign);
                underflow = true;
            }

            return(samples);
        }
Пример #2
0
        public void WithReadFullySetNoInputsReturnsSampleCountRequested()
        {
            var msp = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2));

            msp.ReadFully = true;
            var buffer = new float[1000];

            Assert.AreEqual(buffer.Length, msp.Read(buffer, 0, buffer.Length));
        }
Пример #3
0
        public void WithOneInputReturnsSamplesReadIfNotEnoughToFullyRead()
        {
            var input1 = new TestSampleProvider(44100, 2, 800);
            var msp    = new MixingSampleProvider(new[] { input1 });
            var buffer = new float[1000];

            Assert.AreEqual(800, msp.Read(buffer, 0, buffer.Length));
            // randomly check one value
            Assert.AreEqual(567, buffer[567]);
        }
Пример #4
0
        public void WithOneInputReadsToTheEnd()
        {
            var input1 = new TestSampleProvider(44100, 2, 2000);
            var msp    = new MixingSampleProvider(new [] { input1 });
            var buffer = new float[1000];

            Assert.AreEqual(buffer.Length, msp.Read(buffer, 0, buffer.Length));
            // randomly check one value
            Assert.AreEqual(567, buffer[567]);
        }
Пример #5
0
        public void MixToFile(string filename, bool applyReplayGain)
        {
            Console.WriteLine("Mixing per-channel data...");
            Console.WriteLine("Computing ReplayGain...");
            // Mix the audio. We should probably not be re-reading it here... we could do this in the same pass as loading.
            foreach (var reader in _data.Select(channel => channel.WavReader))
            {
                reader.Position = 0;
            }

            if (applyReplayGain)
            {
                // We read it in a second at a time, to calculate Replay Gains
                var mixer      = new MixingSampleProvider(_data.Select(channel => channel.WavReader.ToSampleProvider().ToStereo()));
                var buffer     = new float[mixer.WaveFormat.SampleRate * 2];
                var replayGain = new TrackGain(SampleRate);
                for (;;)
                {
                    int numRead = mixer.Read(buffer, 0, buffer.Length);
                    if (numRead == 0)
                    {
                        break;
                    }

                    // And analyze
                    replayGain.AnalyzeSamples(buffer, numRead);
                }

                // The +3 is to make it at "YouTube loudness", which is a lot louder than ReplayGain defaults to.
                var gain = replayGain.GetGain() + 3;

                Console.WriteLine($"Applying ReplayGain ({gain:N} dB) and saving to {filename}");

                // Reset the readers again
                foreach (var reader in _data.Select(channel => channel.WavReader))
                {
                    reader.Position = 0;
                }

                mixer = new MixingSampleProvider(_data.Select(channel => channel.WavReader.ToSampleProvider().ToStereo()));
                var amplifier = new VolumeSampleProvider(mixer)
                {
                    Volume = (float)Math.Pow(10, gain / 20)
                };
                WaveFileWriter.CreateWaveFile(filename, amplifier.ToWaveProvider());
            }
            else
            {
                var mixer = new MixingSampleProvider(_data.Select(channel => channel.WavReader.ToSampleProvider().ToStereo()));
                WaveFileWriter.CreateWaveFile(filename, mixer.ToWaveProvider());
            }
        }
        public int Read(float[] buffer, int offset, int count)
        {
            foreach (var mixerInput in Sequencer.GetNextMixerInputs(count))
            {
                mixer.AddMixerInput(mixerInput);
            }

            // now we just need to read from the mixer
            var samplesRead = mixer.Read(buffer, offset, count);

            while (samplesRead < count)
            {
                buffer[samplesRead++] = 0;
            }
            return(samplesRead);
        }
Пример #7
0
        public void FullyReadCausesPartialBufferToBeZeroedOut()
        {
            var input1 = new TestSampleProvider(44100, 2, 800);
            var msp    = new MixingSampleProvider(new[] { input1 });

            msp.ReadFully = true;
            // of 1000 floats of value 9999
            var buffer = Enumerable.Range(1, 1000).Select(n => 9999f).ToArray();

            Assert.AreEqual(buffer.Length, msp.Read(buffer, 0, buffer.Length));
            // check we get 800 samples, followed by zeroed out data
            Assert.AreEqual(567f, buffer[567]);
            Assert.AreEqual(799f, buffer[799]);
            Assert.AreEqual(0, buffer[800]);
            Assert.AreEqual(0, buffer[999]);
        }
Пример #8
0
        public int Read(float[] buffer, int offset, int count)
        {
            foreach (var mixerInput in sequencer.GetNextMixerInputs(count))
            {
                //mixerInput = new MonoToStereoSampleProvider(mixerInput);
                mixer.AddMixerInput(mixerInput);
            }

            // now we just need to read from the mixer
            var samplesRead = mixer.Read(buffer, offset, count);

            if (samplesRead < count)
            {
                Array.Clear(buffer, offset + samplesRead, count - samplesRead);
                samplesRead = count;
            }
            return(samplesRead);
        }
Пример #9
0
        public void MixerInputEndedInvoked()
        {
            var             input1     = new TestSampleProvider(44100, 2, 8000);
            var             input2     = new TestSampleProvider(44100, 2, 800);
            var             msp        = new MixingSampleProvider(new[] { input1, input2 });
            ISampleProvider endedInput = null;

            msp.MixerInputEnded += (s, a) =>
            {
                Assert.IsNull(endedInput);
                endedInput = a.SampleProvider;
            };
            // buffer of 1000 floats of value 9999
            var buffer = Enumerable.Range(1, 1000).Select(n => 9999f).ToArray();

            Assert.AreEqual(buffer.Length, msp.Read(buffer, 0, buffer.Length));
            Assert.AreSame(input2, endedInput);
            Assert.AreEqual(1, msp.MixerInputs.Count());
        }
Пример #10
0
        /** <summary>Record the beat to a wav file.</summary>
         * <param name="seconds">Number of seconds to record</param>
         * <param name="fileName">Name of file to record to</param>
         */
        public void ExportAsWav(double seconds, string fileName)
        {
            fileName = ValidateFileName(fileName);
            if (fileName.Substring(fileName.Length - 4).ToLower() != ".wav") // append wav extension
            {
                fileName += ".wav";
            }
            Writer = new WaveFileWriter(fileName, Mixer.WaveFormat);

            // if no seconds param, use the complete cycle
            if (seconds == 0)
            {
                seconds = GetQuartersForCompleteCycle() * (60d / Tempo);
            }

            int bytesToRec = (int)(Mixer.WaveFormat.AverageBytesPerSecond / 4 * seconds);

            // align bytes
            bytesToRec -= bytesToRec % 4;

            int bytesRecorded = 0;
            int cycleSize     = 1280;

            while (bytesRecorded < bytesToRec)
            {
                int chunk = Math.Min(cycleSize, bytesToRec - bytesRecorded);

                float[] buffer = new float[chunk];
                Mixer.Read(buffer, 0, chunk);
                Writer.WriteSamples(buffer, 0, chunk);
                bytesRecorded += chunk;
                buffer         = null;
            }

            Layers.ForEach(x => x.Reset());

            Writer.Dispose();
        }
        public int Read(float[] buffer, int offset, int count)
        {
            int result = 0;

            try
            {
                result = _mixer.Read(buffer, offset, count);

                if (count > 0 && IsRecording)
                {
                    //write samples to file
                    _writer.WriteSamples(buffer, offset, count);
                }
            }
            catch (NullReferenceException) { }

            if (count == 0)
            {
                Dispose();
            }

            return(result);
        }
Пример #12
0
        public void WithNoInputsFirstReadReturnsNoSamples()
        {
            var msp = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2));

            Assert.AreEqual(0, msp.Read(new float[1000], 0, 1000));
        }
Пример #13
0
        private static void Go(string filename, ICollection <string> filenames, int width, int height, int fps,
                               string background,
                               string logo, string vgmFile, int previewFrameskip, float highPassFrequency, float scale,
                               Type triggerAlgorithm, int viewSamples, int numColumns, string ffMpegPath, string ffMpegExtraArgs,
                               string masterAudioFilename, float autoScale, Color gridColor, float gridWidth, bool gridOuter,
                               Color zeroLineColor, float zeroLineWidth, float lineWidth)
        {
            filename = Path.GetFullPath(filename);
            var waitForm = new WaitForm();

            waitForm.Show();

            int sampleRate;

            using (var reader = new WaveFileReader(filenames.First()))
            {
                sampleRate = reader.WaveFormat.SampleRate;
            }

            // ReSharper disable once CompareOfFloatsByEqualityOperator
            int stepsPerFile  = 1 + (highPassFrequency > 0 ? 1 : 0) + 2;
            int totalProgress = filenames.Count * stepsPerFile;
            int progress      = 0;

            var loadTask = Task.Run(() =>
            {
                // Do a parallel read of all files
                var channels = filenames.AsParallel().Select((wavFilename, channelIndex) =>
                {
                    var reader = new WaveFileReader(wavFilename);
                    var buffer = new float[reader.SampleCount];

                    // We read the file and convert to mono
                    reader.ToSampleProvider().ToMono().Read(buffer, 0, (int)reader.SampleCount);
                    Interlocked.Increment(ref progress);

                    // We don't care about ones where the samples are all equal
                    // ReSharper disable once CompareOfFloatsByEqualityOperator
                    if (buffer.Length == 0 || buffer.All(s => s == buffer[0]))
                    {
                        // So we skip steps here
                        reader.Dispose();
                        Interlocked.Add(ref progress, stepsPerFile - 1);
                        return(null);
                    }

                    if (highPassFrequency > 0)
                    {
                        // Apply the high pass filter
                        var filter = BiQuadFilter.HighPassFilter(reader.WaveFormat.SampleRate, highPassFrequency, 1);
                        for (int i = 0; i < buffer.Length; ++i)
                        {
                            buffer[i] = filter.Transform(buffer[i]);
                        }

                        Interlocked.Increment(ref progress);
                    }

                    float max = float.MinValue;
                    foreach (var sample in buffer)
                    {
                        max = Math.Max(max, Math.Abs(sample));
                    }

                    return(new { Data = buffer, WavReader = reader, Max = max });
                }).Where(ch => ch != null).ToList();

                if (autoScale > 0 || scale > 1)
                {
                    // Calculate the multiplier
                    float multiplier = 1.0f;
                    if (autoScale > 0)
                    {
                        multiplier = autoScale / channels.Max(channel => channel.Max);
                    }

                    if (scale > 1)
                    {
                        multiplier *= scale;
                    }

                    // ...and we apply it
                    channels.AsParallel().Select(channel => channel.Data).ForAll(samples =>
                    {
                        for (int i = 0; i < samples.Length; ++i)
                        {
                            samples[i] *= multiplier;
                        }

                        Interlocked.Increment(ref progress);
                    });
                }

                return(channels.ToList());
            });

            while (!loadTask.IsCompleted)
            {
                Application.DoEvents();
                Thread.Sleep(1);
                waitForm.Progress("Reading data...", (double)progress / totalProgress);
            }

            var voiceData = loadTask.Result.Select(channel => channel.Data).ToList();

            waitForm.Close();

            // Emit normalised data to a WAV file for later mixing
            if (masterAudioFilename == null)
            {
                // Generate a temp filename
                masterAudioFilename = filename + ".wav";
                // Mix the audio. We should probably not be re-reading it here... should do this in one pass.
                foreach (var reader in loadTask.Result.Select(channel => channel.WavReader))
                {
                    reader.Position = 0;
                }
                var mixer     = new MixingSampleProvider(loadTask.Result.Select(channel => channel.WavReader.ToSampleProvider()));
                var length    = (int)loadTask.Result.Max(channel => channel.WavReader.SampleCount);
                var mixedData = new float[length * mixer.WaveFormat.Channels];
                mixer.Read(mixedData, 0, mixedData.Length);
                // Then we want to deinterleave it
                var leftChannel  = new float[length];
                var rightChannel = new float[length];
                for (int i = 0; i < length; ++i)
                {
                    leftChannel[i]  = mixedData[i * 2];
                    rightChannel[i] = mixedData[i * 2 + 1];
                }
                // Then Replay Gain it
                // The +3 is to make it at "YouTube loudness", which is a lot louder than ReplayGain defaults to.
                var replayGain = new TrackGain(sampleRate);
                replayGain.AnalyzeSamples(leftChannel, rightChannel);
                float multiplier = (float)Math.Pow(10, (replayGain.GetGain() + 3) / 20);
                Debug.WriteLine($"ReplayGain multiplier is {multiplier}");
                // And apply it
                for (int i = 0; i < mixedData.Length; ++i)
                {
                    mixedData[i] *= multiplier;
                }
                WaveFileWriter.CreateWaveFile(
                    masterAudioFilename,
                    new FloatArraySampleProvider(mixedData, sampleRate).ToWaveProvider());
            }

            var backgroundImage = new BackgroundRenderer(width, height, Color.Black);

            if (background != null)
            {
                using (var bm = Image.FromFile(background))
                {
                    backgroundImage.Add(new ImageInfo(bm, ContentAlignment.MiddleCenter, true, DockStyle.None, 0.5f));
                }
            }

            if (logo != null)
            {
                using (var bm = Image.FromFile(logo))
                {
                    backgroundImage.Add(new ImageInfo(bm, ContentAlignment.BottomRight, false, DockStyle.None, 1));
                }
            }

            if (vgmFile != null)
            {
                var gd3     = Gd3Tag.LoadFromVgm(vgmFile);
                var gd3Text = gd3.ToString();
                if (gd3Text.Length > 0)
                {
                    backgroundImage.Add(new TextInfo(gd3Text, "Tahoma", 16, ContentAlignment.BottomLeft, FontStyle.Regular,
                                                     DockStyle.Bottom, Color.White));
                }
            }

            var renderer = new WaveformRenderer
            {
                BackgroundImage            = backgroundImage.Image,
                Columns                    = numColumns,
                FramesPerSecond            = fps,
                Width                      = width,
                Height                     = height,
                SamplingRate               = sampleRate,
                RenderedLineWidthInSamples = viewSamples,
                RenderingBounds            = backgroundImage.WaveArea
            };

            if (gridColor != Color.Empty && gridWidth > 0)
            {
                renderer.Grid = new WaveformRenderer.GridConfig
                {
                    Color      = gridColor,
                    Width      = gridWidth,
                    DrawBorder = gridOuter
                };
            }

            if (zeroLineColor != Color.Empty && zeroLineWidth > 0)
            {
                renderer.ZeroLine = new WaveformRenderer.ZeroLineConfig
                {
                    Color = zeroLineColor,
                    Width = zeroLineWidth
                };
            }

            foreach (var channel in voiceData)
            {
                renderer.AddChannel(new Channel(channel, Color.White, lineWidth, "Hello world", Activator.CreateInstance(triggerAlgorithm) as ITriggerAlgorithm, 0));
            }

            var outputs = new List <IGraphicsOutput>();

            if (ffMpegPath != null)
            {
                outputs.Add(new FfmpegOutput(ffMpegPath, filename, width, height, fps, ffMpegExtraArgs, masterAudioFilename));
            }

            if (previewFrameskip > 0)
            {
                outputs.Add(new PreviewOutput(previewFrameskip));
            }

            try
            {
                renderer.Render(outputs);
            }
            catch (Exception)
            {
                // Should mean it was cancelled
            }
            finally
            {
                foreach (var graphicsOutput in outputs)
                {
                    graphicsOutput.Dispose();
                }
            }
        }
 public int Read(float[] buffer, int offset, int count)
 {
     return(mixer.Read(buffer, offset, count));
 }