Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Звук под Windows


Автор: krasgames 27.3.2011, 08:53
Люди, есть ноутбук, не знаю, есть ли на нем спикер (Samsung R60). Нужно хоть как-то выжать из ноутбука гармонический сигнал) Ну хотя-бы через спикер, но есть ли он у меня... Про beep помню, но не получалось с ним, может что не то набирал, а на ноутбуке у меня ни один код не работал!!=( Дайте что-нибудь плз, чтобы точно работало.

Автор: semibug 27.3.2011, 09:06
Чтобы точно работало можно подключить USB спикер, который встанет звуковой картой. Воспроизвести звук на нем способом масса. Например с помощью плеера.

Автор: krasgames 27.3.2011, 09:24
Ну, например, cpp файл такой:
Код

// kon.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

BOOL Beep
(
DWORD 3000, // частота звука
DWORD 1 // длительность звучания
);

int _tmain(int argc, _TCHAR* argv[])
{   
    return 0;
}


остальное, как обычно сразу после создания нового проекта. Может я что-то не включил? Хотятут явно что-то надо для winapi.

Добавлено @ 09:26
Через звуковую карту или USB это можно, только если USB интерфейс замутить самому, я хз, что такое USB спикер, но тогда опять нужен кодsmile Что за плеер?

Автор: Albor 27.3.2011, 10:01
Код

#include "stdafx.h"
#include <windows.h>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{   
   if(Beep(1000,2000))
{
    std::cout<<"Beep OK"<<std::endl;
}
else std::cout<<"Beep not OK"<<std::endl;
    return 0;
}


Попробуй так. Если динамик есть то д.б. звук 1000Гц в течении 2 сек

