Заполнение буфера аудио конечной точки, предоставленное WASAPI, не воспроизводит звук

Я пытаюсь воспроизвести шум через средство рендеринга конечной точки звука по умолчанию, используя интерфейс WASPAI. Я пытаюсь использовать код, предоставленный Microsoft на этой странице: https://learn.microsoft.com/en-us/windows/win32/coreaudio/rendering-a-stream. Я хочу написать класс, который может генерировать шум для этого примера кода.

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

Для начала сделал шапку с нужными методами и генератором случайных чисел.

#pragma once

// RNG
#include <random>

template <typename T>
class Random {
public:
    Random(T low, T high) : mLow(low), mHigh(high), function(std::mt19937_64(__rdtsc())) {};

    T operator()() { 
        signed __int64 f =  function();

        return ((f  % ((signed __int64) mHigh + (signed __int64) mLow)) + (signed __int64) mLow); }

private:
    T mLow;
    T mHigh;
    std::mt19937_64 function;
};

class Noise_Gen {

public:

    Noise_Gen() : nChannels(NULL), nSamplesPerSec(NULL), nAvgBytesPerSec(NULL), nByteAlign(NULL), wBitsPerSample(NULL), 
        wValidBitsPerSample(NULL), wSamplesPerBlock(NULL), dwChannelMask(NULL), rd(NULL) {};

    ~Noise_Gen() {
        if (rd != NULL) {
            delete rd;
        }
    };

    HRESULT SetFormat(WAVEFORMATEX*);

    HRESULT LoadData(UINT32 bufferFrameCount, BYTE* pData, DWORD* flags);

private:
    void* rd;

    // WAVEFORMATEX
    WORD nChannels;
    DWORD nSamplesPerSec;
    DWORD nAvgBytesPerSec;
    WORD nByteAlign;
    WORD wBitsPerSample;

    // WAVEFORMATEXTENSIBLE
    WORD wValidBitsPerSample;
    WORD wSamplesPerBlock;
    DWORD dwChannelMask;
};

Затем я добавил определения:

// WASAPI
#include <Audiopolicy.h>
#include <Audioclient.h>

#include <time.h>

#include "Noise_Gen.h"

HRESULT Noise_Gen::SetFormat(WAVEFORMATEX* format) {
    nChannels = format->nChannels;
    nSamplesPerSec = format->nSamplesPerSec;
    nAvgBytesPerSec = format->nAvgBytesPerSec;
    nByteAlign = format->nBlockAlign;
    wBitsPerSample = format->wBitsPerSample;
    WORD  wFormatTag = format->wFormatTag;
    if (wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
        WAVEFORMATEXTENSIBLE* pWFE = reinterpret_cast<WAVEFORMATEXTENSIBLE*>(format);
        wValidBitsPerSample = pWFE->Samples.wValidBitsPerSample;
        wSamplesPerBlock = pWFE->Samples.wSamplesPerBlock;
        dwChannelMask = pWFE->dwChannelMask;
    } else {
        wValidBitsPerSample = wBitsPerSample;
    }
    double amplitude = std::pow(2.0, wValidBitsPerSample) - 1;
    switch(wBitsPerSample / 8) {
    case(1):
        rd = new Random<unsigned __int8>(0.0, amplitude);
        break;
    case(2): 
        rd = new Random<unsigned __int16>(0.0, amplitude);
        break;
    case(3):
        rd = new Random<unsigned __int32>(0.0, amplitude);
        break;
    case(4): 
        rd = new Random<signed __int32>(-amplitude, amplitude);
        break;
    case(5): 
        rd = new Random<unsigned __int64>(0.0, amplitude);
        break;
    case(6):
        rd = new Random<unsigned __int64>(0.0, amplitude);
        break;
    case(7): 
        rd = new Random<unsigned __int64>(0.0, amplitude);
        break;
    case(8):
        rd = new Random<unsigned __int64>(0.0, amplitude);
        break;
    default:
        return E_NOTIMPL;
    }
    return S_OK;
}

