Войти
ПрограммированиеФорумЗвук

XAudio2/X3DAudio SourceVoice регулировка громкости

#0
5:38, 3 июля 2011

Приветствую.

Вопрос заключается в следующем. Создал некоторую оболочку для всего этого аудио, т.е.
класс rSoundListener - который содержит XAUDIO_LISTENER
класс rSoundEmitter - содержит XAUDIO_EMITTER и IXAudioSourceVoice (ну еще и из файла звук туда засовывает)
класс rSoundController который содержит один объект rSoundEmitter, вектор с rSoundEmitter'ами и всякие XAudio2, IXAudioMasteringVoice и прочее.
Далее.

class rSoundEmitter {
public:
  rSoundEmitter(rSoundController*);
  ~rSoundEmitter();

  void        Move(D3DXVECTOR3);
  void        RelativeMove(D3DXVECTOR3);
  void        Update(float, BOOL Always = FALSE);
  void        SetVolumeLevel(float);
  float        GetVolumeLevel();
  float        SetRelativeVolume(float);
 // Тут еще много функций, но они к вопросу не относятся
private:
  X3DAUDIO_EMITTER  xEmi;
  rSoundController                *pCtrl;
  IXAudio2SourceVoice  *pSourceVoice;
 // Тут еще много переменных, но они к вопросу не относятся
};
// Функции
void rSoundEmitter::Update(float Delta, BOOL Always) // Пересчитывает положение источников звука (Always - это обновлять в любом 
// случае (при перемещении Listener'а)
{
  XAUDIO2_FILTER_PARAMETERS  xFP;
  D3DXVECTOR3    dVel;

  if( ((Position != xEmi.Position) && Delta) || Always)
  {
    dVel = (Position - xEmi.Position) / Delta;
    xEmi.Position = Position;
    xEmi.Velocity = dVel;
    X3DAudioCalculate(*pCtrl->GetHndl(), pCtrl->GetListener()->GetData(), &xEmi, X3DAUDIO_CALCULATE_MATRIX | 
                                   X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | 
                                   X3DAUDIO_CALCULATE_REDIRECT_TO_LFE, pCtrl->GetDSP());
    pSourceVoice->SetFrequencyRatio(pCtrl->GetDSP()->DopplerFactor); // GetDSP() возвращает dspSettings
    pSourceVoice->SetOutputMatrix(pCtrl->GetMV(), 1, pCtrl->GetChannelCnt(), pCtrl->GetDSP()->pMatrixCoefficients); // GetMV()
//  возвращает IXAudioMasteringVoice
    xFP.Type = LowPassFilter;
    xFP.Frequency = 2.0f * sinf(X3DAUDIO_PI/6.0f * pCtrl->GetDSP()->LPFDirectCoefficient);
    xFP.OneOverQ = 1.0f;
    pSourceVoice->SetOutputFilterParameters(pCtrl->GetMV(), &xFP);
    pSourceVoice->SetOutputMatrix(pCtrl->GetSV(), 1, 1, &pCtrl->GetDSP()->ReverbLevel); // GetSV() возвращает IXAudioSubmixVoice
  }
}

void rSoundEmitter::SetVolumeLevel(float Level)
{
  if( pSourceVoice )
  {
    pSourceVoice->SetVolume(Level);
  }
}

float rSoundEmitter::GetVolumeLevel()
{
  float  Rslt = 0;

  if( pSourceVoice )
    pSourceVoice->GetVolume(&Rslt);
  return Rslt;
}

float rSoundEmitter::SetRelativeVolume(float Level)
{
  float Lvl;

  Lvl = GetVolumeLevel();
  Lvl += Level;
  if( Lvl < -XAUDIO2_MAX_VOLUME_LEVEL )
    Lvl = -XAUDIO2_MAX_VOLUME_LEVEL;
  if( Lvl > XAUDIO2_MAX_VOLUME_LEVEL )
    Lvl = XAUDIO2_MAX_VOLUME_LEVEL;
  SetVolumeLevel(Level);
  return Lvl;
}

В общем громкость звука никакими силами не регулируется. Точнее, Вызываем один раз SetRelativeVolume с любым положительным аргументом,
громкость устанавливается в максимум, и больше ни на что не реагирует... (Хотя перемещение источников и приемников звука прекрасно работает.
Может быть, кто знает, в чем проблема?
Заранее спасибо :)


#1
12:16, 3 июля 2011

RedAngel
> В общем громкость звука никакими силами не регулируется. Точнее, Вызываем один
> раз SetRelativeVolume с любым положительным аргументом,
> громкость устанавливается в максимум, и больше ни на что не реагирует... (Хотя
> перемещение источников и приемников звука прекрасно работает.
> Может быть, кто знает, в чем проблема?

Ха, это же тебе XAudio, а не какой-то затрапезный API %)

А если серьезно:

1) Ты звуковые буферы в граф соединил?
2) Проверь коэффициенты для функции  X3DAudioCalculate(), как-то не видно чтобы ты их заполнял где-то, они скорее всего равны 0 и у тебя громкость = 0.
Поля в структуре X3DAUDIO_EMITTER не для красоты придуманы :)
Если ставишь флажок X3DAUDIO_CALCULATE_MATRIX и т.д., их нужно заполнять.


