Sound - Ausgabe eines Signaltonens per Soundkarte mit beliebiger Frequenz



  • Also, mit dem Befehl
    Beep (Frequenz, ms)
    lässt sich eine Piep-Ton über den PC-Speaker ausgeben.

    Wie kann nun solch ein Piep-Ton, mit unterschiedlicher Frequenz über
    die Lautsprecherboxen (die an der Soundkarte angeschlossen sind) ausgeben?

    Ich hoffe jemand kann mir helfen. 😕



  • programmierst du ein Musikprogramm 😃



  • Naja, so was ähnliches.
    Aber es ist mir wirklich sehr wichtig.
    Kannst du mir helfen?



  • Hat sich erledigt.
    Hab mich in den Newsgroups umgeschaut und hab was geeignetes gefunden:
    http://www.marc-pullmann.de/sinus/DSSineWave.cpp
    🙂



  • Ich pack das mal in die FAQ und poste den Code direkt hier, falls es die Datei mal nicht mehr gibt:

    #include "stdafx.h"
    #include <tchar.h>
    #include <stdio.h>
    #include <mmreg.h>
    #include <dsound.h>
    #include <math.h>
    
    #define WND_WIDTH 500
    #define WND_HEIGHT 200
    
    //*** Strukturen
    struct memArea { //beschreibt einen Speicherbereich durch einen Zeiger darauf und die Größe des Bereichs in Bytes
                     //wird von der Funktion createSineWave() als Rückgabetyp verwendet
        void *pointer;
        DWORD size;
    };
    
    //*** Variablen im Zusammenhang mit DirectSound ***
    LPDIRECTSOUND lpDirectSound = NULL;
    LPDIRECTSOUNDBUFFER lpDSBSecondary = NULL;
    BOOL dsInitialized;
    BOOL dsBufferCreated;
    BOOL dsBufferFilled;
    
    //*** Funktionen im Zusammenhang mit DirectSound ***
    BOOL initDirectSound(HWND);
    BOOL createStaticBuffer(DWORD, int);
    BOOL fillStaticBufferFromMem(void *, DWORD);
    void playStaticBuffer();
    void dsStop();
    void dsSetVolume(int);
    
    //*** andere Variablen
    int status = 0; //0: nicht los
                    //1: gerade wird abgespielt
                    //2: gerade wird abgespielt und die Frequenz wurde geändert
    
    //*** andere Funktionen
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    memArea createSineWave(unsigned int);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
    
        static TCHAR szAppName[] = _T("[AppName]");
        int xPos, yPos; //anfängliche Fensterposition
        int xRes, yRes; //Bildschirmauflösung
        WNDCLASSEX wndclass; //Struktur für die Fensterattribute
    
        //Bildschrimauflösung ermitteln
        xRes = GetSystemMetrics(SM_CXSCREEN);
        yRes = GetSystemMetrics(SM_CYSCREEN);
    
        //Fenster zentrieren
        xPos = (int) ((xRes - WND_WIDTH) / 2);
        yPos = (int) ((yRes - WND_HEIGHT) / 2);
    
        wndclass.cbSize = sizeof(WNDCLASSEX);
        wndclass.style = CS_OWNDC;                             //eigener Gerätekontext
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); //Hintergrundfarbe wie 3D-Elemente
        wndclass.lpszMenuName = NULL;
        wndclass.lpszClassName = szAppName;
        wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    
        RegisterClassEx(&wndclass); //Fensterklasse registrieren
    
        //Hauptfenster
        HWND hwnd = CreateWindowEx(WS_EX_STATICEDGE, szAppName, _T("SineWave"), WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, xPos, yPos, WND_WIDTH, WND_HEIGHT, NULL, NULL, hInstance, NULL);
    
        ShowWindow(hwnd, iCmdShow); //Fenster anzeigen
    
        UpdateWindow(hwnd); //Innenbereich neu zeichnen
    
        //Nachrichtenschleife
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0) == TRUE) { //Nachrichten empfangen; NULL, 0, 0: alle Nachrichten; TRUE: falls nicht WM_QUIT-Nachricht (Programm beenden) kommt
            TranslateMessage(&msg);                    //Nachricht konvertieren
            DispatchMessage(&msg);                     //Nachricht verteilen
        }
        return 0;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    
        static HDC hdc; //Gerätekontext
        PAINTSTRUCT ps; //Struktur zur Definition des zu zeichnenden Bereichs
        static SCROLLINFO si = {0}; //für Scrollbars
        static HWND hBtnPlay, hScrFreq, hScrVol, hStFreq, hStVol;
        HFONT hfont; //Schriftart für Buttons etc.
        HINSTANCE hInstance;
        char text[32];
    
        static unsigned int frequency = 100;
        static unsigned int volume = 100;
        memArea ma;
    
        switch (message) {
            case WM_CREATE:
                hInstance = (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE);
    
                hBtnPlay = CreateWindow(_T("BUTTON"), _T("Play / Stop"), BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 150, 70, 80, 30, hwnd, (HMENU) 1, hInstance, NULL);
                hScrFreq = CreateWindow(_T("SCROLLBAR"), _T("Frequency"), SBS_HORZ | WS_CHILD | WS_VISIBLE, 40, 20, 300, 20, hwnd, (HMENU) 2, hInstance, NULL);
                hScrVol = CreateWindow(_T("SCROLLBAR"), _T("Volume"), SBS_HORZ | WS_CHILD | WS_VISIBLE, 40, 130, 300, 20, hwnd, (HMENU) 3, hInstance, NULL);
                hStFreq = CreateWindow(_T("STATIC"), _T("Frequency: 100 Hz"), SS_LEFT | WS_CHILD | WS_VISIBLE, 350, 20, 100, 20, hwnd, (HMENU) 4, hInstance, NULL);
                hStVol = CreateWindow(_T("STATIC"), _T("Volume"), SS_LEFT | WS_CHILD | WS_VISIBLE, 350, 130, 100, 20, hwnd, (HMENU) 5, hInstance, NULL);
    
                //Schriftart setzen
                hfont = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
                SendMessage(hBtnPlay, WM_SETFONT, (WPARAM) hfont, MAKELPARAM(TRUE, 0));
                SendMessage(hStFreq, WM_SETFONT, (WPARAM) hfont, MAKELPARAM(TRUE, 0));
                SendMessage(hStVol, WM_SETFONT, (WPARAM) hfont, MAKELPARAM(TRUE, 0));
    
                //Scrollbars konfigurieren
                si.cbSize = sizeof(SCROLLINFO);
                si.fMask = SIF_POS | SIF_RANGE;
                si.nMin = 50;
                si.nMax = 1000;
                si.nPos = frequency;
                SetScrollInfo(hScrFreq, SB_CTL, &si,TRUE);
                si.nMin = 0; //[DSBVOLUME_MIN/MAX geht nicht, da negative Werte!]
                si.nMax = 100;
                si.nPos = volume;
                //[negative Werte evtl. abfragbar mit GetScrollInfo? s.u.]
                SetScrollInfo(hScrVol, SB_CTL, &si,TRUE);
    
                //DirectSound initialisieren
                dsInitialized = initDirectSound(hwnd);
    
                //Abbrechen, falls gescheitert
                if (!dsInitialized) {
                    MessageBox(hwnd, _T("DirectSoundCreate or SetCooperativeLevel failed"), _T("Error"), MB_OK | MB_ICONSTOP);
                    SendMessage(hwnd, WM_DESTROY, wParam, lParam);
                }
                return 0;
    
            case WM_PAINT:
                hdc = BeginPaint(hwnd, &ps);
                EndPaint(hwnd, &ps);
                return 0;
    
            case WM_COMMAND:
                if (wParam == 1) {
                    switch (status) {
                        case 0:
                            ma = createSineWave(frequency);
                            if (ma.pointer == NULL) MessageBox(hwnd, _T("VitualAlloc failed"), _T("Error"), MB_OK | MB_ICONSTOP);
                            else {
                                dsBufferCreated = createStaticBuffer(ma.size, volume);
    
                                if (!dsBufferCreated) MessageBox(hwnd, _T("CreateSoundBuffer (secondary) failed"), _T("Error"), MB_OK | MB_ICONSTOP);
                                else {
                                    dsBufferFilled = fillStaticBufferFromMem(ma.pointer, ma.size);
    
                                    if (!dsBufferFilled) MessageBox(hwnd, _T("Secondary buffer could not be filled"), _T("Error"), MB_OK | MB_ICONSTOP);
                                    else { 
                                        playStaticBuffer();
                                        status = 1;
                                    }
                                }
                            }
                            break;
    
                        case 1:
                            dsStop();
                            VirtualFree(ma.pointer, ma.size, MEM_DECOMMIT);
                            status = 0;
                            break;
    
                        case 2:
                            dsStop();
                            VirtualFree(ma.pointer, ma.size, MEM_DECOMMIT);
                            ma = createSineWave(frequency);
                            if (ma.pointer == NULL) MessageBox(hwnd, _T("VitualAlloc failed"), _T("Error"), MB_OK | MB_ICONSTOP);
                            else {
                                dsBufferCreated = createStaticBuffer(ma.size, volume);
    
                                if (!dsBufferCreated) MessageBox(hwnd, _T("CreateSoundBuffer (secondary) failed"), _T("Error"), MB_OK | MB_ICONSTOP);
                                else {
                                    dsBufferFilled = fillStaticBufferFromMem(ma.pointer, ma.size);
    
                                    if (!dsBufferFilled) MessageBox(hwnd, _T("Secondary buffer could not be filled"), _T("Error"), MB_OK | MB_ICONSTOP);
                                    else { 
                                        playStaticBuffer();
                                        status = 1;
                                    }
                                }
                            }
                            break;
                    }
                }
                return 0;
    
            case WM_HSCROLL:
                switch (LOWORD(wParam)) {
                    case SB_THUMBTRACK:
                    case SB_THUMBPOSITION:
                        if ((HWND) lParam == hScrFreq) {
                            frequency = HIWORD(wParam);
                            _snprintf(text, 30, "Frequency: %u Hz", frequency);
                            SetWindowText(GetDlgItem(hwnd, 4), _T(text));
                            if (status == 1) status = 2;
                        }
                        //[Abfrage mit GetScrollInfo geht nicht!]
                        if ((HWND) lParam == hScrVol) {
                            volume = HIWORD(wParam);
                            if (status > 0) dsSetVolume(volume);
                        }
                        si.fMask = SIF_POS;
                        si.nPos = HIWORD(wParam);
                        SetScrollInfo((HWND) lParam, SB_CTL, &si, TRUE);
                        break;
                }
                return 0;
    
            case WM_DESTROY:
                //DirectSound-Objekte löschen
                if (lpDSBSecondary != NULL) lpDSBSecondary->Release();
                if (lpDirectSound != NULL) lpDirectSound->Release();
    
                PostQuitMessage(0);
                return 0;
    
            default:
                return DefWindowProc(hwnd, message, wParam, lParam);
    
        }
    }
    
    /***********************************************************************************************/
    
    BOOL initDirectSound(HWND hwnd) { //erstellt ein DirectSound-Objekt, aber noch *keinen* sekundären Puffer
        HRESULT hResult;
    
        //DirectSound-Objekt erstellen
        hResult = DirectSoundCreate(NULL, &lpDirectSound, NULL);
        if (hResult != DS_OK) return FALSE;
    
        //Cooperative Level auf "normal" setzen
        hResult = lpDirectSound->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
        if (hResult != DS_OK) return FALSE;
    
        return TRUE;
    }
    
    BOOL createStaticBuffer(DWORD size, int volume) { //löscht den eventuell vorhandenen sekundären Puffer und legt einen neuen Puffer der angegebenen Größe mit der aktuellen Lautstärke an
        HRESULT hResult;
        WAVEFORMATEX waveFormat = {0};
        DSBUFFERDESC dsBufferDesc = {0};
    
        //vorhandenen Puffer löschen
        if (lpDSBSecondary != NULL) lpDSBSecondary->Release();
    
        //Ausgabeformat für sekundären Puffer
        waveFormat.wFormatTag = WAVE_FORMAT_PCM;
        waveFormat.nChannels = 1;
        waveFormat.nSamplesPerSec = 44100;
        waveFormat.wBitsPerSample = 16;
        waveFormat.nBlockAlign = 2;
        waveFormat.nAvgBytesPerSec = 88200;
    
        //sekundären Puffer anlegen
        dsBufferDesc.dwSize = sizeof (dsBufferDesc);
        dsBufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
        dsBufferDesc.dwBufferBytes = size;
        dsBufferDesc.dwReserved = 0;
        dsBufferDesc.lpwfxFormat = &waveFormat;
        hResult = lpDirectSound->CreateSoundBuffer(&dsBufferDesc, &lpDSBSecondary, NULL);
        if (hResult != DS_OK) return FALSE;
        else dsSetVolume(volume);
    
        return TRUE;
    }
    
    memArea createSineWave(unsigned int frequency) { //erzeugt *eine* Sinusschwingung der angegebenen Frequenz
                                                     //dazu wird ein Speicherbereich reserviert, dessen Position und Größe in der memArea-Struktur zurückgegeben wird
                                                     //DER SPEICHER MUSS AUSSERHALB DIESER FUNKTION WIEDER FREIGEGEBEN WERDEN, SOBALD ER UND DIE DATEN NICHT MEHR GEBRAUCHT WERDEN!
        memArea ma;
        int samples = 44100 / frequency; //44100 Hz Samplefrequenz ist fest vorgegeben
        int i;
    
        //Speicher reservieren
        ma.size = 2 * samples; //Größe des zu reservierenden Speicherbereichs; 2 Bytes pro Sample (16 bit Auflösung) sind fest vorgegeben
        ma.pointer = VirtualAlloc(NULL, ma.size, MEM_COMMIT, PAGE_READWRITE);
    
        //Sinusschwingung erzeugen
        if (ma.pointer != NULL) {
            for (i = 0; i < samples; i++) {
                *((short *) ma.pointer + i) = (short) (sin(((double) i / (double) samples) * 6.283185) * 32767.0);
            }
        }
    
        return ma;
    }
    
    BOOL fillStaticBufferFromMem(void *source, DWORD bytes) { //schreibt Daten ("bytes" Bytes) von "source" in den (statischen) sekundären Puffer
        HRESULT hResult;
        void *audioPtr1, *audioPtr2;
        DWORD audioBytes1, audioBytes2;
        DWORD act_bytes;
    
        //Bereich des Puffers (hier: ganzer Puffer) sperren
        hResult = lpDSBSecondary->Lock(0, 0, &audioPtr1, &audioBytes1, &audioPtr2, &audioBytes2, DSBLOCK_ENTIREBUFFER); //Lock-Größe wird sowieso ignoriert
        if (hResult != DS_OK) return FALSE;
    
        //Daten kopieren
        if (bytes <= audioBytes1) act_bytes = bytes;
        else act_bytes = audioBytes1;
        CopyMemory(audioPtr1, source, act_bytes);
    
        //Pufferbereich entsperren
        hResult = lpDSBSecondary->Unlock(audioPtr1, act_bytes, audioPtr2, 0);
        if (hResult != DS_OK) return FALSE;
    
        return TRUE;
    }
    
    void playStaticBuffer() { //spielt den sekundären Puffer im Loop-Modus ab
        lpDSBSecondary->SetCurrentPosition(0); //vom Anfang des Puffers an abspielen
        lpDSBSecondary->Play(0, 0, DSBPLAY_LOOPING);
    }
    
    void dsStop() {
        lpDSBSecondary->Stop();
    }
    
    void dsSetVolume(int volume) {
        int v = DSBVOLUME_MIN + (int) (((double) volume / 100.0) * (double) (DSBVOLUME_MAX - DSBVOLUME_MIN));
    
        lpDSBSecondary->SetVolume(v);
    }
    

Anmelden zum Antworten