How Can I Play without file?

2019-07-16 03:57发布

问题:

I would like to play a ring alert without loading/streaming it from file.

Can I embed it's signal or tone in code? I am using NAudio.

My purpose is improving performance by removing IO actions.

I don't want to use embedded resources. Only I want generate ring alert in code.

回答1:

With NAudio you have these options to do that:

  • To play a file from a stream (in memory). You have code for this in other answers, actually you do not even need NAudio for this task 'cause System.Media.SoundPlayer is enough).
  • To generate a signal that will be played (without the need to save it somewhere).
  • To play a string of sound commands (somehow as we all did on good old times with play in BASIC).

Generate signal

The example for the first case comes from a Charles Petzold article on MSDN (but take a look to NAudio documentation too):

class SineWaveOscillator : WaveProvider16 {
  double phaseAngle;

  public SineWaveOscillator(int sampleRate): 
    base(sampleRate, 1) {
  }

  public double Frequency { set; get; }
  public short Amplitude { set; get; }

  public override int Read(short[] buffer, int offset, 
    int sampleCount) {

    for (int index = 0; index < sampleCount; index++) {
      buffer[offset + index] = 
        (short)(Amplitude * Math.Sin(phaseAngle));
      phaseAngle += 
        2 * Math.PI * Frequency / WaveFormat.SampleRate;

      if (phaseAngle > 2 * Math.PI)
        phaseAngle -= 2 * Math.PI;
    }
    return sampleCount;
  }
}

Then code to play a tone is simple:

SineWaveOscillator osc = new SineWaveOscillator(44100);
osc.Frequency = 440;
osc.Amplitude = 8192;

WaveOut waveOut = new WaveOut();
waveOut.Init(osc);
waveOut.Play();

Play MIDI

For the second case (play a string of MIDI commands) take again a look to another Charles Petzold article. His MidiStringPlayer class offers everything you need (but you may need to strip out WPF code to use it where you want). Basic code to play MIDI with NAudio is:

using (MidiOut midiOut = new MidiOut(0))
{
    midiOut.Send(MidiMessage.StartNote(60, 127, 0).RawData);
    Thread.Sleep(1000);
    midiOut.Send(MidiMessage.StopNote(60, 0, 0).RawData);
    Thread.Sleep(1000);
}

If you really need to play notes from a string then you have to parse it, code is too long to post it here but in the link you'll find everything.



回答2:

for NAudio solution looks like this

Test.Properties.Resources.aaa this is path of mp3

using (var ms = new MemoryStream(Test.Properties.Resources.aaa))
using (var rdr = new NAudio.Wave.Mp3FileReader(ms))
using (var wavStream = NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(rdr))
using (var baStream = new NAudio.Wave.BlockAlignReductionStream(wavStream))
using (var waveOut = new NAudio.Wave.WaveOut(NAudio.Wave.WaveCallbackInfo.FunctionCallback())) {
   waveOut.Init(baStream);
   waveOut.Play();
   while (waveOut.PlaybackState == NAudio.Wave.PlaybackState.Playing) {
      System.Threading.Thread.Sleep(100);
   }
}


回答3:

You can embed any kind of file into your project by adding it to your resource.

In Visual Studio you can do that by Resources --> Add Resource --> Add existing file.

In my case I named the resource file mySound.

Then you can open the file by adding a SoundPlayer which takes the resource as parameter.

e.g.

    SoundPlayer mysoundplayer = new SoundPlayer(MyAssemblyName.Properties.Resources.mySound);
    mysoundplayer.Play();