Попробуй убрать все лишнее, скорости, обработку, регулируй только громкость.
И хоть запости какие коэффциенты в матрице громкостей получились, а то так гадать сложно :)

P.S. В догонку: а это что за креатив (Position != xEmi.Position) ? О_о

#2
16:04, 3 июля 2011

Структуры заполняются:

BOOL rSoundEmitter::Load(LPWSTR lpFileName) // Загрузка эмитера
{
  XAUDIO2_SEND_DESCRIPTOR  pDesc[2];
  XAUDIO2_VOICE_SENDS    xSend;
  XAUDIO2_BUFFER      xBuffer;
  DWORD          nBufferSize;

  if( (pFile = (rWaveFile*)pCtrl->GetDS()->GetFile(lpFileName)) == NULL ) // Открываем файл
  {
    return FALSE;
  }
  if( (pData = new BYTE[pFile->GetSize()]) == NULL )
  {
    pCtrl->GetDS()->CloseFile(lpFileName);
    return FALSE;
  }
  pFile->ReadData(pData, pFile->GetSize(), &nBufferSize);
  pDesc[0].Flags = XAUDIO2_SEND_USEFILTER;
  pDesc[0].pOutputVoice = pCtrl->GetMV();                    // IXAudio2MasteringVoice
  pDesc[1].Flags = XAUDIO2_SEND_USEFILTER;
  pDesc[1].pOutputVoice = pCtrl->GetSV();                    // IXAudio2SubmixVoice
  xSend.pSends = pDesc;
  xSend.SendCount = 2;
  pCtrl->GetXA()->CreateSourceVoice(&pSourceVoice, pFile->GetFormat(), 0, 2.0f, NULL, &xSend, NULL);
// Заполняем X3DAUDIO_EMITTER
  xEmi.ChannelCount = 1;
  xEmi.ChannelRadius = 1;
  xEmi.pVolumeCurve = (X3DAUDIO_DISTANCE_CURVE*)&X3DAudioDefault_LinearCurve;
  xEmi.CurveDistanceScaler = 14.0f;
    xEmi.DopplerScaler = 1.0f;
  xEmi.pCone = new X3DAUDIO_CONE;
  xEmi.pCone->InnerAngle = 0.0f;
    xEmi.pCone->OuterAngle = 0.0f;
    xEmi.pCone->InnerVolume = 0.0f;
    xEmi.pCone->OuterVolume = 1.0f;
    xEmi.pCone->InnerLPF = 0.0f;
    xEmi.pCone->OuterLPF = 1.0f;
    xEmi.pCone->InnerReverb = 0.0f;
    xEmi.pCone->OuterReverb = 1.0f;
  memset(&xBuffer, NULL, sizeof(XAUDIO2_BUFFER));
  xBuffer.pAudioData = pData;
  xBuffer.Flags = XAUDIO2_END_OF_STREAM;
  xBuffer.AudioBytes = nBufferSize;
  xBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
  if( FAILED(pSourceVoice->SubmitSourceBuffer(&xBuffer, NULL)) )
  {
    pCtrl->GetDS()->CloseFile(pFileName);
    pSourceVoice->DestroyVoice();
    pSourceVoice = NULL;
    return FALSE;
  }
  return TRUE;
}

BOOL rSoundController::Init(DWORD Channels) // А это инициализация dspSettings и прочего
{
  XAUDIO2_DEVICE_DETAILS   details;
  UINT32         flags = 0;

  nChannels = Channels;
  CoInitializeEx(NULL, COINIT_MULTITHREADED);
#ifdef _DEBUG
    flags |= XAUDIO2_DEBUG_ENGINE;
#endif
  if( FAILED(XAudio2Create(&pXAudio2, flags)))
    return FALSE;
  if( FAILED(pXAudio2->CreateMasteringVoice(&pMasteringVoice)) )
  {
    Free();
    return FALSE;
  }
  if( FAILED(pXAudio2->GetDeviceDetails(0, &details)))
  {
    Free();
    return FALSE;
  }
  if( details.OutputFormat.Format.nChannels > nChannels )
  {
    Free();
    return FALSE;
  }
  if( FAILED(pXAudio2->CreateSubmixVoice(&pSubmixVoice, 1, details.OutputFormat.Format.nSamplesPerSec, 0, 0, NULL, NULL)) )
  {
    Free();
    return FALSE;
  }
  nChannelMask = details.OutputFormat.dwChannelMask;
  nChannels = details.OutputFormat.Format.nChannels;
  X3DAudioInitialize(details.OutputFormat.dwChannelMask, X3DAUDIO_SPEED_OF_SOUND, h3DAudio );
  dspSettings.SrcChannelCount = 1;
  dspSettings.DstChannelCount = nChannels;
  dspSettings.pMatrixCoefficients = new float[nChannels];
              return TRUE;
}
Так что все инициализируется.
По поводу громкости. Функция SetVolume срабатывает только один раз. Громкость действительно меняется. Но во второй и в следующие разы она ничего не делает.
И хоть запости какие коэффциенты в матрице громкостей получились

