Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Работа со звуком в Visual C++


Автор: ud_sasha 24.7.2004, 20:06
Когда-то в Borland C++5 была (да и сейчас есть) функция sound(), которая выводила звук определенной частоты на встроенный динамик. Хотелось бы узнать как такое реализовать на Visual C++ 6.0, только звук выводить на звуковую карту. Итак, требуется, к примеру, заставить издавать звуковую карту звук частотой 900 Гц 1 секунду. Спасибо.

Автор: mr.DUDA 25.7.2004, 11:27
Есть такая функция, Beep называется. Но, к сожалению, в Win98/Me она не поддерживает аргументы dwFreq и dwDuration (вместо этого система издаёт "стандартный" звук).

Но можно сделать то же самое, используя PlaySound с параметрами SND_ASYNC | SND_LOOP | SND_MEMORY. Для остановки звука можно вызвать PlaySound с NULL в аргументе pszSound. Чтобы сформировать звук требуемой частоты прямо в памяти, достаточно выполнить ряд не слишком сложных действий, а именно:
- сформировать WAV-header
- заполнить дорожку сэмплами по периоду синусоиды
- длину дорожки подбирать в зависимости от требуемой частоты

Так как звук будет повторяться (SND_LOOP), то одного периода синусоиды будет достаточно. Вот пример, в котором реализована уже готовая функция SuperBeep, возвращающая управление после того, как звук отзвучит заданное количество миллисекунд (dwMilliSeconds). Кстати, можно и не ожидать завершения звучания -- для этого нужно запустить SuperBeep в отдельном потоке.

Исходный текст ф-ции SuperBeep с примером использования:
Цитата
#include "stdafx.h"
#include "windows.h"
#include "math.h"

// подключаем LIB-файл для ф-ции PlaySound
#pragma comment(lib, "winmm.lib")

// описание заголовка файла WAV
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-чанка
};


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;
   
strcpy(head->sigRIFF, "RIFF");
   
strcpy(head->sigWAVE, "WAVE");
   
head->sizeRIFFch = size - 8;
   
strcpy(head->sigFMT, "fmt ");
   
head->sizeFMTch = 16;
   
head->wFormatTag = 1;
   
head->wChannels = 1; // моно
   
head->dwSamplesPerSec = 44100;
   
head->dwAvgBytesPerSec = 44100;
   
head->wBlockAlign = 1;
   
head->wBitPerSample = 8;
   
strcpy(head->sigDATA, "data");
   
head->sizeDATAch = size;

   
// заполняем дорожку периодом синуса
   
BYTE *samples = (BYTE*)(head+1);
   
for(DWORD i=0; i<size; i++)
       
samples[i] = BYTE(255*sin(6.28*double(i)/double(size)));

   
// проигрываем звук
   
PlaySound((const char*)buff, 0, SND_ASYNC|SND_LOOP|SND_MEMORY);

   
// ждём заданное количество миллисекунд
   
Sleep(dwMilliSeconds);

   
// останавливаем звук
   
PlaySound(0, 0, SND_ASYNC);
}


int main(int argc, char* argv[])
{
   
SuperBeep(900, 1000);
   
return 0;
}

Автор: ud_sasha 25.7.2004, 14:38
Спасибо, то что надо!!!
только
Цитата
for(DWORD i=0; i<size; i++)

следует читать как:
Код
for(DWORD i=0; i<numSamples; i++)


иначе за пределы буфера начинаем писать.

Автор: Rutti 26.7.2004, 01:57
А как проще средствами VC++ воспроизвести MP3-файл?

Автор: gepard 26.7.2004, 04:49
Это надо тебе DirectX или OpenAL разбирать
А вообще, вот как просто можно воспроизвести звук *.wav:
Взято с одного из форумов:
Цитата

Написал отличную игру, осталось добавить звуки. Но почему-то не получается. Я пишу так:

#include <windows.h>
#include <mmsystem.h>
#include <windowsx.h>
...
sndPlaySound("C:\\WINME\\MEDIA\\TADA.wav", NULL);

Возникает ошибка:
error LNK2001: unresolved external symbol __imp__sndPlaySoundA@8

Что я делаю не так?
И есть ли в MFC какие-нибудь классы для работы со звуком?


schmidt
Писатель

Из: Frankfurt
Сообщения: 197
  Звуки в VC++

Послано: 05-07-2002 23:29    Цитата      Ответить



А не забыли Winmm.lib подключить?
Лучше использовать функцию PlaySound, на мой взгляд.

~~~~~~~~~~~~



Плюс вот это:
USES mmsystem;

