Odtwarzacz plików dźwiękowych.

  W tym kursie programowania pokażę jak stworzyć w pełni funkcjonalny odtwarzacz plików dźwiękowych w formatach: *.wav, *.mp3, *.midi. Odtwarzcz nie będzie ani lepszy, ani pięknieszy od dostępnych już wszędzie tego typu odtwarzaczy, będzie raczej prosty i funkcjonalny, i będzie zawierał to wszystko co powinien zawierać tego typu program, czyli listę plików, regulator głośności, pasek postępu, pasek stanu, regulatory i inne mniej istone elementy. Po przejściu wszystkich "kroków", każdy będzie już na tyle zorientowany na czym polega programowanie by sobie dowolnie zmodyfikować, ulepszyć i upiększyć program. Więc zaczynamy.

   krok 1. - tworzymy nowy projekt
  Najpierw należy utworzyć na dysku nowy katalog w który będziemy przchowywać projekt. Następnie uruchamiamy BCB. W chwili uruchomienia program automatycznie tworzy nowy projekt. Przchodzimy do menu File i wybieramy Save All. Plik źródłowy zapisujemy pod nazwą Unit1.cpp, plik nagłówkowy zostanie utworzony automatycznie i zapisany pod nazwą Unit1.h. Program będzie się nazywał Empeg więc pod taką nazwą zapisujemy projekt.

    krok 2. - rozmieszczamy komponenty i ustawiamy ich właściwości
  Najpierw umieszczamy na formularzu komponent 'MediaPlayer1' który znajduje się na zakładce System, potem umieszczamy komponenty 'ListBox1', 'Label1', 'OpenDialog1', 'Edit1', 'TrackBar1', 'ProgressBar1', 'Timer1' oraz siedem kopmonentów 'SpeedButton'. Właściwości wszystkich komponentów ustawiamy według wzoru podanego w tabeli:

WłaściwościMediaPlayer1
Visiblefalse
WłaściwościListBox1
Height200
Left8
Sortedfalse
Top30
Width300


WłaściwościLabel1
CaptionLista plików:
Left8
Transparenttrue
Top10
WłaściwościEdit1
Left8
Text 
Top235
Width300


WłaściwościTrackBar1
Frequency10000
Height29
Left235
MaxMaxWord
NameVolume1
PositionMaxWord
ThumbLength15
Top260
Width75
WłaściwościOpenDialog1
FilterPatrz niżej.

Ważna uwaga. W niektórych przypadkach (prawdopodobnie w BCB poniżej wersji 4) w właściwości Max i Position obiektu TrackBar1 nie można wprowadzić wartości MaxWord, dlatego należy przypisać tym właściwościom wartość 65535.

W 'OpenDialog1' wprowadzamy tylko filtry do edytora filtrów według wzoru:
Pliki WAV | *.wav
Pliki MP3 | *.mp3
Pliki MIDI | *.midi
Wszystkie formaty | *.wav;*.mp3;*.midi


Jeśli chodzi o przyciski 'SpeedButton' to jako właściwość Glyph należy wprowadzić pliki graficzne, a konkretnie bitmapy. Można zastosować tutej pliki które są dołączane w czasie instalacji BCB i powinny znajdować się w lokalizacji np. "C:\Program Files\Common Files\Borland Shared\Images\Buttons\", lecz można równie dobrze posłużyć się własnymi bitmapami. Jako właściwość Glyph będę podawał nazwy plików które znajdują się w podanej lokalizacji.

WłaściwościSpeedButton1
AllowAllUptrue
Glyphvcrplay
GroupIndex1
NamePlay1
Left8
Top262
WłaściwościSpeedButton2
AllowAllUptrue
Glyphvcrpause
GroupIndex0
NamePause1
Left40
Top262


WłaściwościSpeedButton3
AllowAllUptrue
Glyphvcrstop
GroupIndex1
NameStop1
Left72
Top262
WłaściwościSpeedButton4
AllowAllUptrue
Glyphvcrrewnd
GroupIndex0
NameRewind1
Left104
Top262


