2Структурное проектирование
2.1SADT
2.2ERD
2.3DFD
3Выбор языка программирования
Для написания программы был выбран язык с большим количеством свободных компонент, позволяющих без определённых специфичных знаний писать программы с необходимым функционалом. Также выбор был сделан в пользу наиболее простого и более знакомого языка, т.е. выбор пал на Delphi, а так-как необходимо было осуществлять работу с Unicode строками, то выбор был сделан в пользу Code Gear Rad Studio Delphi 2009.
Таким образом подобный выбор позволял мне не отвлекаться на разработку своих методов работы с аудио форматами, также он позволил не заботиться о постоянном контроле формата типа данных.
4Разработка интерфейса
Основной задачей при разработке интерфейса является:
Максимальное использование пустого пространства на форме.
Максимально интуитивное управление.
Минимальное количество дополнительных окон.
Таким образом интерфейс очень похож на FooBar2000. В центре список треков с боку управление проигрыванием, с противоположной стороны были размещены вкладки для переключения между режимами отображения главного окна между: списком, опциями.
В низу выводится информация о текущем трек. В верху окно поиска в писке элементов.
Таким образом было максимально использовано свободное пространство на форме будущего проигрывателя.
5 Руководство пользователя.
6Заключение
В процессе разработки ПО были выполнено большинство из предполагающегося функционала. Таким образом аудио плеер выполняет все необходимые функции для обычных плееров.
Также в процессе были разобраны методы и принципы построения ПО, в котором участвовали сторонние люди что позволило достаточно быстро миновать первоначальное тестирование и отлов ошибок.
Также были найдены (но не реализованы) пути интеграции автоматической системы обновления информации треков, что вероятно поспособствует дальнейшему развитию данного ПО.
В процессе же рассмотрения различных медиа проигрывателей было выявлено достаточно плотное на данный момент сотрудничество веб-ресурсов, что предполагает развитие средств медиа-проигрывания в сторону работы с централизованными источниками данныхдля обновления всей информации и предотвращения ошибочности определения тегов для аудио контента и потоковых радиостанций.
7Приложение (Листинг программы).
program Amp;
uses
madExcept,
madLinkDisAsm,
madListHardware,
madListProcesses,
madListModules,
Windows,
SysUtils,
Forms,
main in 'main.pas' {face},
controlls_comp in 'controlls_comp.pas' {DM: TDataModule},
AMixer in 'AMixer.pas',
regftyp in 'regftyp.pas',
EventWaitThread in 'EventWaitThread.pas',
BMLPlaylist in 'BMLPlaylist.pas',
PathUtils in 'PathUtils.pas',
finder in 'finder.pas',
tech_unit in 'tech_unit.pas';
{$R *.res}
const
MailslotName = '\\.\mailslot\DBolidAmp_FileCommand';
EventName = 'BolidAmp_CHECKEXIST';
var
ClientMailslotHandle: THandle;
Letter: string;
BytesWritten: DWORD;
begin
// Пытаемся создать почтовый ящик
try
ServerMailslotHandle := CreateMailSlot(MailslotName, 0, MAILSLOT_WAIT_FOREVER, nil);
finally
if ServerMailslotHandle = INVALID_HANDLE_VALUE then
begin
if GetLastError = ERROR_ALREADY_EXISTS then
begin
// Если такой ящик уже есть, подключаемся к нему как клиент
ClientMailslotHandle := CreateFile(MailslotName, GENERIC_WRITE,
FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
Letter:='';
if ParamCount > 0 then
letter:=readStartParam;
// Отправляем команду в почтовый ящик
WriteFile(ClientMailslotHandle, Letter[1], SizeOf(string)*Length(Letter),
BytesWritten, nil);
// Сигнализируем об отправке данных через специальное событие
CommandEvent := OpenEvent(EVENT_MODIFY_STATE, False, EventName);
SetEvent(CommandEvent);
// Закрываем все дескрипторы
CloseHandle(CommandEvent);
CloseHandle(ClientMailslotHandle);
end
end
else
begin
// Создаём событие для сигнализирования о поступлении данных
CommandEvent := CreateEvent(nil, False, False, EventName);
// Выполняем обычный для VCL-приложений цикл
Application.Initialize;
Application.MainFormOnTaskbar := true;
Application.CreateForm(TDM, DM);
Application.CreateForm(Tface, face);
Application.Run;
// Закрываем все дескрипторы
CloseHandle(ServerMailslotHandle);
CloseHandle(CommandEvent);
end;
end;
end.
unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, ExtCtrls, StdCtrls, ACS_Classes, ShellAPI, Buttons, ToolWin,
Jpeg, PNGImage, ActnMan, ActnCtrls, LCDScreen, RzTrkBar, RzTabs, RzGroupBar,
RzStatus, RzPanel, RzSpnEdt, regftyp, BMLPlaylist, PathUtils,
RzRadGrp, finder, tech_unit, EventWaitThread;
type
Tface = class(TForm)
addDir: TToolButton;
addFile: TToolButton;
AlbumArt: TCategoryPanel;
AssCheck: TRzCheckGroup;
AssTrue: TButton;
CategoryPanelGroup1: TCategoryPanelGroup;
CommonOptions: TRzTabSheet;
edSearch: TButtonedEdit;
imgAlbum: TImage;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
LCD: TLCDScreen;
libraryOptions: TRzTabSheet;
Manipulation: TCategoryPanel;
OptionPages: TRzPageControl;
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Panel4: TPanel;
Panel5: TPanel;
plAddCol: TRzSpinner;
plAddSpeed: TRzSpinner;
play_list: TListView;
plClear: TToolButton;
plNext: TToolButton;
plOpen: TToolButton;
plOpSave: TButton;
plPlay: TToolButton;
plPrev: TToolButton;
plRandom: TToolButton;
plRepeat: TToolButton;
plSave: TToolButton;
plScanIdle: TRzSpinner;
plStop: TToolButton;
RzClockStatus1: TRzClockStatus;
RzGroupBox1: TRzGroupBox;
RzPageControl1: TRzPageControl;
RzPanel1: TRzPanel;
SearchList: TListView;
SearchProgress: TProgressBar;
StatusBar: TRzStatusBar;
StatusPane1: TRzStatusPane;
TabSheet1: TRzTabSheet;
TabSheet2: TRzTabSheet;
TabSheet3: TRzTabSheet;
TB: TRzTrackBar;
tb2: TRzTrackBar;
tbBalance: TRzTrackBar;
ToolBar1: TToolBar;
ToolBar2: TToolBar;
ToolButton2: TToolButton;
ToolButton3: TToolButton;
ToolButton5: TToolButton;
procedure addDirClick(Sender: TObject);
procedure AssTrueClick(Sender: TObject);
procedure edSearchChange(Sender: TObject);
procedure edSearchRightButtonClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormDockOver(Sender: TObject; Source: TDragDockObject; X, Y:
Integer; State: TDragState; var Accept: Boolean);
procedure opFileClick(Sender: TObject);
procedure playClick(Sender: TObject);
procedure play_listDblClick(Sender: TObject);
procedure play_listDragOver(Sender, Source: TObject; X, Y: Integer; State:
TDragState; var Accept: Boolean);
procedure play_listEditing(Sender: TObject; Item: TListItem; var AllowEdit:
Boolean);
procedure play_listKeyPress(Sender: TObject; var Key: Char);
procedure plClearClick(Sender: TObject);
procedure plNextClick(Sender: TObject);
procedure plOpenClick(Sender: TObject);
procedure plOpSaveClick(Sender: TObject);
procedure plPrevClick(Sender: TObject);
procedure plSaveClick(Sender: TObject);
procedure plStopClick(Sender: TObject);
procedure RzPageControl1Close(Sender: TObject; var AllowClose: Boolean);
procedure SearchListDblClick(Sender: TObject);
procedure SearchListKeyPress(Sender: TObject; var Key: Char);
procedure tb2Change(Sender: TObject);
procedure tb2MouseDown(Sender: TObject; Button: TMouseButton; Shift:
TShiftState; X, Y: Integer);
procedure TbBalanceChange(Sender: TObject);
procedure TbBalanceContextPopup(Sender: TObject; MousePos: TPoint; var
Handled: Boolean);
procedure TBChange(Sender: TObject);
procedure TBMouseDown(Sender: TObject; Button: TMouseButton; Shift:
TShiftState; X, Y: Integer);
private
apClose: Boolean;
newfind: TFinder;
PlayingCount: Integer;
PlayingID: Integer;
PlayingIndex: Integer;
Playingprevios: Integer;
StopPlaying: Boolean;
function GetSelectedItem: Integer;
procedure readOptions;
function ReadStringFromMailslot: string;
procedure saveOptions;
procedure WMCommandArrived(var Message: TMessage); message
WM_CommandArrived;
procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
public
procedure appClose;
procedure finderdest;
function getPlayingID: Integer;
function getPlayingIndex: Integer;
procedure PlayItem(index: integer);
procedure readBML(pach:string);
procedure resetPlStatus(index: integer);
procedure saveBML(pach: string;play:boolean);
end;
var
face: Tface;
ServerMailslotHandle: THandle;
implementation
uses controlls_comp, IniFiles;
{$R *.dfm}
{
************************************ Tface *************************************
}
procedure Tface.addDirClick(Sender: TObject);
begin
if dm.SelectFolder.Execute then
dm.scanfile(dm.SelectFolder.SelectedPathName);
end;
procedure Tface.appClose;
begin
apClose:=true;
close;
end;
procedure Tface.AssTrueClick(Sender: TObject);
var
icon: string;
plIcon: string;
begin
icon := ExtractFileDir(application.ExeName)+'\image\type\Audio.ico';
plIcon:= ExtractFileDir(application.ExeName)+'\image\type\PlayList.ico';
registerfiletype('.bml','BolidAmp PlayList','PlayList',plIcon,application.ExeName);
if AssCheck.ItemChecked[0] then registerfiletype('.ogg','oggfile','Audio',icon,application.ExeName);
if AssCheck.ItemChecked[1] then registerfiletype('.mp3','mp3file','Audio',icon,application.ExeName);
if AssCheck.ItemChecked[2] then registerfiletype('.wav','wavfile','Audio',icon,application.ExeName);
if AssCheck.ItemChecked[3] then registerfiletype('.wma','wmafile','Audio',icon,application.ExeName);
if AssCheck.ItemChecked[4] then registerfiletype('.ape','apefile','Audio',icon,application.ExeName);
if AssCheck.ItemChecked[5] then registerfiletype('.flac','flacfile','Audio',icon,application.ExeName);
end;
procedure Tface.edSearchChange(Sender: TObject);
begin
if edSearch.Text<>'' then
begin
edSearch.RightButton.Visible:=true;
play_list.Visible:=false;
SearchList.Visible:=true;
SearchProgress.Visible:=true;
//dm.t5.Enabled:=true;
dm.new_search:=true;
if newfind=nil then begin newfind:=TFinder.Create(false); newfind.Priority:=tpLowest; end;
end
else
edSearchRightButtonClick(nil);
end;
procedure Tface.edSearchRightButtonClick(Sender: TObject);
begin
edSearch.RightButton.Visible:=false;
SearchProgress.Visible:=false;
SearchProgress.Position:=0;
//dm.t5.Enabled:=false;
finderdest;
SearchList.Visible:=false;
play_list.Visible:=true;
SearchList.Clear;
edSearch.Clear;
dm.search_index:=0;
end;
procedure Tface.finderdest;
begin
if (newfind<>nil) then newfind.Terminate;
newfind:=nil;
end;
procedure Tface.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if apClose then
begin
Action := caFree;
end
else
begin
Action := caNone;
face.Visible:=false;
memFree;
end;
end;
procedure Tface.FormCreate(Sender: TObject);
begin
TEventWaitThread.Create(False);
//Tfinder.Create(false);
apClose:=false;
DragAcceptFiles(Handle,True);
PlayingID:=-1;
PlayingCount:=-1;
Playingprevios:=-2;
PlayingIndex:=-1;
with dm do
begin
plPlay.ImageIndex :=img_state_play;
plNext.ImageIndex :=img_state_next;
plPrev.ImageIndex :=img_state_prev;
addFile.ImageIndex :=img_state_fileOpen;
addDir.ImageIndex :=img_state_dirrOpen;
plRepeat.ImageIndex :=img_state_Repeat;
plRandom.ImageIndex :=img_state_random;
plOpen.ImageIndex :=img_state_plOpen;
plSave.ImageIndex :=img_state_plSave;
plStop.ImageIndex :=img_state_Stop;
plClear.ImageIndex :=img_state_plClear;
edSearch.LeftButton.ImageIndex :=img_state_find;
edSearch.RightButton.ImageIndex :=img_state_close;
end;
readOptions;
if face.Left < 0 then face.Left:=100;
if face.Top < 0 then face.Top:=100;
imgAlbum.Picture.LoadFromFile(ExtractFilePath(Application.ExeName)+'image\def_audio.png');
if ParamCount > 0 then
dm.scanfile(readStartParam)
else
face.readBML(ExtractFilePath(Application.ExeName)+'data\plData.bml');
end;
procedure Tface.FormDestroy(Sender: TObject);
var
i: Byte;
begin
DragAcceptFiles(Handle, False);
with dm do
begin
for I := 1 to 4 do
TTimer(FindComponent('T'+inttostr(i))).Enabled:=false;
if DXAudioOut.Status <> tosIdle then
|