Использование waveOutWrite с динамически распределенной памятью

Я экспериментировал со звуком, используя C.

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

Это работало довольно хорошо для того, что это было.

Вот код, который работает: (Вам нужно связать winmm, чтобы это работало)
(ВНИМАНИЕ: это довольно громко.)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <mmsystem.h>

//#pragma comment(lib, "winmm.lib")

int main()
{
    HWAVEOUT hWaveOut=0;
    WAVEFORMATEX wfx = {WAVE_FORMAT_PCM,1,8000,8000,1,8,0};
    //buffer to hold 1 minute of pcm wave data (8 bit, 8khz sample rate)
    char buffer[8000*60];
    int i;
    for (i=0;i<8000*60;i++){
        //generate pseudo-random sound.
        buffer[i] = (i*5&(i>>7)|i*3&(i*4>>10));
    }
    waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
    WAVEHDR header = { buffer, sizeof(buffer), 0, 0, 0, 0, 0, 0 };
    waveOutPrepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut, &header, sizeof(WAVEHDR));
    Sleep(60*1000);
    waveOutUnprepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
    waveOutClose(hWaveOut);
    return 0;
}

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

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

Вот пример, который не работает:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <mmsystem.h>

//#pragma comment(lib, "winmm.lib")

int main()
{
    HWAVEOUT hWaveOut=0;
    WAVEFORMATEX wfx = {WAVE_FORMAT_PCM,1,8000,8000,1,8,0};
    //buffer to hold 1 minute of pcm wave data (8 bit, 8khz sample rate)
    char *buffer = malloc(sizeof(char)*8000*60);
    int i;
    for (i=0;i<8000*60;i++){
        //generate pseudo-random sound.
        buffer[i] = (i*5&(i>>7)|i*3&(i*4>>10));
    }
    waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
    WAVEHDR header = { buffer, sizeof(buffer), 0, 0, 0, 0, 0, 0 };
    waveOutPrepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut, &header, sizeof(WAVEHDR));
    Sleep(60*1000);
    waveOutUnprepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
    waveOutClose(hWaveOut);
    return 0;
}

Примечание: я слышал, что есть способ "заблокировать" часть памяти, и я мог бы использовать это для воспроизведения аудио-буфера, который был динамически распределен. Если так, как бы я это сделал?

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

Большое спасибо за ваше время! Вы, люди, потрясающие.

Обновить:

Я обнаружил, что документация Microsoft использует функции GlobalAlloc(), HeapAlloc(), LocalAlloc() а также VirtualAlloc() выделить память для волновых буферов. Код ниже взят из этого примера:

char *buffer = LocalAlloc(LMEM_FIXED,8000*60); //Doesn't work. Still no sound.

Это также взято из другого примера:

HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 8000*60);
char *buffer = GlobalLock(hData); //Also doesn't work, no sound.

1 ответ

Решение

Проблема здесь:

WAVEHDR header = { buffer, sizeof(buffer), 0, 0, 0, 0, 0, 0 };

Вот, sizeof(buffer) размер указателя на буфер, потому что буфер char *, В вашем первом примере буфер был массивом char, поэтому sizeof(buffer) вернул размер буфера.

Вы должны предоставить выделенный размер, который вы рассчитали выше. Я бы использовал пару констант или переменных, чтобы отслеживать размер, чтобы вы не повторяли вычисления. Например:

//buffer to hold 1 minute of pcm wave data (8 bit, 8khz sample rate)
const size_t samples_per_second = 8000;
const size_t seconds = 60;
const size_t size = samples_per_second * seconds;
unsigned char *buffer = malloc(size);
size_t i;
for (i=0;i<size;i++){
    //generate pseudo-random sound.
    buffer[i] = (i*5&(i>>7)|i*3&(i*4>>10));
}
waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
WAVEHDR header = { buffer, size, 0, 0, 0, 0, 0, 0 };

Вы можете использовать unsigned char для ваших образцов. Я считаю, что форматы WAV хотят беззнаковые значения для 8-битных семплов. (Для других размеров вы хотите подписанные образцы.)

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