sndPlaySound('C:\TEST.WAV',SND_ASYNC); // PLAY
sndPlaySound('C:\TETS.WAV',SND_ASYNC+SND_LOOP); // Loop Mode (зацикливание)
sndPlaySound(Nil,SND_ASYNC); //STOP

Думаю разберёшься.

Автор: chipset 26.7.2004, 04:52
Человеку видимо необходим формат *.MP3.. Наверное надо копать в сторону DirectMusic.

Автор: Rutti 26.7.2004, 23:26
chipset
Цитата
надо копать в сторону DirectMusic.


Так капни же!

Автор: gepard 27.7.2004, 05:52
biggrin.gif
Ты знаешь, какя лопата нужна?
Столько времени нужно.
Лучше учите OpenAL. хотя лопата и время от этого не уменьшились biggrin.gif

Автор: chipset 27.7.2004, 07:29
Это вечный вопрос..
Хотя ДиректИкс имхо перспективнее..

Автор: gepard 27.7.2004, 09:19
Его же вроде микрософт вообще не будет больше делать qstn.gif

Автор: maxim1000 27.7.2004, 17:24
Цитата
А как проще средствами VC++ воспроизвести MP3-файл?

ShellExecute... (описание можно найти в MSDN)

Автор: chipset 28.7.2004, 00:02
[quote]Его же вроде микрософт вообще не будет больше делать [quote]
ДА? qstn.gif
Я слышал что наоборот Ogl загибается biggrin.gif
Ох, флеймим товарищи... exclamation.gif

Автор: DeadProger 8.1.2005, 21:50
Где можно найти понятное объяснение основ DirectMusic?

Автор: chipset 8.1.2005, 21:54
DeadProger
MSDN.
Модератор: Пожалуйста, один топик - один вопрос.

Автор: qqqq1961 10.1.2015, 18:51
Цитата(mr.DUDA @ 25.7.2004,  11:27)
используя PlaySound ...
Код

#include "stdafx.h"
#include "windows.h"
#include "math.h"
#pragma comment(lib, "winmm.lib")
struct WAVHEADER
{
    char    sigRIFF[4];
    DWORD   sizeRIFFch;
    char    sigWAVE[4];
    char    sigFMT[4]; 
    DWORD   sizeFMTch; 
    WORD    wFormatTag;
    WORD    wChannels; 
    DWORD   dwSamplesPerSec;.
    DWORD   dwAvgBytesPerSec;
    WORD    wBlockAlign;    
    WORD    wBitPerSample;  
    char    sigDATA[4];     
    DWORD   sizeDATAch;     
};


void SuperBeep(DWORD dwFrequency, DWORD dwMilliSeconds)
{
    if(!dwFrequency || dwFrequency>44100)  return;
    DWORD numSamples = 44100 / dwFrequency;
    
    DWORD size = sizeof(WAVHEADER) + numSamples;
    void *buff = new char[size ];
    
    WAVHEADER *head = (WAVHEADER*)buff;
    strcpy(head->sigRIFF, "RIFF");
    strcpy(head->sigWAVE, "WAVE");
    head->sizeRIFFch = size - 8; 
    strcpy(head->sigFMT, "fmt ");
    head->sizeFMTch = 16;
    head->wFormatTag = 1;
    head->wChannels = 1; // моно
    head->dwSamplesPerSec = 44100;
    head->dwAvgBytesPerSec = 44100;
    head->wBlockAlign = 1;
    head->wBitPerSample = 8;
    strcpy(head->sigDATA, "data");
    head->sizeDATAch = size;

    BYTE *samples = (BYTE*)(head+1);

 !!!  for(DWORD i=0; i<size; i++) samples[i] = 0;
!!!   for(DWORD i=0; i<size; i++) samples[i] = BYTE(255*sin(6.28*double(i)/double(size)));
    

    PlaySound((const char*)buff, 0, SND_ASYNC|SND_LOOP|SND_MEMORY);
    Sleep(dwMilliSeconds);
    PlaySound(0, 0, SND_ASYNC);
!!!    
}


int main(int argc, char* argv[])
{
  SuperBeep(900, 1000);
}


Кроме предложенного ud_sasha:
Код

for(DWORD i=0; i<numSamples; i++)

Предлагаю исправить еще один выход за пределы буфера:

Код

for(DWORD i=0; i<numSamples; i++) samples[i] = BYTE(255*sin(6.28*double(i)/double(numSamples)));


И нужно деструктор в конце, особенно если нужно повторно функцию вызывать:
Код

  // останавливаем звук
  PlaySound(0, 0, SND_ASYNC);
  delete [] buff;

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