WłaściwościSpeedButton5
AllowAllUptrue
Glyphvcrfsfor
GroupIndex0
NameForward1
Left136
Top262
WłaściwościSpeedButton6
AllowAllUptrue
Glyphfldropen
GroupIndex0
NameOpen1
Left168
Top262


WłaściwościSpeedButton7
AllowAllUptrue
Glyphclear
GroupIndex0
NameClear1
Left200
Top262
WłaściwościTimer1
Enablefalse


WłaściwościProgressBar1
Left8
Step1
Top300
Width300
WłaściwościForm1
-BorderIcons 

biMaximize

false
CaptionEmpeg
Height350
Width325


    krok 3. - wczytywanie plików do listy
  Teraz dołączymy procedury wczytywania plików i umieszczania ich na liście - 'ListBox1'. W tym celu przechodzimy do pliku nagłówkowego Unit1.h i w sekcji private definiujemy listę typu string, która będzie przechowywała ścieżki dostępu do nazw plików ładowanych do listy 'ListBox1'. Definiujemy również funkcję LoadFiles, która będzie obsługiwała wczytywanie plików.
Przykład:

// Plik nagłówkowy np. Unit1.h.
//--------------------------------
private:
void __fastcall
 LoadFiles(void);
TStringList *Lista;
//--------------------------------


Następnie przechodzimy do pliku źródłowego Unit1.cpp i w zdarzeniu formularza 'OnCreate' inicjujemy listę Lista, natomiast w zdarzeniu 'OnClose' usuwamy listę z pamięci, a następnie tworzymy procedurę obsługi funkcji 'LoadFiles' po czym w zdarzeniu 'OnClick' przycisku 'Open1' wywołujemy zdefiniowaną funkcję. Potem również w zdarzeniu 'OnClick' lecz przycisku 'Clear1' wywołujemy funkcję kasującą zawartość obiektów 'Lista' i 'ListBox1'.
Przykład:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Lista = new TStringList;
}
//--------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
Lista->Free();
}
//--------------------------------
void __fastcall TForm1::LoadFiles(void)
{
if(OpenDialog1->Execute()){
for(int i = 0; i < Lista->Count; i++){
  if(OpenDialog1->FileName == Lista->Strings[i]) return;
          }
  Lista->Add(OpenDialog1->FileName);
  ListBox1->Items->Add(ExtractFileName(OpenDialog1->FileName));
     }
}
//--------------------------------
void __fastcall TForm1::Open1Click(TObject *Sender)
{
LoadFiles();
}
//--------------------------------
void __fastcall TForm1::Clear1Click(TObject *Sender)
{
ListBox1->Items->Clear();
Lista->Clear();
}
//--------------------------------


    krok 4. - odtwarzanie plików
  Teraz zajmiemy się obsługą plików znajdujących się na liście oraz obsługą paska postępu 'ProgressBar1', który będzie informował nas o tym jak długo plik jest odtwarzany oraz ile jeszcze pozostało do końca. Natomiast obiekt 'Edit1' będzie wyświetlał tytuł utworu oraz jego czas całkowity dlatego stworzymy również funkcję obliczającą całkowitą długość utworu - 'FullTime'. Wszystko to zostanie zawarte w jednej funkcji 'PlayFile'. W tym celu przechodzimy do pliku nagłówkowego Unit1.h i w sekcji private definiujemy funkcję.
Przykład:

// Plik nagłówkowy np. Unit1.h.
//--------------------------------
private:
void __fastcall LoadFiles(void);
void __fastcall PlayFile(int index); // nowo tworzona funkcja PlayFile
AnsiString FullTime(void); // nowo tworzona funkcja FullTime
TStringList *Lista;
//--------------------------------