// (The size of an audio frame = nChannels * wBitsPerSample)
HRESULT Noise_Gen::LoadData(UINT32 bufferFrameCount, BYTE* pData, DWORD* flags) {
    for(UINT32 i = 0; i < nChannels *bufferFrameCount; i++) {
        switch(wBitsPerSample / 8) {
        case(1):
            pData[i] = (((Random<unsigned __int8>*)rd)->operator()());
            break;
        case(2):{
            unsigned __int16* pData2 = (unsigned __int16*) pData;
            pData2[i] = (((Random<unsigned __int16>*)rd)->operator()());
            break;
        }
        case(3): {
            __int32 data = ((Random<unsigned __int32>*)rd)->operator()();
            unsigned char* cp = (unsigned char*) (&data);
            pData[(3 * i)] = cp[0];
            pData[1 + (3 * i)] = cp[1];
            pData[2 + (3 * i)] = cp[2];
            break;
        }
        case(4):{
            signed __int32* pData2 = (signed __int32*) pData;
            pData2[i] = (((Random<signed __int32>*)rd)->operator()());
            break;
        }
        case(5): {
            __int64 data = ((Random<unsigned __int64>*)rd)->operator()();
            unsigned char* cp = (unsigned char*) &data;
            pData[(5 * i)] = cp[0];
            pData[1 + (5 * i)] = cp[1];
            pData[2 + (5 * i)] = cp[2];
            pData[3 + (5 * i)] = cp[3];
            pData[4 + (5 * i)] = cp[4];
            break;
        }
        case(6): {
            __int64 data = ((Random<unsigned __int64>*)rd)->operator()();
            unsigned char* cp = (unsigned char*) &data;
            pData[(6 * i)] = cp[0];
            pData[1 + (6 * i)] = cp[1];
            pData[2 + (6 * i)] = cp[2];
            pData[3 + (6 * i)] = cp[3];
            pData[4 + (6 * i)] = cp[4];
            pData[5 + (6 * i)] = cp[5];
            break;
        }
        case(7): {
            __int64 data = ((Random<unsigned __int64>*)rd)->operator()();
            unsigned char* cp = (unsigned char*) &data;
            pData[(7 * i)] = cp[0];
            pData[1 + (7 * i)] = cp[1];
            pData[2 + (7 * i)] = cp[2];
            pData[3 + (7 * i)] = cp[3];
            pData[4 + (7 * i)] = cp[4];
            pData[5 + (7 * i)] = cp[5];
            pData[6 + (7 * i)] = cp[6];
            break;
        }
        case(8): {
            unsigned __int64* pData2 = (unsigned __int64*) pData;
            pData2[i] = (((Random<unsigned __int64>*)rd)->operator()());
            break;
        }
        default:
            // For stopping playback
            (*flags) = AUDCLNT_BUFFERFLAGS_SILENT;
            return E_NOTIMPL;
        }
    }
    return S_OK;
}

Затем я добавил свой класс в шаблон, предоставленный Microsoft, и вывел на консоль средство рендеринга конечной точки звука по умолчанию.

#include <InitGuid.h>
#include <iostream>
#include <Windows.h>
#include <dshow.h>

// Windows multimedia device
#include <Mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>

// WASAPI
#include <Audiopolicy.h>
#include <Audioclient.h>

#include "Noise_Gen.h"

//-----------------------------------------------------------
// Play an audio stream on the default audio rendering
// device. The PlayAudioStream function allocates a shared
// buffer big enough to hold one second of PCM audio data.
// The function uses this buffer to stream data to the
// rendering device. The inner loop runs every 1/2 second.
//-----------------------------------------------------------

// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC  10000000
#define REFTIMES_PER_MILLISEC  10000

#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);