Автор: krasgames 27.3.2011, 10:12
Попробовал, спасибо. Динамика нет=( А как со звуковой картой можно вообще работать?

Автор: borisbn 27.3.2011, 10:41
Код

#include <windows.h>

int main()
{
    PlaySound( имя файла с синусоидой, NULL, SND_ASYNC | SND_LOOP );
    return 0;
}


?

Автор: krasgames 27.3.2011, 11:21
Не, хочу именно сгенерировать сигнал, хоть с сопроцессора, хоть со звуковой карты. Сначала на высоком уровне.

Автор: borisbn 27.3.2011, 12:52
krasgames, не получается сгенерить сигнал или воспроизвести его ? Если второе см. http://msdn.microsoft.com/en-us/library/ms713464(v=vs.85).aspx

Автор: semibug 27.3.2011, 13:13
Генерировать можно с помощью функции sin (один период, остальные копией).
Или даже табличкой, например такой

Код

    // 44100 Hz, 16 bit, mono ~1kHz
    const unsigned short sinTab[40] = {
        0x0000, 0x1406, 0x278D, 0x3A1C, 0x4B3C, 0x5A82, 0x678D, 0x720C, 0x79BC, 0x7E6C,
        0x7FFF, 0x7E6C, 0x79BC, 0x720C, 0x678D, 0x5A82, 0x4B3C, 0x3A1C, 0x278D, 0x1406,
        0x0000, 0xEBFA, 0xD873, 0xC5E4, 0xB4C4, 0xA57E, 0x9873, 0x8DF4, 0x8644, 0x8194,
        0x8000, 0x8194, 0x8644, 0x8DF4, 0x9873, 0xA57E, 0xB4C4, 0xC5E4, 0xD873, 0xEBFA
    };


Добавлено через 8 минут и 39 секунд
Во, такой может спикер подойдет:
user posted image
 smile 

Автор: borisbn 27.3.2011, 13:30
Цитата(semibug @  27.3.2011,  13:13 Найти цитируемый пост)
Генерировать можно с помощью функции sin

Код

#include <math.h>

int main()
{
   const double Pi = acos( -1 );
   int outSampleRate = 22050; // выходная частота дискретизации. задаётся при воспроизведении
   int toneFreq = 1000; // частота генерируемого сигнала
   short amplitude = 20000; // амплитуда выходного сигнала. от 0 до 32767
   short buffer[ outSampleRate ];
   for ( int i = 0; i < outSampleRate; i++ )
   {
       buffer[ i ] = (short)( amplitude * sin( toneFreq / (double)outSampleRate * i * 2 * Pi ) );
   } 
}


а дальше http://msdn.microsoft.com/en-us/library/ms713464(v=vs.85).aspx

Автор: semibug 27.3.2011, 13:32
Если принципиально именно звуковой картой нагенерить, можно попробовать MIDI. Правда не уверен, возможно в наше время чаще делают софтовые реализации MIDI (внутри драйвера), т.е. чисто "аппаратной" генерации на упомянутом ноуте может и не выйти.

Добавлено через 1 минуту и 52 секунды
Чето даже призадумался, а точно ли синус, может все таки косинус..
Эх геометрия..

Автор: bsa 27.3.2011, 21:17
а может проще попробовать посмотреть в диспетчере устройств?

Автор: krasgames 11.4.2011, 04:08
borisbn, я пока только описание нашел там, а надо какие-то библиотеки скачать? Если просто вставить в .cpp код, расположенный ниже, то уже выдает ошибку:(
Код

#include "stdafx.h"
include <math.h>
int main()
{
   const double Pi = acos( -1 );
   int outSampleRate = 22050; // выходная частота дискретизации. задаётся при воспроизведении
   int toneFreq = 1000; // частота генерируемого сигнала
   short amplitude = 20000; // амплитуда выходного сигнала. от 0 до 32767
   short buffer[ outSampleRate ];
   for ( int i = 0; i < outSampleRate; i++ )
   {
       buffer[ i ] = (short)( amplitude * sin( toneFreq / (double)outSampleRate * i * 2 * Pi ) );
   } 
}

Автор: borisbn 11.4.2011, 08:29
Цитата(krasgames @  11.4.2011,  04:08 Найти цитируемый пост)
я пока только описание нашел там, а надо какие-то библиотеки скачать?

Это и есть только описание. Библиотек никаких не надо. Это всё функции WinAPI, а он встроен в винду.

Цитата(krasgames @  11.4.2011,  04:08 Найти цитируемый пост)
Если просто вставить в .cpp код, расположенный ниже, то уже выдает ошибку:(

Какой компилятор, какая ошибка и на какой строке рассказать религия не позволяет ?

Автор: krasgames 11.4.2011, 08:38
Компилятор Visio C++ 2008, про ошибку пишет что-то вроде undefined symbols или missing ; точно не помню, сейчас у меня ноут не с собой:( Если все так сложно, по приходу домой напишуsmile

Автор: borisbn 11.4.2011, 08:43
Цитата(krasgames @  11.4.2011,  04:08 Найти цитируемый пост)
include <math.h>

в начале пропустил знак #

Цитата(krasgames @  11.4.2011,  04:08 Найти цитируемый пост)
 const double Pi = acos( -1 );

замени на 
Код

const double Pi = acos( -1.0 );


Цитата(krasgames @  11.4.2011,  04:08 Найти цитируемый пост)
int outSampleRate = 22050;

замени на 
Код

const int outSampleRate = 22050;


Автор: leniviy 12.4.2011, 15:25
Что-то у вас ни про MMSystem, ни про DirectX. Я тут кое-что раскопал

Автор: krasgames 14.4.2011, 17:58
Цитата
// consule.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <math.h>
int main()
{
   const double Pi = acos( -1.0 );
   const int outSampleRate = 22050; // выходная частота дискретизации. задаётся при воспроизведении
   int toneFreq = 1000; // частота генерируемого сигнала
   short amplitude = 20000; // амплитуда выходного сигнала. от 0 до 32767
   short buffer[ outSampleRate ];
   for ( int i = 0; i < outSampleRate; i++ )
   {
       buffer[ i ] = (short)( amplitude * sin( toneFreq / (double)outSampleRate * i * 2 * Pi ) );
   } 
}

Ну теперь ошибок нет. Звук не выдает. 

Автор: borisbn 14.4.2011, 20:24
krasgames, это всего лишь генерация данных, которые, если озвучить (подать на звуковую), даст тон. Теперь нужно этот буфер (buffer) озвучить. как ? http://msdn.microsoft.com/en-us/library/ms713464(v=vs.85).aspx. 
и не раз...

Автор: krasgames 16.4.2011, 04:22
Не понимаю пока. В buffer записывается массив? И как его проиграть с помощью playsound? Там же надо уже файл открыть.

Автор: borisbn 16.4.2011, 09:05
PlaySound проигрывает файл, а я давал ссылку на функции проигрывания буфера.
Вот предпоследняя ссылка оттуда
msdn.microsoft.com/en-us/library/ms708482(v=vs.85).aspx

Автор: krasgames 17.4.2011, 05:08
Если этот код просто добавить после буфера, то выдает ошибки. Я пока не понимаю, что там делается

Автор: borisbn 17.4.2011, 10:11
Цитата(krasgames @  17.4.2011,  05:08 Найти цитируемый пост)
выдает ошибки

какие именно - религия не позволяет озвучить ?

Цитата(krasgames @  17.4.2011,  05:08 Найти цитируемый пост)
Я пока не понимаю, что там делается

там валом комментариев
Цитата
// Open a waveform device for output using window callback.

Цитата
// Allocate and lock memory for the waveform data.

Цитата
// Read the waveform data subchunk.

Цитата
// Allocate and lock memory for the header.

Цитата
// After allocation, set up and prepare header.

Цитата
// Now the data block can be sent to the output device. The 
// waveOutWrite function returns immediately and waveform 
// data is sent to the output device in the background.
 

Автор: krasgames 17.4.2011, 11:33
Пишет, что переменные не определены. cpp такой: 
Код

#include "stdafx.h"
#include <math.h>
#include <windows.h>
int main()
{
   const double Pi = acos( -1.0 );
   const int outSampleRate = 22050; // выходная частота дискретизации. задаётся при воспроизведении
   int toneFreq = 1000; // частота генерируемого сигнала
   short amplitude = 20000; // амплитуда выходного сигнала. от 0 до 32767
   short buffer[ outSampleRate ];
   for ( int i = 0; i < outSampleRate; i++ )
   {
       buffer[ i ] = (short)( amplitude * sin( toneFreq / (double)outSampleRate * i * 2 * Pi ) );
   } 

HANDLE hData  = NULL;  // handle of waveform data memory 
HPSTR  lpData = NULL;  // pointer to waveform data memory 
 
void WriteWaveData(void) 
{ 
    HWAVEOUT    hWaveOut; 
    HGLOBAL     hWaveHdr; 
    LPWAVEHDR   lpWaveHdr; 
    HMMIO       hmmio; 
    UINT        wResult; 
    HANDLE      hFormat; 
    WAVEFORMAT  *pFormat; 
    DWORD       dwDataSize; 

    // Open a waveform device for output using window callback. 

    if (waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, 
                    (LPWAVEFORMAT)pFormat, 
                    (LONG)hwndApp, 0L, CALLBACK_WINDOW)) 
    { 
        MessageBox(hwndApp, 
                   "Failed to open waveform output device.", 
                   NULL, MB_OK | MB_ICONEXCLAMATION); 
        LocalUnlock(hFormat); 
        LocalFree(hFormat); 
        mmioClose(hmmio, 0); 
        return; 
    } 
 
    // Allocate and lock memory for the waveform data. 
 
    hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwDataSize ); 
    if (!hData) 
    { 
        MessageBox(hwndApp, "Out of memory.", 
                   NULL, MB_OK | MB_ICONEXCLAMATION); 
        mmioClose(hmmio, 0); 
        return; 
    } 
    if ((lpData = GlobalLock(hData)) == NULL) 
    { 
        MessageBox(hwndApp, "Failed to lock memory for data chunk.", 
                   NULL, MB_OK | MB_ICONEXCLAMATION); 
        GlobalFree(hData); 
        mmioClose(hmmio, 0); 
        return; 
    } 
 
    // Read the waveform data subchunk. 
 
    if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != (LRESULT)dwDataSize) 
    { 
        MessageBox(hwndApp, "Failed to read data chunk.", 
                   NULL, MB_OK | MB_ICONEXCLAMATION); 
        GlobalUnlock(hData); 
        GlobalFree(hData); 
        mmioClose(hmmio, 0); 
        return; 
    } 
 
    // Allocate and lock memory for the header. 

    hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 
        (DWORD) sizeof(WAVEHDR)); 
    if (hWaveHdr == NULL) 
    { 
        GlobalUnlock(hData); 
        GlobalFree(hData); 
        MessageBox(hwndApp, "Not enough memory for header.", 
            NULL, MB_OK | MB_ICONEXCLAMATION); 
        return; 
    } 
 
    lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr); 
    if (lpWaveHdr == NULL) 
    { 
        GlobalUnlock(hData); 
        GlobalFree(hData); 
        MessageBox(hwndApp, 
            "Failed to lock memory for header.", 
            NULL, MB_OK | MB_ICONEXCLAMATION); 
        return; 
    } 
 
    // After allocation, set up and prepare header. 
 
    lpWaveHdr->lpData = lpData; 
    lpWaveHdr->dwBufferLength = dwDataSize; 
    lpWaveHdr->dwFlags = 0L; 
    lpWaveHdr->dwLoops = 0L; 
    waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); 
 
    // Now the data block can be sent to the output device. The 
    // waveOutWrite function returns immediately and waveform 
    // data is sent to the output device in the background. 
 
    wResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); 
    if (wResult != 0) 
    { 
        waveOutUnprepareHeader(hWaveOut, lpWaveHdr, 
                               sizeof(WAVEHDR)); 
        GlobalUnlock( hData); 
        GlobalFree(hData); 
        MessageBox(hwndApp, "Failed to write block to device", 
                   NULL, MB_OK | MB_ICONEXCLAMATION); 
        return; 
    } 
} 
}

