Hope is a Dream. Dream is a Hope.

非公開ふぃふぃ工房ブログは再開しました。

C/C++で音声出力

最近C#を使って音声処理系のアプリケーションが書けるようになったが、 実はwindowsの音声出力が良く分からない

そこらへんは便利なラッパーライブラリを使って見ないフリをしていた

改めてC/C++でwin32apiから勉強してみる

参考ページ

C言語/C++ - Sample is best! - アットウィキ

C言語/C++/wave - Sample is best! - アットウィキ

C++によるオーディオ信号処理(1) ---環境構築とサンプルプログラム動作確認--- : 工作と競馬

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

#define _USE_MATH_DEFINES

#include <math.h>
#include <stdio.h>
#include <Windows.h>

#include <locale.h> // LC_CTYPE
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

#define VOLUME 64
#define FREQ   440
#define SAMPLE_RATE    11025
#define TONE_MSEC  1000
#define DATA_LEN   (SAMPLE_RATE * TONE_MSEC / 1000)

int main() {
    WAVEFORMATEX    waveformatx;
    MMRESULT        mmresult;
    HWAVEOUT        handle_wave_out;
    WAVEHDR         wave_header;

    char           acData[DATA_LEN]; // MAX 256 (8bit = 1Byte)
    double         dWave;
    int                i;

    // 波形データの生成 Generate Waveform
    for (i = 0; i < DATA_LEN; i++) {
        dWave = sin(i * FREQ * 2 * M_PI / SAMPLE_RATE);
        acData[i] = (char)(dWave * VOLUME) + 128;
        //acData[i] = rand() * 2 * VOLUME / RAND_MAX + 128 - VOLUME; // ホワイトノイズ

    }

    // Play
    waveformatx.wFormatTag = WAVE_FORMAT_PCM;
    waveformatx.nChannels = 1;
    waveformatx.nSamplesPerSec = SAMPLE_RATE;
    waveformatx.nAvgBytesPerSec = SAMPLE_RATE;
    waveformatx.nBlockAlign = 1;
    waveformatx.wBitsPerSample = 8; // 8bit
    waveformatx.cbSize = 0;

    const UINT device_nomber = waveOutGetNumDevs();
    printf("Device no : %d\n", device_nomber);

    // USER Inputs
    printf("Please Input Device ID\n");

    UINT deviceid = 0;
    scanf_s("%d", &deviceid);
    printf("%d\n", deviceid);

    // Check Device Open
    mmresult = waveOutOpen(&handle_wave_out, deviceid, &waveformatx, 0, 0, CALLBACK_NULL);

    if (mmresult != MMSYSERR_NOERROR) {

        printf("error: waveOutOpen\n");

        switch (mmresult)
        {
        case  MMSYSERR_ALLOCATED:
            printf("error: MMSYSERR_ALLOCATED\n");
            break;
        case  MMSYSERR_BADDEVICEID:
            printf("error: MMSYSERR_BADDEVICEID\n");
            break;
        case  MMSYSERR_NODRIVER:
            printf("error: MMSYSERR_NODRIVER\n");
            break;
        case  MMSYSERR_NOMEM:
            printf("error: MMSYSERR_NOMEM\n");
            break;
        case  WAVERR_BADFORMAT:
            printf("error: WAVERR_BADFORMAT\n");
            break;
        case  WAVERR_SYNC:
            printf("error: WAVERR_SYNC\n");
            break;
        default:
            break;
        }

        system("pause");
        return 1;
    }


    // waveOutPrepareHeader
    ZeroMemory(&wave_header, sizeof wave_header);

    wave_header.lpData = acData;
    wave_header.dwBufferLength = DATA_LEN;

    mmresult = waveOutPrepareHeader(handle_wave_out, &wave_header, sizeof wave_header);

    if (mmresult != MMSYSERR_NOERROR) {

        fprintf(stderr, "error: waveOutPrepareHeader\n");

        switch (mmresult)
        {
        case  MMSYSERR_INVALHANDLE:
            printf("error: MMSYSERR_INVALHANDLE\n");
            break;
        case  MMSYSERR_NODRIVER:
            printf("error: MMSYSERR_NODRIVER\n");
            break;
        case  MMSYSERR_NOMEM:
            printf("error: MMSYSERR_NOMEM\n");
            break;
        default:
            break;
        }

        system("pause");
        return 1;
    }

    // waveOutWrite
    mmresult = waveOutWrite(handle_wave_out, &wave_header, sizeof wave_header);
    if (mmresult != MMSYSERR_NOERROR) {

        fprintf(stderr, "error: waveOutWrite\n");

        switch (mmresult)
        {
        case  MMSYSERR_INVALHANDLE:
            printf("error: MMSYSERR_INVALHANDLE\n");
            break;
        case  MMSYSERR_NODRIVER:
            printf("error: MMSYSERR_NODRIVER\n");
            break;
        case  MMSYSERR_NOMEM:
            printf("error: MMSYSERR_NOMEM\n");
            break;
        default:
            break;
        }

        system("pause");

        return 1;
    }

    // wait
    Sleep(TONE_MSEC);

    // Stop

    // waveOutReset
    mmresult = waveOutReset(handle_wave_out);
    if (mmresult != MMSYSERR_NOERROR) {
        fprintf(stderr, "error: waveOutReset\n");
        switch (mmresult)
        {
        case  MMSYSERR_INVALHANDLE:
            printf("error: MMSYSERR_INVALHANDLE\n");
            break;
        case  MMSYSERR_NODRIVER:
            printf("error: MMSYSERR_NODRIVER\n");
            break;
        case  MMSYSERR_NOMEM:
            printf("error: MMSYSERR_NOMEM\n");
            break;
        case  MMSYSERR_NOTSUPPORTED:
            printf("error: MMSYSERR_NOTSUPPORTED\n");
            break;
        default:
            break;
        }
        system("pause");

        return 1;
    }

    // waveOutUnprepareHeader
    mmresult = waveOutUnprepareHeader(handle_wave_out, &wave_header, sizeof wave_header);
    if (mmresult != MMSYSERR_NOERROR) {

        fprintf(stderr, "error: waveOutUnprepareHeader\n");

        switch (mmresult)
        {
        case  MMSYSERR_INVALHANDLE:
            printf("error: MMSYSERR_INVALHANDLE\n");
            break;
        case  MMSYSERR_NODRIVER:
            printf("error: MMSYSERR_NODRIVER\n");
            break;
        case  MMSYSERR_NOMEM:
            printf("error: MMSYSERR_NOMEM\n");
            break;
        case  MMSYSERR_NOTSUPPORTED:
            printf("error: MMSYSERR_NOTSUPPORTED\n");
            break;
        default:
            break;
        }
        system("pause");

        return 1;
    }

    // waveOutClose
    mmresult = waveOutClose(handle_wave_out);
    if (mmresult != MMSYSERR_NOERROR) {

        fprintf(stderr, "error: waveOutClose\n");

        switch (mmresult)
        {
        case  MMSYSERR_INVALHANDLE:
            printf("error: MMSYSERR_INVALHANDLE\n");
            break;
        case  MMSYSERR_NODRIVER:
            printf("error: MMSYSERR_NODRIVER\n");
            break;
        case  MMSYSERR_NOMEM:
            printf("error: MMSYSERR_NOMEM\n");
            break;
        case  WAVERR_STILLPLAYING:
            printf("error: WAVERR_STILLPLAYING\n");
            break;
        default:
            break;
        }

        system("pause");

        return 1;
    }



    system("pause");
    return 0;
}

いやーややこしい。

改訂新版 C/C++によるディジタル信号処理入門 (ディジタル信号処理シリーズ)

改訂新版 C/C++によるディジタル信号処理入門 (ディジタル信号処理シリーズ)