HRESULT PlayAudioStream(Noise_Gen* pMySource) {
    HRESULT hr;
    REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
    REFERENCE_TIME hnsActualDuration;
    IMMDeviceEnumerator* pEnumerator = NULL;
    IMMDevice* pDevice = NULL;
    IAudioClient* pAudioClient = NULL;
    IAudioRenderClient* pRenderClient = NULL;
    WAVEFORMATEX* pwfx = NULL;
    UINT32 bufferFrameCount;
    UINT32 numFramesAvailable;
    UINT32 numFramesPadding;
    BYTE* pData;
    DWORD flags = 0;
    IPropertyStore* pPropertyStore = NULL;
    PROPVARIANT name;

    hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL,
                          CLSCTX_ALL, IID_IMMDeviceEnumerator,
                          (void**) &pEnumerator);
    EXIT_ON_ERROR(hr);
    hr = pEnumerator->GetDefaultAudioEndpoint(
        eRender, eConsole, &pDevice);

    hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
    PropVariantInit(&name);
    hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &name);
    printf("%S", name.pwszVal);
    printf("\n");
    EXIT_ON_ERROR(hr);
    hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL,
                           NULL, (void**) &pAudioClient);
    EXIT_ON_ERROR(hr);
    hr = pAudioClient->GetMixFormat(&pwfx);
    EXIT_ON_ERROR(hr);
    hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
                                  0, hnsRequestedDuration,
                                  0, pwfx, NULL);
    EXIT_ON_ERROR(hr);
    // Tell the audio source which format to use.
    hr = pMySource->SetFormat(pwfx);
    EXIT_ON_ERROR(hr);
    // Get the actual size of the allocated buffer.
    hr = pAudioClient->GetBufferSize(&bufferFrameCount);
    EXIT_ON_ERROR(hr);
    hr = pAudioClient->GetService(IID_IAudioRenderClient,
                                  (void**) &pRenderClient);
    EXIT_ON_ERROR(hr);
    // Grab the entire buffer for the initial fill operation.
    hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
    EXIT_ON_ERROR(hr);
    // Load the initial data into the shared buffer.
    hr = pMySource->LoadData(bufferFrameCount, pData, &flags);
    EXIT_ON_ERROR(hr);
    hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
    EXIT_ON_ERROR(hr);
    // Calculate the actual duration of the allocated buffer.
    hnsActualDuration = (double) REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
    hr = pAudioClient->Start();  // Start playing.
    EXIT_ON_ERROR(hr);
    // Each loop fills about half of the shared buffer.
    while(flags != AUDCLNT_BUFFERFLAGS_SILENT) {
        // Sleep for half the buffer duration.
        Sleep((DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2));
        // See how much buffer space is available.
        hr = pAudioClient->GetCurrentPadding(&numFramesPadding);
        EXIT_ON_ERROR(hr);
        numFramesAvailable = bufferFrameCount - numFramesPadding;
        // Grab all the available space in the shared buffer.
        hr = pRenderClient->GetBuffer(numFramesAvailable, &pData);
        EXIT_ON_ERROR(hr);
        // Get next 1/2-second of data from the audio source.
        hr = pMySource->LoadData(numFramesAvailable, pData, &flags);
        EXIT_ON_ERROR(hr);
        hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags);
        EXIT_ON_ERROR(hr);
    }
    // Wait for last data in buffer to play before stopping.
    Sleep((DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2));
    hr = pAudioClient->Stop();  // Stop playing.
    EXIT_ON_ERROR(hr);
Exit:
    CoTaskMemFree(pwfx);
    SAFE_RELEASE(pEnumerator);
    SAFE_RELEASE(pDevice);
    SAFE_RELEASE(pAudioClient);
    SAFE_RELEASE(pRenderClient);
    return hr;
}

int main() {
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr)) { return hr; }
    Noise_Gen* ng = new Noise_Gen();
    PlayAudioStream(ng);
    delete ng;
    CoUninitialize();
}

Средство визуализации конечной точки аудио по умолчанию в моей системе использует 32-битные значения, поэтому код начинался с записи 32-битных значений без знака в буфер. Затем я попытался использовать значения со знаком, что можно увидеть в приведенном выше коде. В обоих случаях звук не воспроизводился. Я проверил содержимое буфера во время отладки, и оно изменилось. Я напечатал средство визуализации конечной точки звука по умолчанию на консоли, и это динамик моей системы. Windows даже показывает мое приложение в микшере громкости, но звук не отображается даже при максимальной громкости. Затем я проверил время сна, чтобы убедиться, что он находится в спящем режиме, чтобы система имела доступ к буферу, и он действительно спит в течение 500 мс между записями в буфер.

Обновление: я обнаружил, что использую подформат KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, и попытался передать буфер с плавающей запятой в диапазоне от -амплитуды до амплитуды, от 0 до диапазона амплитуды, от -1 до 1 диапазона и от 0 до 1 диапазона.

