Как воспроизводить несколько источников звука одновременно в Silverlight - PullRequest
0 голосов
/ 05 мая 2010

Я хочу одновременно воспроизводить несколько источников звука в 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();
    }
  }

Треки воспроизводятся каждый раз по-разному и не одновременно, как должны (как один звук).

Добавление : Я проверил код из ответа Бобби.

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)

Сложение3 : Опыт работы с маркерами

Я имел опыт работы с Time in TimeLineMarker, и следующий код работает на моем компьютере достаточно хорошо

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 голосов
/ 05 мая 2010

Поскольку вы используете FileStreams для загрузки файлов, я предполагаю, что вы читаете их не через Интернет, а из локальной файловой системы.

Вы не хотите вызывать Play () из обработчиков тиков таймера, если в этом нет необходимости - то есть для первого ME.

Кроме того, вы запускаете таймер каждую миллисекунду, а не секунду (не уверен, действительно ли вы это хотели сказать). Если вы хотите пнуть вторую игру через 2 секунды после первой, попробуйте вызвать меня. Play (), затем создайте таймер для запуска с интервалом в 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 помещаются в очередь Диспетчера как и другие операции. Когда Операция DispatcherTimer выполняется зависит от других рабочих мест в Очередь и их приоритеты. (MSDN: DispatcherTimer)

Может быть очень трудно добиться идеальной синхронизации в многопоточных контекстах. DispatcherTimer будет помещать вызов обработчику в диспетчере пользовательского интерфейса, когда интервал тикает, но это не значит, что он будет немедленно вызван , Единственное, что может стоить в этот момент - настроить DispatcherPriority (например, «Отправить» (самый высокий)).

Сделайте это с помощью этого конструктора:

public DispatcherTimer(
    DispatcherPriority priority
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...