Может что-то не включил?

Автор: borisbn 17.4.2011, 11:53
Цитата(krasgames @  17.4.2011,  11:33 Найти цитируемый пост)
Пишет, что переменные не определены. cpp такой: 

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

первое, что видно, так это то, что ты определил функцию WriteWaveData внутри функции main. Этого нельзя делать в Си++.
Ты знаешь, мне кажется с твоими знаниями Си++ тебе ещё рановато использовать winAPI. Не обижайся, я не пнуть тебя или посмеяться хочу, а помочь. Посмотри лучше другие языки (C#, Delphi, Python). Если же хочешь именно Си++, то начни с учебника, с учебных задач, а не с такой (не сказать, что сложной, но и вовсе не простой для новичка) задачи.

Автор: krasgames 17.4.2011, 13:56
Заново. Мои действия: 
1. буффер создал и включил его в функцию main, в итоге ошибок не выдало, это делал сугубо по инструкциям в посте:
Код

 const double Pi = acos( -1.0 );
   const int outSampleRate = 22050; // выходная частота дискретизации. задаётся при воспроизведении
   int toneFreq = 1000; // частота генерируемого сигнала
   short amplitude = 20000; // амплитуда выходного сигнала. от 0 до 32767
   short buffer[ outSampleRate ];
   for ( int i = 0; i < outSampleRate; i++ )
   {
       buffer[ i ] = (short)( amplitude * sin( toneFreq / (double)outSampleRate * i * 2 * Pi ) );
   } 

2. Вставил код с ссылки после функции main "для воспроизведения буфера". Ничего не менял, это код с сайта!
Сейчас по прежнему выдает ошибку, но пишет: "hwndApp undeclared", начиная с 36 строчки и кончая 121. И еще невозможно преобразовать кое-что на строке 57.
Просто я не сталкивался с такого рода задачами:( Вообще мы по специальности С++ изучали, но с уклоном в нужную сторону. Можно бы и в книге поискать, но у меня специальность вообще не в эту сторону, нельзя время терять, в своей области читать много:( Вот и спрашиваю у профессионалов, лень подсказать что ли?smile

Автор: leniviy 17.4.2011, 15:35
hwndApp - глобальная переменная типа HWND. В ней содержится описатель главного окна программы.
В примере опущена. Если создашь в студии с помощью мастера новый проект типа win32 application, то скорее всего в главном cpp файле будет объявлена эта переменная (возможно она будет называться не hwndApp, но тип у неё будет HWND )

Автор: krasgames 17.4.2011, 16:23
Так это будет не консольное приложение?

Автор: bsa 17.4.2011, 23:05
Цитата(krasgames @  17.4.2011,  13:56 Найти цитируемый пост)
Вообще мы по специальности С++ изучали, но с уклоном в нужную сторону.

C++ он и в африке С++. Уклонов у него нет.

На сколько я помню, основная твоя задача, проверить, имеется ли звуковуха или спикер в ноутбуке. Не думаю, что писать программу на С++ для этого является самым оптимальным путем. Проще проверить физическое наличие выходов и в диспетчере устройств наличие соответствующего девайса. Если там нет звуковухи, то пытаться воспроизвести звук глупо.
Для начала, можно вообще попробовать кликнуть на wav файл. Если винда ругнется, что нет устройства для воспроизведения, то можно откладывать ноут в сторону. Если начнет играть, но звука не будет, то следует попробовать подергать регуляторы громкости. Если не поможет, то с большой долей вероятности звуковуха (частично) сгорела, и ноут опять можно откладывать.

Автор: krasgames 20.4.2011, 11:25
Цитата
C++ он и в африке С++. Уклонов у него нет.
 Мы создавали консольные приложения, проводили математические вычисления и выводили результаты на экран. Я это имею ввиду. Не трогали работу процессора с внешними устройствами (кроме клавушки и монитора). С++ ярче и разнообразнее, чем кажется ;) smile Да мы и не пользовались сторонними библиотеками, юзали самые примитивные функции.
Цитата
Проще проверить физическое наличие выходов и в диспетчере устройств наличие соответствующего девайса

Нет. Моя цель - сгенерировать чистую синусоиду на выходе. Делаю частотомер, хочу замутить компьютерный генератор сигналов. Поэтому решение задачи невозможно данным путем. Про спикер хотел для личного развития. В дальнейшем виднеются цели, связанные с созданием произвольных сигналов, поэтому хочу все-таки придерживаться языка программирования.

Добавлено @ 11:37
Цитата
http://forum.vingrad.ru/forum/topic-311554.html
 Я создавал уже тему и забылsmile Сорри за 2 темы, это про одно и то же:(

Автор: krasgames 20.4.2011, 11:43
ООО. Рабочий кодsmile Только пока не понял, как он работает. Поразмышляю на досугеsmile
Код

// cons.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include "math.h"
// подключаем LIB-файл для ф-ции PlaySound
#pragma comment(lib, "winmm.lib")
// описание заголовка файла WAV
#pragma pack (push, 1)
struct WAVHEADER
{
    char    sigRIFF[4];     // должно быть равно "RIFF"
    DWORD   sizeRIFFch;     // размер чанка RIFF
    char    sigWAVE[4];     // должно быть равно "WAVE"
    char    sigFMT[4];      // должно быть равно "fmt "
    DWORD   sizeFMTch;      // размер чанка FMT
    WORD    wFormatTag;     // категория формата, для PCM = 1
    WORD    wChannels;      // кол-во каналов: 1-моно 2-стерео
    DWORD   dwSamplesPerSec;// кол-во сэмплов в сек.
    DWORD   dwAvgBytesPerSec;// среднее число байт в сек
    WORD    wBlockAlign;    // выравнивание данных в дата-чанке
    WORD    wBitPerSample;  // бит в сэмпле
    char    sigDATA[4];     // должно быть равно "data"
    DWORD   sizeDATAch;     // размер data-чанка
};
#pragma pack (pop)
void SuperBeep(DWORD dwFrequency, DWORD dwMilliSeconds)
{
    // частота дискретизации = 44100 Гц
    // кол-во бит на сэмпл = 8
    // если требуемая частота > 44100 или равна нулю, то выходим
    if(!dwFrequency || dwFrequency>44100)
        return;
    // длина дорожки в байтах
    DWORD numSamples = 44100 / dwFrequency;
   
    // выделяем память под дорожку
    DWORD size = sizeof(WAVHEADER) + numSamples;
    void *buff = new char[size];
   
    // заполняем WAV-header
    WAVHEADER *head = (WAVHEADER*)buff;
    memcpy(head->sigRIFF, "RIFF", 4);
    memcpy(head->sigWAVE, "WAVE", 4);
    head->sizeRIFFch = size - 8;
    memcpy(head->sigFMT, "fmt ", 4);
    head->sizeFMTch = 16;
    head->wFormatTag = 1;
    head->wChannels = 1; // моно
    head->dwSamplesPerSec = 44100;
    head->dwAvgBytesPerSec = 44100;
    head->wBlockAlign = 1;
    head->wBitPerSample = 8;
    memcpy(head->sigDATA, "data", 4);
    head->sizeDATAch = size;
    // заполняем дорожку периодом синуса
    BYTE *samples = (BYTE*)(head+1);
    for(DWORD i=0; i<numSamples; i++)
        samples[i] = BYTE(255*sin(6.28*double(i)/double(size)));
    // проигрываем звук
   // PlaySound((const char*)buff, 0, SND_ASYNC|SND_LOOP|SND_MEMORY);
    PlaySound((LPCTSTR)buff, 0, SND_ASYNC|SND_LOOP|SND_MEMORY);
    // ждём заданное количество миллисекунд
    Sleep(dwMilliSeconds);
    // останавливаем звук
    PlaySound(0, 0, SND_ASYNC);
}
//////////////////////////////////////////////////////////////////////////
// Тестовый звук - 900 Гц, одна секунда
int main(int argc, char* argv[])
{
    /*
    int i = PlaySound(TEXT("1.wav"), NULL, SND_SYNC | SND_FILENAME);
    if (i==S_OK){
        printf("%s","allOk" );
    }else{
        printf("%s","error" );
    }
*/
    //Beep(500, 200) ;
    //Sleep(5000);
    SuperBeep(900, 1000);
    return 0;
}


Вроде одна строчка говорит, что это синусоида, но так ли это? А частоты не совпадают. Наверное, в функции дело. 440 и 880 - звучат не через октаву. http://www.gitaristam.ru/school/frequency.htm

Автор: krasgames 22.4.2011, 13:24
Что делать то? Жду приказа, господин!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)