Что мне не хватает?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
993
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш код распределения случайных чисел работает некорректно для форматов с плавающей запятой (насколько я знаю, в основном всегда будет смешанный формат в общем режиме).

Это неправильно даже для целых чисел. Я полагаю, вы хотели написать

((f  % ((signed __int64) mHigh - (signed __int64) mLow)) + (signed __int64) mLow); 

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

Для форматов с плавающей запятой вы всегда используете диапазон от -1 до 1.

Я адаптировал ваш код для использования std::uniform_real_distribution, и в моих динамиках воспроизводится шум.

#include <cstdio>
#include <Windows.h>

// Windows multimedia device
#include <Mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>

// WASAPI
#include <Audiopolicy.h>
#include <Audioclient.h>

#include <random>


class Noise_Gen {
public:
    Noise_Gen() : format(), engine(__rdtsc()), float_dist(-1.f, 1.f) {};

    void SetFormat(WAVEFORMATEX* wfex) {
        if (wfex->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
            format = *reinterpret_cast<WAVEFORMATEXTENSIBLE*>(wfex);
        } else {
            format.Format = *wfex;
            format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
            INIT_WAVEFORMATEX_GUID(&format.SubFormat, wfex->wFormatTag);
            format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample;
            format.dwChannelMask = 0;
        }
    }

    // (The size of an audio frame = nChannels * wBitsPerSample)
    void FillBuffer(UINT32 bufferFrameCount, BYTE* pData, DWORD* flags) {
        const UINT16 formatTag = EXTRACT_WAVEFORMATEX_ID(&format.SubFormat);
        if (formatTag == WAVE_FORMAT_IEEE_FLOAT) {
            float* fData = (float*)pData;
            for(UINT32 i = 0; i < format.Format.nChannels * bufferFrameCount; i++) {
                fData[i] = float_dist(engine);
            }
        } else if (formatTag == WAVE_FORMAT_PCM) {
            using rndT = decltype(engine)::result_type;
            UINT32 iterations = format.Format.nBlockAlign * bufferFrameCount / sizeof(rndT);
            UINT32 leftoverBytes = format.Format.nBlockAlign * bufferFrameCount % sizeof(rndT);
            rndT* iData = (rndT*)pData;
            UINT32 i = 0;
            for(; i < iterations; i++) {
                iData[i] = engine();
            }
            if (leftoverBytes != 0) {
                rndT lastRnd = engine();
                BYTE* pLastBytes = pData + i * sizeof(rndT);
                for(UINT32 j = 0; j < leftoverBytes; ++j) {
                    pLastBytes[j] = lastRnd >> (j * 8) & 0xFF;
                }
            }
        } else {
            //memset(pData, 0, wfex.Format.nBlockAlign * bufferFrameCount);
            *flags = AUDCLNT_BUFFERFLAGS_SILENT;
        }
    }

private:
    WAVEFORMATEXTENSIBLE format;

    std::mt19937_64 engine;
    std::uniform_real_distribution<float> float_dist;
};

// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC  10000000ll
#define REFTIMES_PER_MILLISEC  10000

#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

