2016-06-11 5 views
0

Я использую NAudio с «Огнем и забыть Воспроизведение аудио с NAudio» учебник (спасибо Mark для этой удивительной полезности!), Как написано здесь: http://mark-dot-net.blogspot.nl/2014/02/fire-and-forget-audio-playback-with.htmlNAudio: Использование MixingSampleProvider правильно с VolumeSampleProvider

мне удалось для добавления к нему VolumeSampleProvider с использованием MixingSampleProvider в качестве входных данных. Однако, когда я сейчас воспроизвожу два звука сразу друг за другом, первый звук всегда получает и второй том, даже если первый уже играет.

Итак, мой вопрос: как добавить звуки с индивидуальным объемом звука?

Это то, что я использовал:

 mixer = new MixingSampleProvider(waveformat); 
     mixer.ReadFully = true; 
     volumeProvider = new VolumeSampleProvider(mixer); 
     panProvider = new PanningSampleProvider(volumeProvider); 
     outputDevice.Init(panProvider); 
     outputDevice.Play(); 

ответ

1

Я не 100% уверен, что вы просите, и я не знаю, если вы это уже решена, но вот мой взгляд на это.

ISampleProvider объекты играют в игру «Пропустить доллар» к их источнику ISampleProvider через метод Read(). В конце концов, кто-то делает фактическое чтение аудио байтов. Индивидуальные классы ISampleProvider делают все, что они делают с байтами.

MixingSampleProvider, например, принимает N источников звука ... те смешиваются. Когда вызывается Read(), он выполняет итерацию источников звука и считывает count байт от каждого.

Передача его в VolumeSampleProvider обрабатывает все байты (из этих различных источников) в качестве группы ... он говорит:

buffer[offset+n] *= volume; 

Это собирается скорректировать байты через борт ... так что каждый байт корректируется в буфере с помощью множителя volume;

PanningSampleProvider просто предоставляет множитель для стереозвука и соответственно регулирует байты, делая то же самое, что и VolumeSampleProvider.

Если вы хотите индивидуально обрабатывать тома источника звука, вам необходимо обработать то, что находится выше по потоку от MixingSampleProvider. По существу, вещи, которые вы передаете MixingSampleProvider, должны иметь возможность самостоятельно регулировать объем.

Если вы передали пучок SampleChannel объектов на ваш MixingSampleProvider ..., вы можете выполнить независимую регулировку громкости. Класс Samplechannel включает объект VolumeSampleProvider и предоставляет свойство Volume, которое позволяет установить громкость на этом объекте VolumeSampleProvider.

SampleChannel также включает в себя MeteringSampleProvider, который обеспечивает отчетность о максимальном размере выборки в течение заданного периода. Он вызывает событие, которое дает вам массив этих значений, по одному на канал.

+0

Дорогой Мэтт, спасибо за этот ответ. Мне нужно будет поближе познакомиться с классом SampleChannel, чтобы выяснить, могу ли я заставить его работать. Прошло более года с тех пор, как я работал над этим кодом, поэтому не думаю, что скоро узнаю. Приветствую. – Paul

0

Я понял (благодаря своей способности), что единственный способ выполнить эту работу состоит в том, чтобы оставить микшер в одиночку и отдельно настроить панорамирование и объем каждого CachedSound, прежде чем добавлять его в микшер. Поэтому мне пришлось переписать CachedSoundProvider, используя панорамирование и объем в качестве дополнительных входных параметров.

Это новый конструктор:

public CachedSoundSampleProvider(CachedSound cachedSound, float volume = 1, float pan = 0) 
    { 
     this.cachedSound = cachedSound; 
     LeftVolume = volume * (0.5f - pan/2); 
     RightVolume = volume * (0.5f + pan/2); 
    } 

И это новый Read() функция:

public int Read(float[] buffer, int offset, int count) 
    { 
     long availableSamples = cachedSound.AudioData.Length - position; 
     long samplesToCopy = Math.Min(availableSamples, count); 

     int destOffset = offset; 
     for (int sourceSample = 0; sourceSample < samplesToCopy; sourceSample += 2) 
     { 
      float outL = cachedSound.AudioData[position + sourceSample + 0]; 
      float outR = cachedSound.AudioData[position + sourceSample + 1]; 

      buffer[destOffset + 0] = outL * LeftVolume; 
      buffer[destOffset + 1] = outR * RightVolume; 
      destOffset += 2; 
     } 

     position += samplesToCopy; 
     return (int)samplesToCopy; 
    }