Ejemplo n.º 1
0
        public WaveSample(WaveAudioFormat sampleFormat, int sampleValue)
        {
            this.SampleFormat = sampleFormat;
            // Initialize the Sample byte array to be the size of ===>   FULL_SAMPLE = [CHANNELS x CHANNEL_SIZE]
            this.Sample = new byte[this.SampleFormat.BytesPerSample * this.SampleFormat.ChannelCount];
            // Clip the provided sample value to constrain it to an acceptable audio value, then set it on the object.
            this.ClipSample(ref sampleValue);
            this.SampleValue = sampleValue;
            // Set the sample values equal across all channels on instantiation.
            int discardClipping = sampleValue; //don't care about the ref, just can't use a `this`

            this.SetAllChannelValues(ref discardClipping);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Static method to combine lists of multiple WaveSample objects into a single WaveSample.
        /// </summary>
        /// <returns>A single WaveSample representing the mixing of all provided samples.</returns>
        public static WaveSample CombineWaveSamples(WaveAudioFormat audioFormat, params WaveSample[] samples)
        {
            var combinedSamples = new int[audioFormat.ChannelCount];
            var newSample       = new WaveSample(audioFormat, 0);

            // For each sample, add the channel values onto the aggregate total.
            foreach (WaveSample smp in samples)
            {
                int[] channelValues = smp.GetAllChannelValues();
                for (int i = 0; i < channelValues.Length; i++)
                {
                    combinedSamples[i] += channelValues[i];
                }
            }
            // Now, set the new sample's channel values to be mapped to the final totals for each channel.
            for (int channel = 0; channel < combinedSamples.Length; channel++)
            {
                newSample.SetChannelValue(channel, ref combinedSamples[channel]);
            }
            return(newSample);
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Mixes different audio streams, represented as lists of WaveSample objects and their corresponding amplitude weighting, into an overall stream of sound.
 /// The resulting stream duration will equal the longest stream in the "samples" list, so varying stream durations can be easily mixed together; simply note that
 /// the final stream starts all component streams at the "0" duration mark.
 /// </summary>
 /// <param name="audioFormat">The format used for aggregating all stream data. This MUST be the same format used across all streams -- any stream NOT matching the provided format will be DISCARDED from the final result.</param>
 /// <param name="peakOutputAmplitudePercentage">A scaling percentage for the final stream's peak output amplitude. Defaults to 100%, which represents no change in the mixed stream's volume.</param>
 /// <param name="componentStreamCollection">Any amount of tuples consisting of the amplitude (volume) weighting within all mixed samples, and the audio sample itself. NOTE: The weighting is NOT a percentage value!</param>
 /// <returns>An audio stream (stream of samples) equal to the combination of all provided component streams at their given amplitude weightings.</returns>
 /// <see cref="WaveSample"/>
 public static List <WaveSample> MixSamples(
     WaveAudioFormat audioFormat,
     double peakOutputAmplitudePercentage = 100.0,
     params (double, List <WaveSample>)[] componentStreamCollection
Ejemplo n.º 4
0
        /// <summary>
        /// Plays the given sequence of Morse symbols using the internal WaveGenerator module. This "queues"
        /// audio to play, rather than relying on Thread.Sleep to gap the DITs/DAHs (symbols) from each other.
        /// </summary>
        /// <param name="morseStream">The sequence of MorseSymbol items to be played.</param>
        /// <param name="cancelToken">Tracks whether or not this operation should be cancelled.</param>
        /// <see cref="MorseSymbol"/>
        /// <see cref="WaveGenerator"/>
        public void PlayWaveStream(List <MorseSymbol> morseStream, CancellationToken cancelToken)
        {
            // First, get the audio constructed.
            var wavFormat      = new WaveAudioFormat(16000, 16, 1); //doesn't need to be the most high-def sound
            var wavType        = WaveGenerator.WaveType.SINE;       //always a SINE wave (for now; configurable later)
            var streamSequence = new List <WaveSample>();           //container for the resulting stream of samples

            streamSequence.Add(new WaveSample(wavFormat, 0));       //initialize the stream with at least ONE empty sample
            ////Loading icon??
            foreach (MorseSymbol sym in morseStream)
            {
                if (cancelToken != null && cancelToken.IsCancellationRequested)
                {
                    return;
                }
                if (sym.hasSound())
                {
                    WaveAudioTools.AppendSamples(
                        ref streamSequence,
                        (100.0, WaveGenerator.CreateNewWave(wavFormat, wavType, this.Gain * 100.0, sym.getDuration() / 1000.0, this.Frequency))
                        );
                }
                else
                {
                    WaveAudioTools.AppendSamples(
                        ref streamSequence,
                        (100.0, WaveGenerator.CreateEmptySpace(wavFormat, sym.getDuration() / 1000.0))
                        );
                }
            }
            // Construct the output stream in WAV format.
            using var finalStream = new WaveStream(streamSequence);
            ////Release loading icon??
            // Then, play the stream, while at the same time updating the text stream to sync as
            //   best as possible to the currently-playing audio.
            // Define a lambda of sorts for updating the live text view for transmissions.
            Action <MorseSymbol> updateTextStream = s => {
                Program.mainForm.Invoke((System.Windows.Forms.MethodInvoker) delegate {
                    Program.txLiveView.AppendText(s.getRepresentation());
                });
            };

            // Construct the player.
            using var queuedStream = new System.IO.MemoryStream(finalStream.GetRawWaveStream());
            using var mediaPlayer  = new System.Media.SoundPlayer(queuedStream);
            //...and...... GO!
            mediaPlayer.Play();
            int infiniteLoopPrevention = 0;

            // Give the player 2s to load the stream.
            while (!mediaPlayer.IsLoadCompleted && infiniteLoopPrevention < 100)
            {
                if (cancelToken != null && cancelToken.IsCancellationRequested)
                {
                    mediaPlayer.Stop();
                    mediaPlayer.Dispose();
                    break;
                }
                Thread.Sleep(20);
                infiniteLoopPrevention++;
            }
            // During stream playback, send out the symbols.
            for (int index = 0; index < morseStream.Count; index++)
            {
                var sym = morseStream[index];
                if (cancelToken != null && cancelToken.IsCancellationRequested)
                {
                    mediaPlayer.Stop();
                    mediaPlayer.Dispose();
                    break;
                }
                //Thread.Sleep((int)sym.getDuration());
                Task.Delay((int)sym.getDuration()).Wait();
                updateTextStream(sym);
                // Handle progress bar updates.
                Program.mainForm.Invoke((System.Windows.Forms.MethodInvoker) delegate {
                    try { Program.pbTXProgress.Value = (((index * 100) / morseStream.Count) + 1); } catch { }
                });
            }
        }