Разработка синтезатора звука в среде визуального программирования Delphi.
Программная реализация
Основные сведения о генераторе звука Источниками звука могут стать любые явления, вызывающие местное изменение давления или механическое напряжение. Широко распространены источники звука в виде колеблющихся твёрдых тел (например, диффузоры громкоговорителей и мембраны телефонов, струны и деки музыкальных инструментов; в ультразвуковом диапазоне частот — пластинки и стержни из пьезоэлектрических… Читать ещё >
Разработка синтезатора звука в среде визуального программирования Delphi. Программная реализация (реферат, курсовая, диплом, контрольная)
Министерство образования Республики Беларусь Учреждение образования
«Гомельский государственный университет имени Франциска Скорины»
Факультет математический Кафедра вычислительной математики и программирования Разработка синтезатора звука в среде визуального программирования Delphi. Программная реализация Курсовой проект Исполнитель:
студент группы ПO-32
Дубовик Т. С.
Научный руководитель:
к.т.н., доцент кафедры Цурганова Л. А.
Гомель 2014
Введение
Звук — физическое явление, представляющее собой распространение в виде упругих волн механических колебаний в твёрдой, жидкой или газообразной среде. В узком смысле под звуком имеют в виду эти колебания, рассматриваемые по отношению к тому, как они воспринимаются органами чувств животных и человека.
Как и любая волна, звук характеризуется амплитудой и спектром частот. Обычно человек осознаёт колебания, передаваемые по воздуху, в диапазоне частот от 16—20 Гц до 15—20 кГц. Звук ниже диапазона слышимости человека называют инфразвуком; выше: до 1 ГГц, — ультразвуком, от 1 ГГц — гиперзвуком.
Восприятие посредством слуха создает акустическое пространство, центр которого в каждый данный момент находится там, где находится источник звука, — в отличие от визуального пространства, центром которого является каждый воспринимающий посредством зрения человек.
Среди слышимых звуков следует особо выделить фонетические, речевые звуки и фонемы (из которых состоит устная речь) и музыкальные звуки (из которых состоит музыка).
Различают продольные и поперечные звуковые волны в зависимости от соотношения направления распространения волны и направления механических колебаний частиц среды распространения.
В своём проекте я подробно рассмотрю генерацию звуковых волн и создание собственного источника (генератора звука) с помощью средства разработки Delphi.
Целью данного курсового проекта является подробное ознакомление с принципами генерации звука и создание собственного генератора звука.
1. Основные сведения о генераторе звука Источниками звука могут стать любые явления, вызывающие местное изменение давления или механическое напряжение. Широко распространены источники звука в виде колеблющихся твёрдых тел (например, диффузоры громкоговорителей и мембраны телефонов, струны и деки музыкальных инструментов; в ультразвуковом диапазоне частот — пластинки и стержни из пьезоэлектрических материалов или магнитострикционных материалов). Источниками звука могут служить и колебания ограниченных объёмов самой среды (например, в органных трубах, духовых музыкальных инструментах, свистках и т. п.).
Чистый звуковой тон представляет собой звуковую волну, подчиняющуюся синусоидальному закону:
у =,
где — максимальная амплитуда синусоиды;
— частота (=);
— количество колебаний упругой среды в секунду ();
— период;
— время (параметрическая переменная).
Звук характеризуется частотой (f), обычно измеряемой в герцах, т. е. количеством колебаний в секунду, и амплитудой (у). Амплитуда звуковых колебаний определяет громкость звука.
Для монотонного звука (меандр.) характерно постоянство амплитуды во времени.
Затухающие звуковые колебания характеризуются уменьшением амплитуды с течением времени.
Человек воспринимает механические колебания частотой 20 Гц — 20 КГц (дети — до 30 КГц) как звуковые. Колебания с частотой менее 20 Гц называются инфразвуком, колебания с частотой более 20 КГц — ультразвуком. Для передачи разборчивой речи достаточен диапазон частот от 300 до 3000 Гц.
Если несколько чистых синусоидальных колебаний смешать, то вид колебания изменится — колебания станут несинусоидальными.
Особый случай, когда смешиваются не любые синусоидальные колебания, а строго определенные, частота которых отличается в два раза (гармоники).
Основная гармоника имеет частоту, и амплитуду а1; вторая гармоника — частоту f2 и амплитуду а2; третья гармоника соответственно f3 и a3.
Причем f1а2>а3,При бесконечном количестве таких гармоник образуется периодический сигнал, состоящий из прямоугольных импульсов.
На слух всякое отклонение от синусоиды приводит к изменению звучания. В IBM PC источником звуковых колебаний является динамик (PC Speaker), воспроизводящий частоты приблизительно от 2 до 8 КГц. Для генерации звука в PC Speaker используются прямоугольные импульсы.
Синусоидальные сигналы в ЭВМ можно получить только с помощью специальных устройств — аудиоплат.
1.1 Частотный синтез Многоголосый частотный синтезатор предназначен для генерации звуковых сигналов сложной формы. Существуют два принципиально различных способа синтеза звуковых сигналов:
частотный синтез (FM — Fregueney Modulation);
волновой синтез (WS — Ware Synthesys).
Частотные синтезаторы (модуляторы) генерируют звуковые колебания синусоидальной формы заданной частоты и амплитуды, благодаря чему значительно улучшается качество звука (по сравнению с попытками генерировать звук с помощью прямоугольных колебаний). Наличие нескольких генераторов позволяет использовать эти устройства для синтеза сложных звуковых сигналов, в том числе речи.
Тембр звука формируется воздействием одной простой волны на другую с целью изменения ее частоты. Под воздейтсвием частотной модуляции возникают более спектрально богатые и сложные звуки, которые невозможно получить другими типами синтеза.
Впервые о применении частотной модуляции для синтеза звука задумался в 1966 году американец John Chowning, в будущем директор Центра компьютерных исследований музыки и акустики (CCRMA) Стенфордского университета, а на тот момент времени — преподаватель композиции кафедры электронной музыки.
В своём проекте я воспользовался методом генерации путём частотной модуляции, потому что он является достаточно эффективным и простым для реализации, к тому же спектр звуков, создаваемый с помощью частотной модуляции, действительно огромен.
2. Технология разработки генератора звука Я разработал программу генератор звука в среде Borland Delphi с использованием стандартных классов TMemoryStream (для хранения звука в виде бинарных данных) и TStrings (для хранения характеристик конкретной частоты). Также описал новый класс TFreqObj и использовал достаточно нестандартный класс TWaveFormatEx для хранения формата аудиоданных.
При запуске пользователь может настроить громкость и частоту звука, также он должен выбрать качество звука и время проигрывания в миллисекундах (0 — зациклить). После нажатия кнопки «Старт» пользователь услышит синусоидальный звук соответствующей громкости и частоты.
Сейчас я подробно опишу используемые классы, а в дальнейшем подробно разберу процедуру MakeComplexSound.
2.1 Класс TFreqObj
Я создал класс TFreqObj для удобства хранения и последующего использования характеристик частоты звука, таких, как:
— максимальная амплитуда синусоиды;
— частота (=);
— количество колебаний упругой среды в секунду ().
Также в нём описан простейший конструктор с параметрами и функция приведения всех параметров в одну форматированную строку.
2.2 Класс TWaveFormatEx
Для хранения информации об аудио-данных мы будем использовать класс TWaveFormatEx. Структура TWaveFormatEx определена следующим образом:
typedef struct
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX;
Описание полей следующее:
wFormatTag указывает тип аудио-данных. Нас интересуют только несжатые аудио-данные (PCM), поэтому для нас нужно чтобы тут было значение 0×0001 (то есть 1).
nChannels определяет количество каналов.
nSamplesPerSec определяет норму отбора в секунду. Обычно используется значение 44 100 Гц.
nAvgBytesPerSec чаще всего определяет среднюю скорость передачи байтов в секунду.
nBlockAlign определяет выравнивание в байтах.
wBitsPerSample определяет количество бит для выборки. Обычно равно 8 либо 16.
cbSize определяет размер всей структуры WAVEFORMATEX. Что в итоге равняется 18 байтам.
3 Алгоритмы и программная реализация генератора звука Суть метода генерации состоит в следующем: в текстовом виде хранятся характеристики конкретной частоты (длина волны, частота и т. д.)в формате TFreqObj, затем создаётся экземпляр класса TWaveFormatEx (он предназначен для приведения звуковой информации в понятный аудиоплате вид), этот класс заполняется информацией о звуке и затем в него добавляется сгенерированная в зависимости от характеристик конкретной частоты информация (грубо говоря, звук в виде бинарных данных) и отсылается функцией PlaySound на аудиоплату.
3.1 Процедура MakeComplexSound
Данная процедура заполняет формат аудиоданных TWaveFormatEx, затем его заполняет сначала необходимыми низкими частотами (они нужны для корректного воспроизведения звука), а затем данными в зависимости от выбранной пользователем частоты.
Заполнение формата TWaveFormatEx:
with WaveFormatEx do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := Mono;
nSamplesPerSec := SampleRate;
wBitsPerSample := $ 0008;
nBlockAlign := (nChannels * wBitsPerSample) div 8;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0;
end;
Заполнение объекта типа TMemoryStream для последующего его отправления в процедуру PlaySound:
MS[n] := TMemoryStream. Create;
with MS[n] do
begin
DataCount := (Duration * SampleRate) div 1000;
RiffCount := Length (WaveId) + Length (FmtId) + SizeOf (DWORD) +
SizeOf (TWaveFormatEx) + Length (DataId) + SizeOf (DWORD) + DataCount;
Write (RiffId[1], 4); // 'RIFF'
Write (RiffCount, SizeOf (DWORD)); // file data size
Write (WaveId[1], Length (WaveId)); // 'WAVE'
Write (FmtId[1], Length (FmtId)); // 'fmt '
TempInt := SizeOf (TWaveFormatEx);
Write (TempInt, SizeOf (DWORD)); // TWaveFormat data size
Write (WaveFormatEx, SizeOf (TWaveFormatEx)); // WaveFormatEx record
Write (DataId[1], Length (DataId)); // 'data'
Write (DataCount, SizeOf (DWORD)); // sound data size
minfreq:=TFreqObj (freqlist.objects[0]).ftemp;
maxval:=0;
freqerror:=false;
sampdiv2:=samplerate div 2;
for i := 0 to trunc (2/minfreq*samplerate) do
begin
soundvalue:=0;
for j:=0 to freqlist. count-1 do
if TFreqObj (freqlist.objects[j])<>nil then
with TFreqObj (freqlist.objects[j]) do
begin
if ftemp>sampdiv2 then freqerror:=true;
w := 2 * Pi * Ftemp;
ph:=p/pi;
SoundValue:=soundvalue+trunc (Volume*a/1000*sin (ph+i*w/SampleRate);
end;
If soundvalue>maxval
then maxval:=soundvalue;
end;
for i := 0 to DataCount — 1 do
begin
soundvalue:=127;
for j:=0 to freqlist. count-1 do
if TFreqObj (freqlist.objects[j])<>nil then
with TFreqObj (freqlist.objects[j]) do
begin
if ftemp< sampdiv2 then
begin
ptspercycle:=samplerate/Ftemp;
if j=0 then setlength (imagedata, min (datacount, trunc (5*ptspercycle)));
x:=frac (i/ptspercycle+p/360);
amp:=a/1000 ;
w := 2 * Pi * Ftemp;
ph:=p/pi;
SoundValue:=soundvalue+trunc (Volume*amp*sin (ph+i*w / SampleRate));
end;
end;
if maxval>127 then byteval:=soundvalue*127 div maxval
else byteval:=soundvalue;
Write (Byteval, SizeOf (Byte));
If i<=high (imagedata) then imagedata[i]: =byteval;
end;
end;
3.2 Запись звука в файл Получившийся звук можно записать в файл формата .WAV. Создавая поток для проигрывания нашей волны, мы уже задали в самом его начале формат данных, все характеристики нашей звуковой волны, то есть мы имеем заголовок и собственно звуковую волну в виде потока данных. Класс TMemoryStream, которым мы пользуемся для хранения потока в памяти, содержит метод SaveToFile. С помощью данного метода мы сохраняем наш поток в файл формата .WAV длиной в 1 секунду. Данный файл может быть воспроизведён в любом проигрывателе.
Ниже представлен код процедуры записи звука в файл:
procedure TForm1. Button1Click (Sender: TObject);
begin программа генератор звук
if Button1. Caption='Запись в файл' then
begin
PlayBtn.Click;
Button1.Caption:='Сохранить';
end
else if Button1. Caption='Сохранить' then
begin
PlaySound (nil, 0, SND_Purge);
playing:=false;
if SaveDialog2. Execute then
begin
ms[streaminuse]. SaveToFile (SaveDialog2.FileName);
Button1.Caption:='Запись в файл';
if assigned (ms[streaminuse]) then freeandnil (Ms[streaminuse]);
end;
end;
end;
Заключение
В ходе выполнения курсового проекта были изучены основы программирования для работы со звуком: изучены основные понятия, некоторые классы для работы со звуком, а также использование потоков в создаваемом приложении. В качестве примера полученных навыков было разработано приложение «Генератор звука».
Разработанное приложение состоит из следующих основных классов: TFreqObj, TMemoryStream, TWaveFormatEx; также был использован модуль MMSystem. Класс TFreqObj хранит в себе характеристики конкретной частоты, TMemoryStream используется для хранения аудиоданных в бинарном виде для последующего воспроизведения, а TWaveFormatEx — для хранения формата аудиоданных и таких его характеристик, как качество звуки и типа данных.
Результат работы может использоваться на любом ПК для создания и изучения синусоидального звука.
Список использованных источников
Википедия — свободная энциклопедия // URL: https://www.wikipedia.org
GameDev.ru — крупнейший ресурс в России о создании компьютерных игр // URL: https://www.gamedev.ru
Soundcoding.ru — программирование звука в среде Windows // URL: https://www.soundcoding.ru
Кинтцель, Т. Руководство программиста по работе со звуком / Т. Кинтцель. — М.: ДМК, 2000. — 432 с.
Приложение, А Скриншот работы программы
Приложение Б Исходный код
unit U_SoundGen2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
MPlayer, mmsystem, StdCtrls, ComCtrls, Menus, CheckLst, ExtCtrls, shellAPI, Buttons;
type
TfreqObj=class (TObject)
ftemp, f, P, a, shape:INTEGER;
StringRep:String;
constructor Create (newf, newP, newA, newshape: integer);
procedure makestringrep;
end;
TVolumeLevel = 0.127 ;
TForm1 = class (TForm)
PageControl1: TPageControl;
IntroSheet: TTabSheet;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
SoundSheet: TTabSheet;
Label3: TLabel;
VolLbl: TLabel;
FreqLbl: TLabel;
Label1: TLabel;
Label6: TLabel;
PlayBtn: TButton;
StopBtn: TButton;
VolBar: TTrackBar;
ListBox1: TCheckListBox;
Freqbar: TTrackBar;
RateRgrp: TRadioGroup;
VolEdit: TEdit;
FreqEdit: TEdit;
Edit1: TEdit;
Unitsgrp: TRadioGroup;
Duration: TUpDown;
Label2: TLabel;
Label4: TLabel;
Label5: TLabel;
Button1: TButton;
SaveDialog2: TSaveDialog;
procedure PlayBtnClick (Sender: TObject);
procedure StopBtnClick (Sender: TObject);
procedure VolBarChange (Sender: TObject);
procedure FormCreate (Sender: TObject);
procedure FreqbarChange (Sender: TObject);
procedure RateRgrpClick (Sender: TObject);
procedure VolEditChange (Sender: TObject);
procedure FreqEditChange (Sender: TObject);
procedure FreqEditKeyPress (Sender: TObject; var Key: Char);
procedure Button1Click (Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
MS: array[0.1] of tmemorystream;
StreamInUse:integer;
datacount:integer;
soundname, soundfilename: string;
soundfilelist:TStringList;
modified:boolean;
playing:boolean;
checkclicked:boolean;
imagedata:array of byte;
procedure MakeComplexSound (n:integer; freqlist: TStrings;
Duration{mSec}: Integer; Volume: TVolumeLevel);
procedure MsPlaySound;
procedure savesound;
procedure LoadSound (name:string);
procedure checkplaying;
end;
var
Form1: TForm1;
SampleRate: Integer = 11 025; // 8000, 11 025, 22 050, or 44 100
implementation
{$R *.DFM}
uses math, U_SetFreq;
function makesoundname (name:string):string;
var n: integer;
s:string;
begin
s:=extractfilename (name);
n:=pos ('.', s);
if n>0 then delete (s, n, length (s)-n+1);
result:=s;
end;
var shapenames: array[0.3] of string=('Sine','Square','Sawtooth','Triangle');
defaultname:string='DEFAULT.SND';
Constructor TFreqObj. Create;
begin
inherited create;
f:=newf;
ftemp:=f;
p:=newp;
a:=newA;
shape:=newSHAPE;
makestringrep;
end;
procedure TFreqObj. makestringrep;
begin
stringrep:=format ('%5d (F:%4d, P:%4d, A:%4d %S)',[ftemp, f, p, a, SHAPENAMES[SHAPE]]);
end;
const
Mono: Word = $ 0001;
RiffId: string = 'RIFF';
WaveId: string = 'WAVE';
FmtId: string = 'fmt ';
DataId: string = 'data';
procedure TForm1. MakeComplexSound (N:integer {stream # to use};
freqlist:TStrings;
Duration{mSec}: Integer;
Volume: TVolumeLevel);
var
WaveFormatEx: TWaveFormatEx;
i, j, TempInt, RiffCount: integer;
SoundValue: integer;
Byteval:byte;
minfreq, maxval: integer;
w, ph, amp: double;
freqerror:boolean;
sampdiv2:integer;
msg:string;
ptspercycle, x: extended;
begin
with WaveFormatEx do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := Mono;
nSamplesPerSec := SampleRate;
wBitsPerSample := $ 0008;
nBlockAlign := (nChannels * wBitsPerSample) div 8;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0;
end;
MS[n] := TMemoryStream. Create;
with MS[n] do
begin
DataCount := (Duration * SampleRate) div 1000;
RiffCount := Length (WaveId) + Length (FmtId) + SizeOf (DWORD) +
SizeOf (TWaveFormatEx) + Length (DataId) + SizeOf (DWORD) + DataCount;
Write (RiffId[1], 4); // 'RIFF'
Write (RiffCount, SizeOf (DWORD)); // file data size
Write (WaveId[1], Length (WaveId)); // 'WAVE'
Write (FmtId[1], Length (FmtId)); // 'fmt '
TempInt := SizeOf (TWaveFormatEx);
Write (TempInt, SizeOf (DWORD)); // TWaveFormat data size
Write (WaveFormatEx, SizeOf (TWaveFormatEx)); // WaveFormatEx record
Write (DataId[1], Length (DataId)); // 'data'
Write (DataCount, SizeOf (DWORD)); // sound data size
minfreq:=TFreqObj (freqlist.objects[0]).ftemp;
maxval:=0;
freqerror:=false;
sampdiv2:=samplerate div 2;
for i := 0 to trunc (2/minfreq*samplerate) do
begin
soundvalue:=0;
for j:=0 to freqlist. count-1 do
if TFreqObj (freqlist.objects[j])<>nil then
with TFreqObj (freqlist.objects[j]) do
begin
if ftemp>sampdiv2 then freqerror:=true;
w := 2 * Pi * Ftemp;
ph:=p/pi;
SoundValue := soundvalue+ trunc (Volume * a/1000* sin (ph+i * w / SampleRate));
end;
If soundvalue>maxval
then maxval:=soundvalue;
end;
for i := 0 to DataCount — 1 do
begin
soundvalue:=127;
for j:=0 to freqlist. count-1 do
if TFreqObj (freqlist.objects[j])<>nil then
with TFreqObj (freqlist.objects[j]) do
begin
if ftemp< sampdiv2 then
begin
ptspercycle:=samplerate/Ftemp;
if j=0 then setlength (imagedata, min (datacount, trunc (5*ptspercycle)));
x:=frac (i/ptspercycle+p/360);
amp:=a/1000 ;
w := 2 * Pi * Ftemp;
ph:=p/pi;
SoundValue := soundvalue+ trunc (Volume * amp* sin (ph+i * w / SampleRate));
end;
end;
if maxval>127 then byteval:=soundvalue*127 div maxval
else byteval:=soundvalue;
Write (Byteval, SizeOf (Byte));
If i<=high (imagedata) then imagedata[i]: =byteval;
end;
end;
end;
procedure TForm1. msPlaySound;
var options: integer;
begin
options:=SND_MEMORY or SND_ASYNC;
if duration. position=0 then options:=options or SND_LOOP;
PlaySound (MS[streaminuse]. Memory, 0, options);
end;
procedure TForm1. PlayBtnClick (Sender: TObject);
var
nextstream:integer;
freqlist:TStringlist;
i:integer;
dur:integer;
begin
freqlist:=TStringlist.create;
with listbox1 do
if items. count>0 then
begin
for i:=0 to items. count-1 do if checked[i]
then freqlist. addobject (items[i], items. objects[i]);
nextstream:=(streaminuse+1) mod 2;
if freqlist. count>0 then
begin
dur:=duration.position;
if unitsgrp. itemindex=1 then dur:=dur*1000;
if dur=0 then dur:=5000;
MakeComplexSound (nextstream, freqlist, dur, Volbar. position);
stopbtnclick (sender);
playing:=true;
streaminuse:=nextstream;
MsPlaySound;
end
else stopbtnclick (sender);
freqlist.free;
end;
end;
procedure TForm1. StopBtnClick (Sender: TObject);
begin
PlaySound (nil, 0, SND_Purge);
if assigned (ms[streaminuse]) then freeandnil (Ms[streaminuse]);
playing:=false;
end;
procedure TForm1. FormCreate (Sender: TObject);
begin
streaminuse:=1;
pagecontrol1.activepage:=SoundSheet;
loadsound ('-Default.snd');
end;
procedure TForm1. CheckPlaying;
begin
if playing then playbtnclick (self)
else
begin
playbtnclick (self);
stopbtnclick (self);
end;
end;
Procedure TForm1. savesound;
var
ff:textfile;
i:integer;
begin
assignfile (ff, soundfilename);
rewrite (ff);
writeln (ff,'D',' ', duration. position,' ', unitsgrp. itemindex);
for i:=0 to listbox1.items.count-1 do
with listbox1, TFreqObj (items.objects[i]) do writeln (ff,
integer (checked[i]),' ', f,' ', p,' ', a,' ', shape,' ', stringrep);
closefile (ff);
modified:=false;
end;
Procedure TForm1. Loadsound (name:string);
var
ff:textfile;
t:TFreqobj;
chk:integer;
d:char;
dur, units: integer;
begin
soundfilename:=name;
assignfile (ff, soundfilename);
reset (ff);
read (ff, d);
if d='D' then
begin
readln (ff, dur, units);
duration.position:=dur;
unitsgrp.itemindex:=units;
end
else reset (ff);
soundname:=makesoundname (soundfilename);
listbox1.clear;
while not eof (ff) do
with listbox1 do
begin
t:=tfreqobj.create (0,0,0,0);
with t do readln (ff, chk, f, p, a, shape, stringrep);
t.ftemp:=t.f;
items.AddObject (t.stringrep, t);
checked[items.count-1]: =chk<>0
end;
closefile (ff);
modified:=false;
freqbar.position:=TFreqobj (listbox1.items.objects[0]).f;
volbar.position:=64;
volbarchange (self);
end;
procedure TForm1. FreqbarChange (Sender: TObject);
var
scale:extended;
i:integer;
begin
if freqbar. position>0 then
begin
with listbox1, items do
if count>=1 then
begin
scale:=freqbar.position/TFreqobj (objects[0]).f;
freqedit.text:=inttostr (freqbar.position);
for i:=0 to count-1 do
if objects[i]<>nil then
with TFreqObj (objects[i]) do
begin
ftemp:=round (f*scale);
makestringrep;
items[i]: =stringrep;
end;
end;
checkplaying;
end;
end;
var samprates: array[0.3] of integer=(8000,11 025,22050,44 100);
procedure TForm1. RateRgrpClick (Sender: TObject);
begin
samplerate:=samprates[rateRgrp.itemindex];
checkplaying;
end;
procedure TForm1. VolBarChange (Sender: TObject);
begin
volEdit.text:=inttostr (Volbar.position);
checkplaying;
end;
procedure TForm1. VolEditChange (Sender: TObject);
var n: integer;
begin
n:=volbar.position;
volbar.position:=strtointdef (VolEdit.text, n);
if n<>volbar.position then volbarchange (sender);
end;
procedure TForm1. FreqEditChange (Sender: TObject);
var n: integer;
begin
n:=freqbar.position;
freqbar.position:=strtointdef (freqedit.text, n);
if n<>freqbar.position then FreqBarchange (sender);
end;
procedure TForm1. FreqEditKeyPress (Sender: TObject; var Key: Char);
begin
if key=#13 then Freqeditchange (sender);
end;
procedure TForm1. Button1Click (Sender: TObject);
begin
if Button1. Caption='Запись в файл' then
begin
PlayBtn.Click;
Button1.Caption:='Сохранить';
end
else if Button1. Caption='Сохранить' then
begin
PlaySound (nil, 0, SND_Purge);
playing:=false;
if SaveDialog2. Execute then
begin
ms[streaminuse]. SaveToFile (SaveDialog2.FileName);
Button1.Caption:='Запись в файл';
if assigned (ms[streaminuse]) then freeandnil (Ms[streaminuse]);
end;
end;
end;
end.