Następnie przechodzimy do pliku źródłowego i tworzymy obsługę funkcji 'PlayFile', a nastęnie w zdarzeniu przycisku 'Play1' - 'OnClick' wywołujemy funkcję i uruchamiamy odtwarzanie pliku wskazanego na liście - 'ListBox1'.
Przykład:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
AnsiString TForm1::FullTime(void)
{
  String MediaLength = "??:??:??";
  MediaPlayer1->TimeFormat = tfMilliseconds;
  int Time = MediaPlayer1->Length / 1000;
  int Hours = Time / 3600;
  int Minutes = (Time - (Hours*3600)) / 60;
  int Seconds = Time - (Hours*3600) - (Minutes*60);

  MediaLength = FormatCurr(" - Długość: 0#:", Hours);
  MediaLength += FormatCurr("0#:", Minutes);
  MediaLength += FormatCurr("0#", Seconds);

  return MediaLength;
}
//--------------------------------
void __fastcall TForm1::PlayFile(int index)
{
MediaPlayer1->FileName = Lista->Strings[index];
MediaPlayer1->Open();

Timer1->Enabled = true;
ProgressBar1->Max = MediaPlayer1->Length;

MediaPlayer1->Play();
Edit1->Text = ListBox1->Items->Strings[index] + FullTime();
}
//--------------------------------
void __fastcall TForm1::Play1Click(TObject *Sender)
{
if(ListBox1->ItemIndex >= 0)
PlayFile(ListBox1->ItemIndex);
else {
Application->MessageBox("Wybierz z listy plik który chcesz odtworzyć!", "Nie wybrano pliku.", MB_OK|MB_ICONSTOP);
          }
}
//--------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
ProgressBar1->Position = MediaPlayer1->Position;
if(ProgressBar1->Position == MediaPlayer1->Length){
    Timer1->Enabled = false;
    if(ListBox1->ItemIndex < ListBox1->Items->Count - 1)
      ListBox1->ItemIndex = ListBox1->ItemIndex + 1;
    else ListBox1->ItemIndex = 0;
      MediaPlayer1->Close();
      PlayFile(ListBox1->ItemIndex);
              }
}
//--------------------------------


    krok 5.- wykańczanie programu, dołączanie obsługi pozostałych obiektów
Teraz w zdarzeniu 'OnChange' obiektu 'Volume'1 dołączymy obsługę regulacji głośności, a następnie dołączymy obsługę pozostałych przycisków.
Przykład:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::Volume1Change(TObject *Sender)
{
waveOutSetVolume (0, (Volume1->Position * 65536) + Volume1->Position);
}
//--------------------------------
void __fastcall TForm1::Pause1Click(TObject *Sender)
{
MediaPlayer1->Pause();
}
//--------------------------------
void __fastcall TForm1::Stop1Click(TObject *Sender)
{
Timer1->Enabled = false;
MediaPlayer1->Close();
}
//--------------------------------
void __fastcall
TForm1::Rewind1Click(TObject *Sender)
{
if(ListBox1->ItemIndex > 0)
ListBox1->ItemIndex--;
PlayFile(ListBox1->ItemIndex);
}
//--------------------------------
void __fastcall TForm1::Forward1Click(TObject *Sender)
{
if(ListBox1->ItemIndex < ListBox1->Items->Count)
ListBox1->ItemIndex++;
PlayFile(ListBox1->ItemIndex);
}
//--------------------------------


  Program jest już gotowy i jeśli wszystko zrobiliście dobrze, tak jak to opisałem to będzie działał. Można by go jeszcze usprawnić, ale to by uczyniło kod i cały kurs mało czytelnym. Tak jak obiecywałem program nie jest piękny, nie obfituje również w opcje, ale co to by była za frajda tworzyć programy poprzez przpisywanie lub kopiowanie kodu, dlatego resztę możecie rozwinąć, zmodyfikować, poprawić według własnego uznania.
  Program nie został dokładnie przetestowany, tak więc jeśli znajdziecie jakieś błędy to uwagi proszę mi przesłać e-mail'em.

Przygotował: Cyfrowy Baron


...pliki źródłowe (BCB 4).