HRESULT PlayAudioStream(Noise_Gen* pMySource) {
    HRESULT hr;
    REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
    REFERENCE_TIME hnsActualDuration;
    IMMDeviceEnumerator* pEnumerator = NULL;
    IPropertyStore* pPropertyStore = NULL;
    IMMDevice* pDevice = NULL;
    IAudioClient* pAudioClient = NULL;
    IAudioRenderClient* pRenderClient = NULL;
    WAVEFORMATEX* pwfx = NULL;
    UINT32 bufferFrameCount;
    BYTE* pData;
    DWORD flags = 0;
    PROPVARIANT name;

    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
        CLSCTX_ALL, IID_PPV_ARGS(&pEnumerator));
    EXIT_ON_ERROR(hr);
    hr = pEnumerator->GetDefaultAudioEndpoint(
        eRender, eConsole, &pDevice);
    EXIT_ON_ERROR(hr);

    hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
    EXIT_ON_ERROR(hr);
    PropVariantInit(&name);
    hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &name);
    EXIT_ON_ERROR(hr);
    printf("%S", name.pwszVal);
    printf("\n");
    hr = pDevice->Activate(__uuidof(pAudioClient), CLSCTX_ALL,
        NULL, (void**) &pAudioClient);
    EXIT_ON_ERROR(hr);
    hr = pAudioClient->GetMixFormat(&pwfx);
    EXIT_ON_ERROR(hr);

    hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
        0, hnsRequestedDuration,
        0, pwfx, NULL);
    EXIT_ON_ERROR(hr);
    // Tell the audio source which format to use.
    pMySource->SetFormat(pwfx);
    // Get the actual size of the allocated buffer.
    hr = pAudioClient->GetBufferSize(&bufferFrameCount);
    EXIT_ON_ERROR(hr);
    hr = pAudioClient->GetService(IID_PPV_ARGS(&pRenderClient));
    EXIT_ON_ERROR(hr);
    // Grab the entire buffer for the initial fill operation.
    hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
    EXIT_ON_ERROR(hr);

    // Load the initial data into the shared buffer.
    pMySource->FillBuffer(bufferFrameCount, pData, &flags);    

    hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
    EXIT_ON_ERROR(hr);
    // Calculate the actual duration of the allocated buffer.
    hnsActualDuration = REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
    hr = pAudioClient->Start();  // Start playing.
    EXIT_ON_ERROR(hr);
    // Each loop fills about half of the shared buffer.
    DWORD sleepTime;
    while(flags != AUDCLNT_BUFFERFLAGS_SILENT) {
        // Sleep for half the buffer duration.
        sleepTime = (DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2);
        if (sleepTime != 0)
            Sleep(sleepTime);
        // See how much buffer space is available.
        UINT32 numFramesPadding;
        hr = pAudioClient->GetCurrentPadding(&numFramesPadding);
        EXIT_ON_ERROR(hr);

        UINT32 numFramesAvailable = bufferFrameCount - numFramesPadding;
        // Grab all the available space in the shared buffer.
        hr = pRenderClient->GetBuffer(numFramesAvailable, &pData);
        EXIT_ON_ERROR(hr);

        // Get next 1/2-second of data from the audio source.
        pMySource->FillBuffer(numFramesAvailable, pData, &flags);

        hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags);
        EXIT_ON_ERROR(hr);
    }
    // Wait for last data in buffer to play before stopping.
    sleepTime = (DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2);
    if (sleepTime != 0)
        Sleep(sleepTime);
    hr = pAudioClient->Stop();  // Stop playing.
    EXIT_ON_ERROR(hr);

Exit:
    CoTaskMemFree(pwfx);
    SAFE_RELEASE(pRenderClient);
    SAFE_RELEASE(pAudioClient);
    SAFE_RELEASE(pDevice);
    SAFE_RELEASE(pPropertyStore); // you forgot to free the property store
    SAFE_RELEASE(pEnumerator);
    return hr;
}

int main() {
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr)) { return hr; }

    Noise_Gen ng;
    PlayAudioStream(&ng);
    
    CoUninitialize();
}

Спасибо за ответ. Мне не хватало информации: «Для форматов с плавающей запятой вы всегда используете диапазон от -1 до 1». В итоге я использовал std::bind(std::uniform_real_distribution<>(low, high), std::default_random_engine()) для случайных чисел.

John Glen 18.12.2020 23:53

Я могу ошибаться, но я не думаю, что это заполняет весь кольцевой буфер. Когда numFramesAvailable меньше полного размера буфера, FillBuffer вернется к индексу 0 из pData в случае WAVE_FORMAT_IEEE_FLOAT.

fdcpp 11.01.2021 18:32

pData будет указывать на буфер с правильным смещением уже тогда, когда мы получим его из IAudioRenderClient::GetBuffer, поэтому мы всегда должны начинать заполнение новых данных со смещения 0 от pData.

The Om 11.01.2021 19:28

@TheOm Это странно, так как я обнаружил, что это не относится к моей собственной реализации. Меня беспокоит то, что природа белого шума звука скрывает разрывы.

fdcpp 11.01.2021 20:41

@TheOm GetBuffer не обновляет адрес pData в моем случае, и мне нужно самому отслеживать положение буфера.

fdcpp 11.01.2021 20:43

@TheOm извинения, игнорируйте все это, каким-то образом удалось удалить важную строку при копировании / вставке.

fdcpp 11.01.2021 21:19

Другие вопросы по теме