0.5 0.5

(Position != xEmi.Position)  - это чтобы оно не пересчитывало ничего, если положение эмитера не изменилось.

#3
16:30, 3 июля 2011

xEmi.pCone->InnerVolume = 0.0f;
А чего оно тут 0?


Убери все лишнее, конусы эффекты и т.д. Добейся чтобы работало, а потом добавляй

RedAngel
> (Position != xEmi.Position) - это чтобы оно не пересчитывало ничего, если
> положение эмитера не изменилось.

Так оно ничего и не пересчитывает никогда. Можешь хоть 100500 раз громкость задавать.
Чему ты тогда удивляешься?

Вообще оптимизации, а уж тем более такие сомнительные, стоит добавлять только когда все заработало.

#4
16:40, 3 июля 2011
xEmi.pCone->InnerVolume = 0.0f;
А чего оно тут 0?

Из примера из SDK содрано.
Добейся чтобы работало

Так оно и работает. Дело в том, что эту громкость я уже после того, как все написал решил добавить.
Так оно ничего и не пересчитывает никогда.

Пересчитывает. Это я тут  накосячил, когда rSoundEmitter::SetVolumeLevel() постил.
void rSoundEmitter::SetVolumeLevel(float Level)
{
  if( pSourceVoice )
  {
    pSourceVoice->SetVolume(Level);
    Update(1, TRUE); // TRUE
  }
}
#5
17:33, 3 июля 2011

RedAngel
> Пересчитывает.

А как выглядит оператор != для этих векторов?

#6
17:59, 3 июля 2011
А как выглядит оператор != для этих векторов?

d3dx9math.h:

typedef struct D3DXVECTOR3 : public D3DVECTOR
{
public:
 

    BOOL operator != ( CONST D3DXVECTOR3& ) const;

} D3DXVECTOR3, *LPD3DXVECTOR3;

Да, я тут еще раз SDK посмотрел, и подумал следующее. Этот самый SetVolume никакого отношения к матрицам и прочему не имеет. Он, получается,
устанавливает какой-то множитель, на который умножается исходный звук (т.е. изменяет амплитуду исходного сигнала), а потом уже к нему применяются всякие матрицы и прочее. Ведь X3DAudioCalculate просто берет данные из структур LISTENER и EMITTER и считает их взаимное расположение, т.е. просто выдает числа, сколько звука дать в левый канал, сколько в правый. И эти значения уже потом (вручную) передаются в IXAudio2SourceVoice. А этот множитель, который задается, через SetVolume никаким образом не зависит от положения источника и прочего, т.е. то же самое, как если бы мы взяли любой звуковой редактор, и увеличили бы в нем громкость звука в самом аудиофайле.

#7
18:51, 3 июля 2011

RedAngel
> d3dx9math.h:

Об этом я и так догадываюсь :). А реализация?
И ты уверен что оно нормально работает вектора в аудио они от D3DVECTOR происходят, а не от D3DXVECTOR3

RedAngel
> Да, я тут еще раз SDK посмотрел, и подумал следующее. Этот самый SetVolume
> никакого отношения к матрицам и прочему не имеет. Он, получается,
> устанавливает какой-то множитель, на который умножается исходный звук (т.е.
> изменяет амплитуду исходного сигнала), а потом уже к нему применяются всякие
> матрицы и прочее. Ведь X3DAudioCalculate просто берет данные из структур
> LISTENER и EMITTER и считает их взаимное расположение, т.е. просто выдает
> числа, сколько звука дать в левый канал, сколько в правый. И эти значения уже
> потом (вручную) передаются в IXAudio2SourceVoice. А этот множитель, который
> задается, через SetVolume никаким образом не зависит от положения источника и
> прочего, т.е. то же самое, как если бы мы взяли любой звуковой редактор, и
> увеличили бы в нем громкость звука в самом аудиофайле.

Да, конечно, так и работает.
Например, если ты хочешь сделать так чтобы взрывы были громче чем  звуки двигателя, то ставишь им больше громкость.

Я помню что когда писал обертку вокруг этого, с громкостью тоже как-то не сложилось. Времени не было разбираться чего оно и как. Я на вроде коэффициенты на выходе домножал на громкость и не парился. Но давно дело было, точно не вспомню чего и как.

#8
23:58, 4 июля 2011

Спасибо за помощь. Проблема решена. Сам накосячил :(

float rSoundEmitter::SetRelativeVolume(float Level)
{
  float Lvl;

  Lvl = GetVolumeLevel();
  Lvl += Level;
  if( Lvl < 0 )
    Lvl = 0;
  if( Lvl > XAUDIO2_MAX_VOLUME_LEVEL )
    Lvl = XAUDIO2_MAX_VOLUME_LEVEL;
  SetVolumeLevel(Level); // В аргументе Level вместо Lvl
  return Lvl;
}
ПрограммированиеФорумЗвук

Тема в архиве.