如何在Silverlight中同时播放多个音频源

时间:2010-05-05 16:26:22

标签: silverlight audio

我想在Silverlight中同时播放多个音频源。 所以我在Silverlight 4中创建了一个原型,该原型应该播放两个mp3文件,其中包含相同的滴答声,并且间隔为1秒。因此,如果这些文件与任何整个第二个偏移(0和1,0和2,1和1秒等)一起播放,则必须将这些文件作为一个声音发声。

我的原型我使用了两个MediaElement(me和me2)对象。

DateTime startTime;

private void Play_Clicked(object sender, RoutedEventArgs e) {
  me.SetSource(new FileStream(file1), FileMode.Open)));
  me2.SetSource(new FileStream(file2), FileMode.Open)));
  var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1) };
  timer.Tick += RefreshData;
  timer.Start();
}

第一个文件应在00:00秒播放。第二次是00:02秒。

void RefreshData(object sender, EventArgs e) {
    if(me.CurrentState != MediaElementState.Playing) {
      startTime = DateTime.Now;
      me.Play();
      return;
    }

    var elapsed = DateTime.Now - startTime;
    if(me2.CurrentState != MediaElementState.Playing && 
      elapsed >= TimeSpan.FromSeconds(2)) {
      me2.Play();
      ((DispatcherTimer)sender).Stop();
    }
  }

每次播放的曲目都是不同的,而不是同时播放(作为一种声音)。

加成: 我已经测试了Bobby答案的代码。

private void Play_Clicked(object sender, RoutedEventArgs e) { 
  me.SetSource(new FileStream(file1), FileMode.Open))); 
  me2.SetSource(new FileStream(file2), FileMode.Open)));
  // This code plays well enough.
  // me.Play(); 
  // me2.Play();

  // But adding the 2 second offset using the timer, 
  // they play no simultaneous.
  var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; 
  timer.Tick += (source, arg) => { 
    me2.Play(); 
    ((DispatcherTimer)source).Stop(); 
  };
  timer.Start();
}

是否可以仅使用一个MediaElement或任何可以播放多个来源的MediaStreamSource实现来一起播放它们?

加法2 :调试播放位置

添加调试信息明确地表明,我与计时器的滴答声相比起了不同的作用

...
me2.Play();
System.Diagnostics.Debug.WriteLine(
  me.Position.TotalMilliseconds + " -> " + me2.Position.TotalMilliseconds);
// 1820 -> 0 (but not 2000 -> 0)

Addition3 :有标记的经验

我在TimeLineMarker中遇到过Time,并且以下代码在我的电脑上运行良好

me.Markers.Clear();
me.Markers.Add(new TimelineMarker { Time = TimeSpan.FromMilliseconds(1892) });
me.MarkerReached += (source, args) => {
                            me2.Play();
                            me.Markers.Clear();
                          };
me.Play();

1 个答案:

答案 0 :(得分:0)

由于您正在使用FileStreams来加载文件,我假设您不是通过Web读取它们,而是从本地文件系统读取它们。

如果没有必要,你不想从计时器滴答处理程序调用Play() - 即第一个ME。

此外,你每隔毫秒运行一次计时器,而不是第二次(不确定这实际上是你的意思)。如果你想在第一次播放后2秒钟踢第二次播放,那么尝试呼叫我。播放()然后创建定时器以2秒的间隔运行,它所做的只是调用me2.Play()并自行停止

此外,根据上面的评论,要查看行为是否合理确定(充分同步),请尝试运行几次,看看原则上它们是否可以很好地一起玩。

private void Play_Clicked(object sender, RoutedEventArgs e) {
  me.SetSource(new FileStream(file1), FileMode.Open)));
  me2.SetSource(new FileStream(file2), FileMode.Open)));
  me.Play();
  me2.Play();
}

..编辑:

  

不保证定时器可以执行   恰好在时间间隔发生时,   但他们保证不会执行   在时间间隔发生之前。这个   是因为DispatcherTimer操作   放在Dispatcher队列中   像其他操作。当。。。的时候   DispatcherTimer操作执行是   依赖于其他工作   队列及其优先级。 (msdn : DispatcherTimer)

在多线程上下文中实现完美同步可能非常困难。当间隔时间点时,DispatcherTimer将调用UI Dispatcher中的处理程序,但这并不意味着它会立即被调用。此时唯一可能值得一提的是调整DispatcherPriority(例如调整为'发送'(最高))。

使用此构造函数执行此操作:

public DispatcherTimer(
    DispatcherPriority priority
)