Модераторы: Snowy, Alexeis, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Воспроизведение звука, Как воспроизвести звук синусоиды 
:(
    Опции темы
oleg2s
Дата 8.6.2012, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Доброе время суток.
Как воспроизвести звук синусоиды (прямоугольника) определенной частоты и длительности?
В случае прямоугольника желательно еще менять длительность меандра.
Beep, PlaySound, MessageBeep не подходят
Beep - просто пикает
MessageBeep - выдает системные звуки
PlaySound - воспроизводит звуки из заданного банка инструментов. В стандартных банках нет такого инструмента.
PM MAIL   Вверх
Чучмек
Дата 8.6.2012, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 2
Всего: 41



Код


uses ...,Mmsystem;

var h:HWAVE;
wf:tWAVEFORMATEX;
woh:array[0..1]of WAVEHDR;
bufs:array[0..1,0..65535,0..1]of smallint;



const
fL=59;  //Частота левого канала
fR=50;  //Частота правого канала
var
 nL:real=0;
 nR:real=0;
procedure callbackproc(h: integer;Msg,UserData,P1,P2:cardinal); stdcall;
var i:integer;
begin
if msg =WOM_DONE then
 begin
 for i:=0 to 65535 do
  begin
  psmallint(cardinal(PWAVEHDR(p1)^.lpData)+i*4)^:=smallint(trunc( 32767*sin(2*pi*nL)));
  psmallint(cardinal(PWAVEHDR(p1)^.lpData)+i*4+2)^:=smallint(trunc( 32767*sin(2*pi*nR)));
  nL:=frac(nL+fL/wf.nSamplesPerSec);
  nR:=frac(nR+fR/wf.nSamplesPerSec);
  end;
 waveOutWrite(h,pointer(p1),sizeof(woh[0]));
 end;

end;



procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
wf.wFormatTag:=WAVE_FORMAT_PCM;
wf.nChannels:=2;    //2 канала
wf.wBitsPerSample:=16;    //16 бит
wf.nBlockAlign:=(wf.nChannels * wf.wBitsPerSample)div 8;
wf.nSamplesPerSec:=44100;    //44,1 кГц
wf.nAvgBytesPerSec:=wf.nSamplesPerSec*wf.nBlockAlign;
waveOutOpen(@h,WAVE_MAPPER,@wf,cardinal(@callbackproc),0,CALLBACK_FUNCTION);


for i:=0 to 1 do
 begin
 fillchar(woh[i],sizeof(woh[i]),0);
 woh[i].lpData:=@(bufs[i]);
 woh[i].dwBufferLength:=sizeof(bufs[i]);
 woh[i].dwLoops:=1;
 waveOutPrepareHeader(h,@(woh[i]),sizeof(woh[i]));
 callbackproc(h,WOM_DONE,0,cardinal(@(woh[i])),0);
 end;
waveOutReStart(h);
end;


Это сообщение отредактировал(а) Чучмек - 8.6.2012, 14:59


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
oleg2s
Дата 13.6.2012, 05:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Спасибо, вроде работает.
Только как задать длительность?
Ну и разобраться надо еще, как это работает...
Есть над чем подумать.
PM MAIL   Вверх
Alexeis
Дата 13.6.2012, 13:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 55
Всего: 459



Цитата(oleg2s @  13.6.2012,  06:51 Найти цитируемый пост)
Только как задать длительность?

  Посмотри на 
Код

procedure callbackproc(h: integer;Msg,UserData,P1,P2:cardinal); stdcall;


когда она вызывается с параметром Msg = WOM_DONE, то буфер аудио данных отправлен аудио драйверу. Данный код обрабатывая сообщение WOM_DONE засылает очередную порцию сгеренированных данных. Если не реагировать на WOM_DONE, то буфер драйвера опустеет и звук прекратиться. Сколько данных передашь в буфер, столько и будет звучать. 1 секунда в этом формате займет wf.nAvgBytesPerSec байт.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
oleg2s
Дата 15.6.2012, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Спасибо, разобрался.
Еще один вопрос:
Почему в конце слышен небольшой щелчок?
Пытался заполнять буфер так, чтобы синусоида оканчивалась на нуле. Результат тот же :(
Стандартная процедура Beep тоже щелкает.

PM MAIL   Вверх
Dimonka2
Дата 20.6.2012, 18:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 40
Регистрация: 19.3.2009

Репутация: нет
Всего: нет



Цитата(oleg2s @  15.6.2012,  14:41 Найти цитируемый пост)
Почему в конце слышен небольшой щелчок?
Пытался заполнять буфер так, чтобы синусоида оканчивалась на нуле. Результат тот же :(

0 - это смотря в какой системе исчисления. 
В 16-ти битном звуке 0 - это $8000, а твой 0 - это максимальное отрицальное число, поэтому и щёлкает.
PM MAIL   Вверх
oleg2s
Дата 21.6.2012, 04:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Цитата(Dimonka2 @  20.6.2012,  18:15 Найти цитируемый пост)
В 16-ти битном звуке 0 - это $8000, а твой 0 - это максимальное отрицальное число, поэтому и щёлкает. 

Я заполняю буфер от -32767 до 32767 (десяч.) Значит надо закончить максимальным значением?
PM MAIL   Вверх
oleg2s
Дата 21.6.2012, 05:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Попробовал заполнить весь буфер 32768 ($8000). Слышны щелчки.
Заполнение буфера -32767, приведит к тому же результату.
Если заполнить буфер 0-м, то полная тишина. Вывод: В 16-ти битном звуке 0 - это НЕ $8000, а $0, он же и в десятичке 0.
PM MAIL   Вверх
Чучмек
Дата 23.6.2012, 07:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 2
Всего: 41



Попробуй, перед выключением, свести  плавно к нулю амплитуду.


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
oleg2s
Дата 25.6.2012, 04:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Причина ясна. Опытным путем проверил, что если сигнал заканчивается не в нуле, то появляются щенчки. Причем они слышны начиная со значения 100 (ну у кого какой слух). Теперь стоит две задачи:
Первая, практическая. Какой величины (крутизны) должен быть фронт? Какую кривую должен описывать этот фронт?
Вторая, математическая. Как описать кривую фронта?
Кто-нибудь занимался обработкой сигнала?

PM MAIL   Вверх
ivan219
Дата 25.6.2012, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1121
Регистрация: 19.11.2005
Где: Планета земля

Репутация: 4
Всего: 12



oleg2s у вас передача сигнала происходит блоками значит начало нового блока должно быть продолжение старого.

Код

Fi := 0;

Код

for t := 0 to N - 1 do X[t] := Sin(2 * Pi * F / Fd * t + Fi);
Fi := 2 * Pi * F / Fd * N + Fi;
if Fi > 2 * Pi then Fi := Fi - 2 * Pi;


И максимальное значение в 16бит звуке = 32767 а минимальное -32768
Так что делайте всегда так что бы ваше максимальное или минимальное значение было равно |32767|

Это сообщение отредактировал(а) ivan219 - 25.6.2012, 21:56
PM MAIL ICQ   Вверх
oleg2s
Дата 29.6.2012, 07:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Нет. У меня данные НЕ передаются блоками. У меня всего один блок заполненный синусоидой.
PM MAIL   Вверх
ivan219
Дата 3.7.2012, 19:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1121
Регистрация: 19.11.2005
Где: Планета земля

Репутация: 4
Всего: 12



Цитата(oleg2s @  29.6.2012,  07:08 Найти цитируемый пост)
Нет. У меня данные НЕ передаются блоками. У меня всего один блок заполненный синусоидой.

Ну правильно.
У Вас он один, но вы его постоянно блоками передаёте в звуковую карту и у же в ней, из этих блоков строится не правильная синусоида с разрывами между блоками по этому вы и слышите щелчки.
Смотрите ниже красным цветом это не правильная синусоида.
Синим та какая должна быть.
user posted image
Код

var
  Form1: TForm1;
  pSignal, pSignal1: Array[0..499] of Integer;

.
.
.

const
  F = 6.2355; // Частота сигнала
  Fd = 500;  // Частота дискретизации
  N = 100;   // Размер блока
var
  I, I1: Cardinal;
  Fi: Double;
begin
 Fi := 0;
 for I := 0 to 4 do
  begin
   for I1 := 0 to N - 1 do
    begin
     pSignal[I1 + I * N] := 50 - Round(50 * Sin(2 * Pi * I1 * F / Fd)); // Не правильно!
     pSignal1[I1 + I * N] := 50 - Round(50 * Sin(2 * Pi * I1 * F / Fd + Fi)); // Правильно! При любом значении F не будет разрыва фазы а значит и щелчков.
    end;
   Fi := Fi + 2 * Pi * N * F / Fd;
   Fi := Fi - 2 * Pi * Trunc(0.5 * Fi / Pi); // Нужно для того что бы Fi была в пределе 0..2 * Pi
  end;


Это сообщение отредактировал(а) ivan219 - 3.7.2012, 19:43
PM MAIL ICQ   Вверх
oleg2s
Дата 5.7.2012, 05:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 12.5.2012

Репутация: нет
Всего: 1



Нет. У меня ОДИН БЛОК и я его запускаю ОДИН РАЗ.
Блок длиной 65535, это примерно 1,5 сек при 44100.
Этого мне достаточно.
Теперь если сигнал заканчивается не на нуле, то слышен щелчек.
Пытался завалить фронт по огибающей синусоиде меньшей частоты. Эффект стал меньше, но при определенных частотах все же слышен. Пробовал заваливать фронт по убывающей прямой. Получилось лучше, но все же не так как хотелось бы.
По какой  кривой и какой длительности надо заваливать фронт? Вот в чем вопрос.
PM MAIL   Вверх
Чучмек
Дата 5.7.2012, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 2
Всего: 41



Попробуй по такой кривой

а=А-k*t^n


a - спадающая амплитуда
А- амплитуда синусоиды
t - время от начала спада
n - коэффициент крутизны 
k=A/(T^n)  
Т длительность спада от А до нуля

Попробуй с различными T и n (n = 0,3 ... 10)


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Звук, графика и видео"
Girder
Snowy
Alexeis

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • По вопросам разработки игр стоит заглянуть сюда

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Girder, Snowy.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Звук, графика и видео | Следующая тема »


 




[ Время генерации скрипта: 0.1973 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.