Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:

Error. Page cannot be displayed. Please contact your service provider for more details. (24)


Как вывести звук заданной частоты на колонки?

Поиск:
Недавно в FAQ'e С++ я увидел темку в которой объяснялось, как вывести звук заданной частоты на звуковую карту. Я подумал: "А как же такое сделать на VB?"

Вот объяснения mr.DUDA на тему того, что тут и как:

В WinAPI есть функция Beep, позволяющая вывести звук с заданной частотой и длительностью на звуковую карту. Но, к сожалению, в Win9x/Me она не поддерживает аргументы dwFreq и dwDuration (вместо этого система издаёт "стандартный" звук).

Для того, чтобы всё-таки вывести звук с заданными параметрами на саундкарту, можно использовать WinAPI-шную функцию 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<numSamples; 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);
}


//////////////////////////////////////////////////////////////////////////
// Тестовый звук - 900 Гц, одна секунда

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

Если кто-то сможет это переписать на VB, то он получит + в репутации, т.к. это непростое занятие. И именно поэтому я сделал проще. Я сделал dll c содержанием всего выше описанного и осталось только написать пару строк в VB.
Вот так выглядит исходник dll'ки:
dll.cpp
Код
#include "stdafx.h"
#include "windows.h"
#include "math.h"

// для VS 6.0 необходимо вставить еще
#include "Mmsystem.h"

#include "dll.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-чанка
};


extern "C" LIBRARY_EXPORT_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<numSamples; 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);
}

dll.h
Код
#ifndef _DLL_
#define _DLL_

#define LIBRARY_EXPORT_VOID __declspec(dllexport) void __stdcall

extern "C" LIBRARY_EXPORT_VOID SuperBeep(DWORD dwFrequency, DWORD dwMilliSeconds);

#endif

Откомпилировав это все получаем файл dll с одной единственной функцией: SuperBeep. dll я так и назвал superbeep.dll. Это файл я прикрепил к теме и поэтому все что вам остается сделать это скинуть его в системную папку.
Вот что надо написать на VB, чтобы получить звук с чистотой 4000 Hz и длительностью в 50 миллисекунд:
Код
Option Explicit

Private Declare Sub SuperBeep Lib "superbeep.dll" Alias "_SuperBeep@8" (ByVal lFrequency As Long, ByVal lMilliSeconds As Long)

Private Sub Command1_Click()
SuperBeep 4000, 50
End Sub

Цитата
Если кто-то сможет это переписать на VB, то он получит + в репутации, т.к. это непростое занятие.

+ получил -Mikle-. Вот его код:
Код
Option Explicit

'Описание ф-ии PlaySound изменено для того, чтоб иметь возможность
'передавать в качестве первого аргумента массив
'Первый параметр передается по ссылке(без ByVal) и имеет тип Any
Public Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" (lpszName As Any, ByVal hModule As Long, ByVal dwFlags As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Const SND_ASYNC = &H1
Public Const SND_MEMORY = &H4
Public Const SND_LOOP = &H8

Public Type WAVHEADER
   sigRIFF(3) As Byte    ' должно быть равно "RIFF"
   sizeRIFFch As Long    ' размер чанка RIFF
   sigWAVE(3) As Byte    ' должно быть равно "WAVE"
   sigFMT(3) As Byte    ' должно быть равно "fmt "
   sizeFMTch As Long    ' размер чанка FMT
   wFormatTag As Integer  ' категория формата, для PCM = 1
   wChannels As Integer   ' кол-во каналов: 1-моно 2-стерео
   dwSamplesPerSec As Long ' кол-во сэмплов в сек.
   dwAvgBytesPerSec As Long ' среднее число байт в сек
   wBlockAlign As Integer  ' выравнивание данных в дата-чанке
   wBitPerSample As Integer ' бит в сэмпле
   sigDATA(3) As Byte    ' должно быть равно "data"
   sizeDATAch As Long    ' размер data-чанка
End Type

Sub VBSuperBeep(dwFrequency As Long, dwMilliseconds As Long)
' частота дискретизации = 44100 Гц
' кол-во бит на сэмпл = 8
' если требуемая частота > 44100 или равна нулю, то выходим
If dwFrequency = 0 Or dwFrequency > 44100 Then Exit Sub

Dim Head As WAVHEADER

' длина дорожки в байтах
Dim numSamples As Long
numSamples = 44100 / dwFrequency

' выделяем память под дорожку
Dim Size As Long
Size = Len(Head) + numSamples

Dim buff() As Byte
ReDim buff(1 To Size)

'заполняем WAV-header
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

'копируем его в буфер
CopyMemory buff(1), Head, Len(Head)

Dim lpSamp As Long 'BYTE *samples = (BYTE*)(head+1)
lpSamp = Len(Head) + 1

'заполняем дорожку периодом синуса
Dim i As Long, b As Long

For i = 0 To numSamples - 1
   b = Abs(255 * Sin(6.28 * i / Size))
   buff(i + lpSamp) = CByte(b)
Next

'проигрываем звук
PlaySound buff(1), 0, SND_ASYNC Or SND_LOOP Or SND_MEMORY

'ждём заданное количество миллисекунд
Sleep dwMilliseconds

'останавливаем звук
PlaySound ByVal vbNullString, 0, SND_ASYNC
End Sub

'ПРОЦЕДУРА копирования из строки, в массив байт
'  В ней я проверяю некоторые моменты, и вывожу MsgBox
'  при не правильных параметрах на случай,
'  если кто-то решит пользоваться этой процедурой в своих программах
'ВНИМАНИЕ! я предполагаю что нижняя граница массива,
'  передаваемого в процедуру, равна нулю!

Private Sub StrCpy(Arr() As Byte, Expr As String)
   
   'Если нижняя граница массива >= 0(значит установлен массив)
   'И длина строки >= длине массива(лишь бы она не была меньше длины массива),
   'то копируем из ее содержимого столько байт, сколько длина массива
   
   If LBound(Arr) >= 0 And Len(Expr) >= UBound(Arr) + 1 Then
       CopyMemory Arr(0), ByVal Expr, UBound(Arr) + 1
   Else
       MsgBox "Не правильные аргументы в процедуре StrCpy!", vbCritical
       Stop
   End If

End Sub

Я заметил разницу в звуке когда экспериментировал с dll'кой, она также как и этот вариант дает разницу в звуке, при каждом вызове. Если поставить длительность звука 1000, откомпилировать проект, запустить ЕХЕ'шник и потом понажимать несколько раз на Command1, то будет чувствоваться разница в звуке.
Автор: cardinal, mr.DUDA, -Mikle-
Сайт: http://






Просмотров: 5699

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную