
2.2 Быстрое преобразование Фурье
Быстрое преобразование Фурье (БПФ) — это быстрый алгоритм вычисления дискретного преобразования Фурье (ДПФ). То есть алгоритм вычисления за количество действий, меньшее чем O(N2), требуемых для прямого (по формуле) вычисления ДПФ. Иногда под БПФ понимается один из быстрых алгоритмов, называемый алгоритмом прореживания по частоте/времени или алгоритмом по основанию 2, имеющего сложность O(Nlog(N)).
Дискретное преобразование Фурье— это одно из преобразований Фурье, широко применяемых в алгоритмах цифровой обработки сигналов (его модификации применяются в сжатии звука в MP3, сжатии изображений в JPEG и др.), а также в других областях, связанных с анализом частот в дискретном (к примеру, оцифрованном аналоговом) сигнале. Дискретное преобразование Фурье требует в качестве входа дискретную функцию. Такие функции часто создаются путём дискретизации (выборки значений из непрерывных функций). Дискретные преобразования Фурье помогают решать частные дифференциальные уравнения и выполнять такие операции, как свёртки. Дискретные преобразования Фурье также активно используются в статистике, при анализе временных рядов. Преобразования бывают одномерные, двумерные и даже трёхмерные.
Описание программы
Описание функционирования системы
При запуске программы появляется форма с различными компонентами.
Данная программа позволяет воспроизводить аудио файлы различных расширений, а именно: WAV/AIFF/MP3/MP2/MP1/OGG.
Воспроизведение трека сопровождается графической отрисовкой уровней громкости левого и правого каналов, а также спектроанализатора. Также во время звучания трека отображается навигация по данному треку, т.е. есть возможность перемещаться по треку в любое его положение, посредством ползунка. При воспроизведение трека на плеере высвечивается информационное окно, которое показывает о длительности проигрываемого трека, а также о его битрейте.
В данной программе была реализована такая функция как громкость. Она позволяет менять уровень звучания трека. Помимо этой регулировки существует регулировка прозрачности плеера. Она необходимо для удобства обращения сразу с несколькими программами, что достигается путем установления прозрачности окна плеера.
Управление воспроизведением осуществляется кнопками воспроизведения на самом плеере, и непосредственно горячими клавишами клавиатуры. Прослушивать треки можно как в порядке добавления их в плейлист, так и случайным образом, посредством кнопки «Random».
В данном плеере был разработан эквалайзер, который включает в себя три регулировки:
- регулировка низких частот
- регулировка средних частот
- регулировка высоких частот
Наличие плейлиста позволяет отслеживать список добавленных треков. Добавление трека в плейлист осуществляется 3 способами:
- добавление трека через кнопку плеера
- добавление трека путём перетаскивания из любого окна Windows
- добавление треков путем загрузки сохраненного ранее плейлиста
В связи с возможностью добавления треков в плейлиста, также была разработана функция удаления треков из плейлиста.
Плейлист можно сохранить в файл с расширением .txt .
Для данного плеера было разработано два скина, которые можно менять во время работы программы.
Для удобства работы с программой была реализована функция сворачивания плеера в трей.
Описание функционирования системы
Меню
Воспроизведение
Визуализация
PlayList
Управление скинами
Информационное окно
Управление воспроизведением
Сохранение
Добавление
Удаление
Основными блоками программы являются «меню» и «воспроизведение».
Если трек проигрывается, то отрисовывается «визуализация» и появляется возможность управления воспроизведением. Также при запуске трека показывается информационное окно. Добавлять, удалять и сохранять треки можно как во время воспроизведения, так и до него. Управление скинами происходит не зависимо от того, проигрывается трек или нет.
Заключение
Все заявленные пункты технического задания реализованы. В ходе работы программы не возникает ошибок т.е она работает вполне корректно.
В качестве дальнейшей модернизации могут выступать:
- возможность менять треки местами перетаскиванием мышью
- несколько скинов
- расширить меню «опции»
- добавление плагинов
- усовершенствование внешнего вида
- информация о текущей позиции трека в минутах и секундах
- возможность работы сразу с несколькими плейлистами
- более подробное информационное окно
Приложения
Текст программы
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Bass, ExtCtrls, XPMan, ComCtrls, MMSystem, jpeg,
Buttons, shellapi, Spectrum_vis, CommonTypes, ExtDlgs, Menus;
//CommonTypes, ExtDlgs;
type
TForm1 = class(TForm)
Timer1: TTimer;
OpenDialog2: TOpenDialog;
ListBox2: TListBox;
Image1: TImage;
PaintBox1: TPaintBox;
PaintBox2: TPaintBox;
Timer2: TTimer;
Button1: TButton;
SaveDialog1: TSaveDialog;
Button2: TButton;
OpenDialog1: TOpenDialog;
PaintBox3: TPaintBox;
PaintBox4: TPaintBox;
Button5: TButton;
ScrollBar1: TScrollBar;
ListBox1: TListBox;
Label2: TLabel;
Button7: TButton;
Button3: TButton;
PaintBox5: TPaintBox;
RadioGroup1: TRadioGroup;
Timer3: TTimer;
TrackBar4: TTrackBar;
TrackBar1: TTrackBar;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
BitBtn4: TBitBtn;
Image2: TImage;
BitBtn5: TBitBtn;
BitBtn6: TBitBtn;
Button4: TButton;
TrackX: TTrackBar;
TrackY: TTrackBar;
Label1: TLabel;
Button6: TButton;
PopupMenu1: TPopupMenu;
N1: TMenuItem;
N2: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure SpeedButton2Click(Sender: TObject);
procedure SpeedButton4Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure SpeedButton5Click(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
function GetKBPS(Channel: DWORD): integer;
function FileSize(fileName : wideString) : Int64;
procedure SpeedButton3Click(Sender: TObject);
procedure ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
function ViewKBPS(Sender: TObject): integer;
procedure Button7Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
procedure Timer3Timer(Sender: TObject);
procedure TrackBar4Change(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
procedure BitBtn3Click(Sender: TObject);
procedure BitBtn4Click(Sender: TObject);
procedure BitBtn5Click(Sender: TObject);
procedure BitBtn6Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Image2Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
Sliding: boolean;
FIconData:TNotifyIconData;
protected
procedure WndProc(var Msg: TMessage); Override;
procedure ControlWindow(var Msg: TMessage); message WM_SYSCOMMAND;
public
{ Public declarations }
protected
procedure WMDROPFILES (var Msg: TMessage); message WM_DROPFILES;
end;
var
Form1: TForm1;
Channel: HStream;
Path: string;
volume: LongWord; // громкость воспроизведения:
// старшее слово - правый канал
// младшее слово - левый канал
Click_on_list: boolean; // клик по листбоксу
Click_on_list_2: boolean; // клик на кнопку "Play" или
// или двойной клик по плейлисту
Index: integer; // индекс строки в листбоксе2
CountItem: integer; // количество добавленных строк (файлов) в плейлист
f: TextFile; // текстовый файл, в котором хранится плейлист
CountItemText: integer; // количество добавленных строк (файлов) в .txt
i: integer;
p: BASS_FXPARAMEQ;
pR: BASS_FXREVERB;
fx: array[1..4] of integer;
booly: boolean; // если true, то можно снимать с паузы
// если false, то можно ставить на паузу
boolskin: boolean; // для скинов
boolPaintBox: boolean; // для PaintBox, отрисовка разными цветами
boolSpectrum: boolean; // для Spectrum, отрисовка разными цветами
implementation
uses Math, Unit2;
{$R *.dfm}
procedure BasicPlayerPlayFile(const FileName: string);
var
FFileName: PChar;
begin
if not FileExists(FileName) then Exit; // Проверяем на существование файла
FFileName := PChar(FileName);
if Channel <> 0 then
begin
Bass_ChannelStop(Channel);
Bass_StreamFree(Channel);
Channel := 0;
end;
Channel := Bass_StreamCreateFile(False, FFileName, 0 ,0, 0);
if Channel = 0 then
begin
// Если не удалось загрузить файл выводим следующий код
MessageBox(0, 'Ошибка загрузки файла', 0, MB_OK or MB_ICONSTOP);
Exit;
end;
if not (Bass_ChannelPlay(Channel, False)) then
// Если не удаётся воспроизвести делаем следующее
MessageBox(0, 'Ошибка воспроизведения файла', 0, MB_OK or MB_ICONSTOP);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
hRgn: Cardinal; // для BitBtn
begin
// Создаем главную форму и блокируем ее показ
inherited;
Application.ShowMainForm:=true;
// Подготавливаем иконку для System Tray
with FIconData do begin
cbSize:=SizeOf(FIconData);
Wnd:=Handle;
uID:=100;
uFlags:=NIF_MESSAGE+NIF_ICON+NIF_TIP;
uCallbackMessage:=WM_USER+1;
hIcon:=Application.Icon.Handle;
szTip:='плеер';
end;
// Все готово - помещаем иконку в System Tray
Shell_NotifyIcon(NIM_ADD, @FIconData);
boolskin := true;
boolPaintBox := true;
boolSpectrum := true;
TrackX.Visible := false;
TrackY.Visible := false;
RadioGroup1.Visible := false;
Image2.Height := 321;
//// AlphaBlend: boolean оно разрешает/запрещает использовать прозрачность
//// AlphaBlendValue. принимает значения от 0 до 255
AlphaBlend := true;
AlphaBlendValue := 255;
booly := false;
DragAcceptFiles(Form1.Handle, true);
Click_on_list := false;
Click_on_list_2 := false;
If not BASS_Init(-1,44100,0,Handle,nil) then
Halt; // сбой при инициализации, закрываем программу
Spectrum := TSpectrum.Create(PaintBox5.Width, PaintBox5.Height);
Button3.Enabled := false;
Button1.Enabled := false;
Button7.Enabled := false;
// для BitBtn
hRgn := CreateEllipticRgn(6, 6, 45, 45);//(0,0,BitBtn1.Width,BitBtn1.Height);
SetWindowRgn(BitBtn1.Handle,hRgn,false);
hRgn := CreateEllipticRgn(6, 6, 45, 45);
SetWindowRgn(BitBtn2.Handle,hRgn,false);
hRgn := CreateEllipticRgn(6, 6, 45, 45);
SetWindowRgn(BitBtn3.Handle,hRgn,false);
hRgn := CreateEllipticRgn(6, 6, 45, 45);
SetWindowRgn(BitBtn4.Handle,hRgn,false);
hRgn := CreateEllipticRgn(6, 6, 45, 45);
SetWindowRgn(BitBtn5.Handle,hRgn,false);
hRgn := CreateEllipticRgn(6, 6, 45, 45);
SetWindowRgn(BitBtn6.Handle,hRgn,false);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
L, R, L1, R1, L2, R2: Integer;
Level: DWORD; // переменная для получения данных с канала
begin
if BASS_ChannelIsActive(Channel) <> BASS_ACTIVE_PLAYING then Exit;
// если канал не воспроизводится, то выходим отсюда
Level := BASS_ChannelGetLevel(Channel);
L := HiWord(Level);
R := LoWord(Level);
PaintBox1.Canvas.Brush.Color := clBlack;
PaintBox1.Canvas.FillRect(PaintBox1.Canvas.ClipRect);
PaintBox2.Canvas.Brush.Color := clBlack;
PaintBox2.Canvas.FillRect(PaintBox1.Canvas.ClipRect);
PaintBox3.Canvas.Brush.Color := clBlack;
PaintBox3.Canvas.FillRect(PaintBox1.Canvas.ClipRect);
PaintBox4.Canvas.Brush.Color := clBlack;
PaintBox4.Canvas.FillRect(PaintBox1.Canvas.ClipRect);
// очистили наши PaintBox'ы
L1 := Round(L / (32768 / PaintBox1.Height));
R1 := Round(R / (32768 / PaintBox2.Height));
L2 := Round(L / (32768 / PaintBox3.Height));
R2 := Round(R / (32768 / PaintBox4.Height));
if boolPaintBox then
begin
PaintBox1.Canvas.Brush.Color := clBlue;
PaintBox2.Canvas.Brush.Color := clBlue;
PaintBox3.Canvas.Brush.Color := clYellow;
PaintBox4.Canvas.Brush.Color := clYellow;
end
else
begin
PaintBox1.Canvas.Brush.Color := clLime;
PaintBox2.Canvas.Brush.Color := clLime;
PaintBox3.Canvas.Brush.Color := clGreen;
PaintBox4.Canvas.Brush.Color := clGreen;
end;
PaintBox1.Canvas.Rectangle(0, PaintBox1.Height - L1, PaintBox1.Width, PaintBox1.Height);
PaintBox2.Canvas.Rectangle(0, PaintBox2.Height - R1, PaintBox2.Width, PaintBox2.Height);
PaintBox3.Canvas.Rectangle(0, PaintBox3.Height - L2, PaintBox3.Width, PaintBox3.Height);
PaintBox4.Canvas.Rectangle(0, PaintBox4.Height - R2, PaintBox4.Width, PaintBox4.Height);
end;
// открытие сохранённого плейлиста
procedure TForm1.Button2Click(Sender: TObject);
var
fname: string;
begin
if OpenDialog1.Execute then
begin
ListBox1.Clear;
ListBox2.Clear;
fname := OpenDialog1.FileName;
AssignFile(f, fname);
Reset(f); // открыть файл
while not Eof(f) do
begin
ReadLn(f, fname);
ListBox1.Items.Add(ExtractFileName(fname));
ListBox2.Items.Add(fname);
end;
CloseFile(f);
end;
Button1.Enabled := true;
Button3.Enabled := true;
Button7.Enabled := true;
end;
// воспроизведение по двойному клику по ListBox
procedure TForm1.ListBox1DblClick(Sender: TObject);
begin
ScrollBar1.Position := 0;
Index := ListBox1.ItemIndex;
BasicPlayerPlayFile(ListBox2.Items[Index]);
Click_on_list := true;
Click_on_list_2 := true;
Scrollbar1.Max := round(BASS_ChannelBytes2Seconds(channel, BASS_ChannelGetLength(channel)));
ViewKBPS(Form1);
end;
// Добавление треков через кнопку
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
If OpenDialog2.Execute then
Begin
ListBox1.Items.Add(ExtractFileName(OpenDialog2.FileName));
ListBox2.Items.Add(ExtractFilePath(OpenDialog2.FileName)+
ExtractFileName(OpenDialog2.FileName));
end;
ScrollBar1.Position := 0;
Button3.Enabled := true;
Button1.Enabled := true;
Button7.Enabled := true;
end;
// перетаскивание формы
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
SendMessage(Form1.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
end;
// воспроизвести предыдущий трек
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
if (ListBox1.ItemIndex <> 0) then
begin
ListBox1.ItemIndex := ListBox1.ItemIndex - 1;
BasicPlayerPlayFile(ListBox2.Items[ListBox1.ItemIndex]);
end;
end;
// воспроизвести следующий трек
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
//if < ListBox1.SelCount) then
begin
ListBox1.ItemIndex := ListBox1.ItemIndex + 1;
BasicPlayerPlayFile(ListBox2.Items[ListBox1.ItemIndex]);
end;
end;
// сохранение текущего плейлиста
procedure TForm1.Button1Click(Sender: TObject);
var
fname: string;
temp: string;
i: integer;
begin
CountItemText := 0;
if SaveDialog1.execute then
begin
fname := SaveDialog1.FileName ;
AssignFile(f, fname);
Rewrite(f);
for i := 0 to CountItem - 1 do
begin
temp := ListBox2.Items[i];
writeln(f, temp);
CountItemText := CountItemText + 1;
end;
end;
CloseFile(f);
end;
// кнопка "Пауза"
procedure TForm1.SpeedButton5Click(Sender: TObject);
begin
BASS_ChannelPause(channel);
end;
// добавление файла из любого окна Windows
procedure TForm1.WMDROPFILES(var Msg: TMessage);
var
i,
amount,
size: integer;
Filename: PChar;
begin
inherited;
Amount := DragQueryFile(Msg.WParam, $FFFFFFFF, Filename, 255);
for i := 0 to (Amount - 1) do
begin
size := DragQueryFile(Msg.WParam, i , nil, 0) + 1;
Filename:= StrAlloc(size);
DragQueryFile(Msg.WParam,i , Filename, size);
ListBox1.Items.Add(ExtractFileName(FileName));
ListBox2.Items.Add(ExtractFilePath(FileName) + ExtractFileName(FileName));
CountItem := CountItem + 1;
StrDispose(Filename);
end;
DragFinish(Msg.WParam);
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
/////// меняется позиция ScrollBar ////
if not Sliding then
Scrollbar1.Position := round(BASS_ChannelBytes2Seconds(channel, BASS_ChannelGetPosition(channel)));
/////////////////////////////////////////
//// Расчет закгрузки CPU //////
Label1.Caption := 'CPU% ' + FloatToStrF(BASS_GetCPU, ffFixed, 4, 2);
///////////////////////////////
// если нажата горячая клавиша "пробел" => пауза
if GetAsyncKeyState($20) <> 0 then
begin
if booly then
begin
BASS_ChannelPause(channel);
booly := false;
end
else // если нажат повторно => Play
begin
BASS_ChannelPlay(Channel, false);
booly := true;
end;
end;
// если нажата горячая клавиша "right" => следующий трек
if GetAsyncKeyState($27) <> 0 then
begin
ListBox1.ItemIndex := ListBox1.ItemIndex + 1;
BasicPlayerPlayFile(ListBox2.Items[ListBox1.ItemIndex]);
end;
// если нажата горячая клавиша "left" => предыдущий трек
if GetAsyncKeyState($25) <> 0 then
begin
if (ListBox1.ItemIndex <> 0) then
begin
ListBox1.ItemIndex := ListBox1.ItemIndex - 1;
BasicPlayerPlayFile(ListBox2.Items[ListBox1.ItemIndex]);
end;
end;
end;
// определение битрейта трека
function TForm1.GetKBPS(Channel: DWORD): integer;
var
FloatLen: FLOAT;
Length: Int64;
len: DWORD;
begin
Length:= 0;
Length:= BASS_ChannelGetLength(Channel);
if Length < 0 then Length:= 0;
FloatLen:= BASS_ChannelBytes2Seconds(Channel, Length);
len:=BASS_StreamGetFilePosition(Channel, BASS_FILEPOS_END);
Result:= Round(len / (125 * FloatLen) + 0.5);
end;
// определение размера файла
function TForm1.FileSize(fileName: wideString): Int64;
var
sr : TSearchRec;
begin
if FindFirst(fileName, faAnyFile, sr ) = 0 then
result := Int64(sr.FindData.nFileSizeHigh) shl Int64(32) + Int64(sr.FindData.nFileSizeLow)
else
result := -1;
FindClose(sr) ;
end;
// воспроизведение после паузы
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
BASS_ChannelPlay(Channel, false); // если false, поток можно приостанавливать,
// затем играть с места остановки.
// Если true, то остановка грозит возвращением к началу.
end;
// нажатие на кнопку "ЭКВАЛАЙЗЕР"
// открывается новая форма с ругулировками частот:
// - низких
// - средних
// - высоких
procedure TForm1.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
begin
Sliding := Scrollcode <> scPosition;
if ScrollCode = scEndScroll then
BASS_ChannelSetPosition(channel, BASS_ChannelSeconds2Bytes(channel, Scrollbar1.position));
end;
// выводит в Label1 информацию о длительноти и битрейте трека
function TForm1.ViewKBPS(Sender: TObject): integer;
var
i, isec, imin: float; // длительность трека
begin
i := FileSize(ListBox2.Items[Index])/((GetKBPS(Channel)*1000)/8);
isec := i - (Floor(i / 60))*60;
imin := (i / 60);
if (isec < 10) then
begin
Label2.Caption := 'Битрейт: ' + IntToStr(GetKBPS(Channel)) + ' kbps' + #13 +
'Длительность трека: ' + '0' + FloatToStr(Floor(imin)) +
':0' + FloatToStr(Floor(isec));
end
else
begin
Label2.Caption := 'Битрейт: ' + IntToStr(GetKBPS(Channel)) + ' kbps,' +
' Длительность: ' + '0' + FloatToStr(Floor(imin)) +
':' + FloatToStr(Floor(isec));
end;
end;
// удаление выделенного трека из плейлиста
procedure TForm1.Button7Click(Sender: TObject);
var
i: integer;
begin
ListBox1.DeleteSelected;
ListBox2.Items.Delete(Index);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
Randomize;
BasicPlayerPlayFile(ListBox2.Items[random(ListBox2.Count)]);
end;
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
Spectrum.Mode := RadioGroup1.ItemIndex;
end;
procedure TForm1.Timer3Timer(Sender: TObject);
var
FFTFata : TFFTData; WaveData : TWaveData;
begin
if BASS_ChannelIsActive(Channel) <> BASS_ACTIVE_PLAYING then Exit;
BASS_ChannelGetData(Channel, @FFTFata, BASS_DATA_FFT1024);
Spectrum.Draw (PaintBox5.Canvas.Handle, FFTFata, boolSpectrum, TrackX.Position - 40, TrackY.Position - 60);
end;
procedure TForm1.TrackBar4Change(Sender: TObject);
begin
AlphaBlendValue := 255 - TrackBar4.Position;
end;
// Открытие эквалайзера в отдельном окне
procedure TForm1.Button5Click(Sender: TObject);
begin
Form2:= TForm2.Create(Application);
Form2.Caption:= 'Эквалайзер';
Form2.Show;
Button5.Enabled := false;
end;
procedure TForm1.TrackBar1Change(Sender: TObject);
var
s: dword;
a, b: word;
h: hWnd;
volume: longword;
begin
// a := TrackBar1.Position;
// b := TrackBar1.Position;
// s := (a shl 16) or b;
//WaveOutSetVolume(h, s);
// BASS_ChannelSetAttributes(channel, volume);
BASS_ChannelSetAttributes(channel, 44100, 100 - TrackBar1.Position, 0);
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
If OpenDialog2.Execute then
Begin
ListBox1.Items.Add(ExtractFileName(OpenDialog2.FileName));
ListBox2.Items.Add(ExtractFilePath(OpenDialog2.FileName)+
ExtractFileName(OpenDialog2.FileName));
end;
Button1.Enabled := true;
Button3.Enabled := true;
Button7.Enabled := true;
end;
procedure TForm1.BitBtn3Click(Sender: TObject);
begin
// если false, поток можно приостанавливать,
// затем играть с места остановки.
// Если true, то остановка грозит возвращением к началу.
BASS_ChannelPlay(Channel, false);
end;
procedure TForm1.BitBtn4Click(Sender: TObject);
begin
BASS_ChannelPause(channel);
end;
procedure TForm1.BitBtn5Click(Sender: TObject);
begin
if (ListBox1.ItemIndex <> 0) then
begin
ListBox1.ItemIndex := ListBox1.ItemIndex - 1;
BasicPlayerPlayFile(ListBox2.Items[ListBox1.ItemIndex]);
end;
end;
procedure TForm1.BitBtn6Click(Sender: TObject);
begin
//if < ListBox1.SelCount) then
begin
ListBox1.ItemIndex := ListBox1.ItemIndex + 1;
BasicPlayerPlayFile(ListBox2.Items[ListBox1.ItemIndex]);
end;
end;
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
BASS_ChannelStop(channel);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
TrackX.Visible := true;
TrackY.Visible := true;
RadioGroup1.Visible := true;
Image2.Height := 417;
Form1.Height := 658;
Form1.Width := 378;
end;
procedure TForm1.Image2Click(Sender: TObject);
begin
TrackX.Visible := false;
TrackY.Visible := false;
RadioGroup1.Visible := false;
Image2.Height := 321;
Form1.Height := 562;
end;
procedure TForm1.Button6Click(Sender: TObject);
begin
if boolskin then
begin
BitBtn1.Glyph.LoadFromFile('D:\Курсовик\pic\green\1.bmp');
BitBtn2.Glyph.LoadFromFile('D:\Курсовик\pic\green\2.bmp');
BitBtn3.Glyph.LoadFromFile('D:\Курсовик\pic\green\3.bmp');
BitBtn4.Glyph.LoadFromFile('D:\Курсовик\pic\green\4.bmp');
BitBtn5.Glyph.LoadFromFile('D:\Курсовик\pic\green\5.bmp');
BitBtn6.Glyph.LoadFromFile('D:\Курсовик\pic\green\6.bmp');
Image1.Picture.LoadFromFile('D:\Курсовик\pic\bkg1.jpg');
Image2.Picture.LoadFromFile('D:\Курсовик\pic\bkg3.jpg');
Label2.Font.Color:= clLime;
// ListBox1.Color := clLime;
boolSpectrum := false;
boolPaintBox := false;
boolskin := false;
end
else
begin
BitBtn1.Glyph.LoadFromFile('D:\Курсовик\pic\blue\1.bmp');
BitBtn2.Glyph.LoadFromFile('D:\Курсовик\pic\blue\2.bmp');
BitBtn3.Glyph.LoadFromFile('D:\Курсовик\pic\blue\3.bmp');
BitBtn4.Glyph.LoadFromFile('D:\Курсовик\pic\blue\4.bmp');
BitBtn5.Glyph.LoadFromFile('D:\Курсовик\pic\blue\5.bmp');
BitBtn6.Glyph.LoadFromFile('D:\Курсовик\pic\blue\6.bmp');
Image1.Picture.LoadFromFile('D:\Курсовик\pic\bkg2.jpg');
Image2.Picture.LoadFromFile('D:\Курсовик\pic\bkg4.jpg');
Label2.Font.Color:= clBlack;
//ListBox1.Color := clInactiveCaption;
boolSpectrum := true;
boolPaintBox := true;
boolskin := true;
end;
end;
procedure TForm1.N1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.N2Click(Sender: TObject);
begin
ShowWindow(Handle, SW_NORMAL);
end;
procedure TForm1.WndProc(var Msg: TMessage);
var
P: TPoint;
begin
if Msg.Msg=WM_USER+1 then begin
case Msg.LParam of
WM_LBUTTONDOWN:
begin
end;
WM_RBUTTONDOWN: // Нажата правая кнопка мыши - показываем pop-up меню
begin
SetForegroundWindow(Handle); // Восстанавливаем программу в качестве переднего окна
GetCursorPos(P); // Запоминаем координаты курсора мыши
PopupMenu1.Popup(P.X,P.Y); // Показываем pop-up меню
PostMessage(Handle,WM_NULL,0,0) // Обнуляем сообщение
end;
end;
end;
inherited;
end;
procedure TForm1.ControlWindow(var Msg: TMessage);
begin
// Если в заголовке окна программы нажаты кнопка Свернуть,
// скрываем форму
case Msg.WParam of
SC_MINIMIZE:
ShowWindow(Handle, SW_HIDE);
else
inherited;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// Перед уничтожение формы удаляем иконку из SysTray
Shell_NotifyIcon(NIM_DELETE, @FIconData);
inherited Destroy;
end;
end.
unit spectrum_vis;
interface
uses Windows, Dialogs, Graphics, SysUtils, CommonTypes, Classes;
type TSpectrum = Class(TObject)
private
VisBuff : TBitmap;
BackBmp : TBitmap;
BkgColor : TColor;
SpecHeight : Integer;
PenColor : TColor;
PeakColor: TColor;
DrawType : Integer;
DrawRes : Integer;
FrmClear : Boolean;
UseBkg : Boolean;
PeakFall : Integer;
LineFall : Integer;
ColWidth : Integer;
ShowPeak : Boolean;
FFTPeacks : array [0..128] of Integer;
FFTFallOff : array [0..128] of Integer;
public
Constructor Create (Width, Height : Integer);
procedure Draw(HWND : THandle; FFTData : TFFTData; boolSpectrum : boolean; X, Y : Integer);
procedure SetBackGround (Active : Boolean; BkgCanvas : TGraphic);
property BackColor : TColor read BkgColor write BkgColor;
property Height : Integer read SpecHeight write SpecHeight;
property Width : Integer read ColWidth write ColWidth;
property Pen : TColor read PenColor write PenColor;
property Peak : TColor read PeakColor write PeakColor;
property Mode : Integer read DrawType write DrawType;
property Res : Integer read DrawRes write DrawRes;
property FrameClear : Boolean read FrmClear write FrmClear;
property PeakFallOff: Integer read PeakFall write PeakFall;
property LineFallOff: Integer read LineFall write LineFall;
property DrawPeak : Boolean read ShowPeak write ShowPeak;
end;
var Spectrum : TSpectrum;
implementation
Constructor TSpectrum.Create(Width, Height : Integer);
begin
VisBuff := TBitmap.Create;
BackBmp := TBitmap.Create;
VisBuff.Width := Width;
VisBuff.Height := Height;
BackBmp.Width := Width;
BackBmp.Height := Height;
BkgColor := clBlack;
SpecHeight := 100;
PenColor := clBlue;
PeakColor := clYellow;
DrawType := 0;
DrawRes := 1;
FrmClear := True;
UseBkg := False;
PeakFall := 2;
LineFall := 3;
ColWidth := 5;
ShowPeak := True;
end;
procedure TSpectrum.SetBackGround (Active : Boolean; BkgCanvas : TGraphic);
begin
UseBkg := Active;
BackBmp.Canvas.Draw(0, 0, BkgCanvas);
end;
procedure TSpectrum.Draw(HWND : THandle; FFTData : TFFTData; boolSpectrum : boolean; X, Y : Integer);
var i, YPos : LongInt; YVal : Single;
begin
if boolSpectrum then
begin
PenColor := clBlue;
PeakColor := clYellow;
end
else
begin
PenColor := clLime;
PeakColor := clGreen;
end;
if FrmClear then begin
VisBuff.Canvas.Pen.Color := BkgColor;
VisBuff.Canvas.Brush.Color := BkgColor;
VisBuff.Canvas.Rectangle(0, 0, VisBuff.Width, VisBuff.Height);
if UseBkg then VisBuff.Canvas.CopyRect(Rect(0, 0, BackBmp.Width, BackBmp.Height), BackBmp.Canvas, Rect(0, 0, BackBmp.Width, BackBmp.Height));
end;
VisBuff.Canvas.Pen.Color := PenColor;
for i := 0 to 128 do begin
YVal := Abs(FFTData[(i * DrawRes) + 5]);
YPos := Trunc((YVal) * 500);
if YPos > Height then YPos := SpecHeight;
if YPos >= FFTPeacks[i] then FFTPeacks[i] := YPos
else FFTPeacks[i] := FFTPeacks[i] - PeakFall;
if YPos >= FFTFallOff[i] then FFTFallOff[i] := YPos
else FFTFallOff[i] := FFTFallOff[i] - LineFall;
if (VisBuff.Height - FFTPeacks[i]) > VisBuff.Height then FFTPeacks[i] := 0;
if (VisBuff.Height - FFTFallOff[i]) > VisBuff.Height then FFTFallOff[i] := 0;
case DrawType of
0 : begin
VisBuff.Canvas.MoveTo(X + i, Y + VisBuff.Height);
VisBuff.Canvas.LineTo(X + i, Y + VisBuff.Height - FFTFallOff[i]);
if ShowPeak then VisBuff.Canvas.Pixels[X + i, Y + VisBuff.Height - FFTPeacks[i]] := Pen;
end;
1 : begin
if ShowPeak then VisBuff.Canvas.Pen.Color := PeakColor;
if ShowPeak then VisBuff.Canvas.MoveTo(X + i * (ColWidth + 1), Y + VisBuff.Height - FFTPeacks[i]);
if ShowPeak then VisBuff.Canvas.LineTo(X + i * (ColWidth + 1) + ColWidth, Y + VisBuff.Height - FFTPeacks[i]);
VisBuff.Canvas.Pen.Color := PenColor;
VisBuff.Canvas.Brush.Color := PenColor;
VisBuff.Canvas.Rectangle(X + i * (ColWidth + 1), Y + VisBuff.Height - FFTFallOff[i], X + i * (ColWidth + 1) + ColWidth, Y + VisBuff.Height);
end;
end;
end;
BitBlt(HWND, 0, 0, VisBuff.Width, VisBuff.Height, VisBuff.Canvas.Handle, 0, 0, srccopy)
end;
end.
Руководство пользователя
Загружая данную программу на экране появляется плеер. Для прослушивания музыки можно добавить треки через кнопку «добавить трек», при этом добавленный трек сразу появится в плейлисте. Есть возможность добавить трек из любого окна Windows (например, папка «Моя Музыка») путём перетаскивания треков мышью в область плейлиста. Также треки можно добавить через кнопку «добавить сохранённый плейлист». Если необходимо удалить трек из плейлиста нужно выделить его и нажать кнопку «Del». Для того чтобы сохранить плейлист необходимо сначала добавить один или более треков в плейлист любыми первыми двумя способами добавления треков в плейлист. Затем нажать кнопку «сохранить плейлист» и указать директорию, куда необходимо сохранить плейлист, с последующим написанием расширения «.txt».
Начать воспроизведение трека можно двойным щелчком мыши по треку в плейлисте. Также можно управлять воспроизведением трека посредством кнопок «пауза», «стоп», «следующий трек», «предыдущий трек», «воспроизвести».
Для регулировки эквалайзера необходимо нажать кнопку «эквалайзер» , после чего откроется окно с настройками низких, средних и высоких частот.
Поменять скин плеера можно в любой момент, нажав на кнопку «Skin».
В данном плеер есть возможность регулировки громкости и прозрачности. Регуляторы находятся по краям плеера и называются соответственно.