Criando um Tocador de udio com Playlist 03-09-2013
Voc, provavelmente, j desejou criar seu
prprio player de udio. E isso no difcil, se usarmos o componente MediaPlayer
do
Delphi, presente na paleta System. Ento, mos obra.
Crie um novo projeto e vamos adicionar a ele trs componentes
Panel: um ficar alinhado na parte superior do formulrio, outro na
lateral esquerda e o terceiro ocupar a rea restante. Mas para que eles se
comportem da maneira desejada, vamos ajustar a propriedade Align de cada
um deles. Para o Panel que ficar alinhado ao topo, ajuste-a para alTop.
Para o que ficar esquerda, mude para alLeft. O outro, ainda no deve
ser alterado: faremos isso via cdigo posteriormente. Assim, sua aplicao, por
enquanto, tem essa aparncia:
OK, uma aparncia nada agradvel, mas vamos modific-la aos
poucos. Clique no
Panel1 e vamos alterar sua propriedade Caption para algo que
indique o objetivo do programa. Digite, por exemplo, Playlist. Nos panels
dois e trs, simplesmente apague o texto dos Captions - eles ficaro vazios.
Agora, da paleta Additional, pegue um
componente Splitter e coloque prximo ao Panel2. Este componente ser
muito til: ele permitir o redimensionamento do segundo painel quando voc
executar seu programa, permitindo o ajuste de sua largura conforme seu gosto.
Sempre que o segundo painel for redimensionado, o terceiro painel ir, tambm,
se auto-ajustar ao espao que lhe sobrou. Mas, para que isso ocorra, vamos
inserir o seguinte cdigo no evento OnCreate do formulrio:
//Cdigo
para o evento OnCreate do form1
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel3.Align := alClient;
end;
O alinhamento alClient diz ao Panel que ele dever ocupar
toda a rea restante do formulrio. Podemos tambm eliminar as bordas dos
painis, para que fiquem mais sutis.Para isso, altere a propriedade
BevelOuter de cada Panel para bvNone.
Agora, pegue um componente ListBox da
paleta Standard e coloque-o no terceiro Panel. Esta ListBox conter os
nomes das msicas que sero executadas. Ajuste o componente no centro do Panel e
altere sua propriedade Anchors para que akLeft, akTop, akRight e
akBottom fiquem como True. Isso permitir que, quando o terceiro
panel sofrer um redimensionamento, a Listbox o acompanhe. No entanto, deixe um
pouco mais de espao prximo ao rodap da Listbox, pois l iremos adicionar os
botes que controlaro a playlist. Eis o que voc deve ter at o momento:
Se voc executar seu aplicativo neste ponto, ver que o
redimensionamento com o
Splitter j funciona, influenciando nas dimenses dos Panels 2 e 3 e,
conseqentemente, na da Listbox.
Vamos adicionar, agora, o nosso componente
principal: o MediaPlayer, da paleta System. Coloque-o no Panel1
e altere sua propriedade Visible para False. Ns no desejamos ver
os botes deste componente, pois iremos criar nossos prprios botes de comando
para nossa playlist - isso nos permitir um controle maior sobre as aes do
aplicativo.
Para os botes, usaremos seis SpeedButtons
(),
da paleta Additional. Coloque-os abaixo da ListBox. interessante
alterar a propriedade Name de cada um deles de acordo com a funo que
ir exercer. Assim, na ordem, renomeie-os para BtnBack, BtnNext, BtnPlay,
BtnPause, BtnStop e BtnSair - eles sero, respectivamente, os
botes de voltar, avanar, tocar, pausar e parar as msicas da playlist; o
ltimo ir fechar o aplicativo. Devemos tambm colocar pequenas figuras nestes
botes. No arquivo zipado disponibilizado para download esto as figuras usadas
para cada boto, prontas para voc utilizar. Basta associ-las propriedade
Glyph de cada SpeedButton.
Ainda, abaixo da seqncia de botes, coloque
uma TrackBar (paleta Win32). Ela ser usada como controle de
volume do software. Ajuste a propriedade ThumbLength da TrackBar para 14.
Isso deixar o seu "ponteiro" em um tamanho menor, mais discreto. Ajuste tambm
a propriedade TickMarks para tmTopLeft. Assim, as marcas
indicadoras de posio (os "risquinhos" milimtricos da TrackBar) ficaro na
parte superior do componente, e no abaixo dele. Agora, ajuste a propriedade
TickStyle para tsManual. Isso eliminar todos os "risquinhos" da
TrackBar, deixando apenas os indicadores inicial e final de posio,
proporcionando ao
componente um visual mais "limpo". Por fim, altere o valor da propriedade
Max para 99. Esse ser o volume mximo que o componente dever atingir. Cabe
aqui uma explicao: teoricamente, o volume mximo deveria ser 100 (ou seja,
100% do total obtido), mas por um falha do componente, ao chegar a 100, o volume
totalmente zerado - o que no pode acontecer. Por isso, deixe-o com o valor de
99. Essa diferena de 1 ponto no faz diferena ao ouvido humano.
De
volta paleta Standard, adicione ao formulrio, em qualquer local, um
componente PopupMenu. Este um menu especial, daqueles que so acionados
quando clicamos em cima de algum objeto com o boto direito do mouse. O que
queremos aqui que, ao clicarmos com o boto direito do mouse na Listbox, surja
um menu com as opes de adicionar e remover faixas da playlist. Para isso,
clique na ListBox e busque a propriedade PopupMenu. Clique na caixa de
seleo logo frente e escolha PopupMenu1. Pronto: a ligao
entre o nosso menu e a Listbox est feita.
Falta adicionar opes ao menu. Para isso,
clique duas vezes sobre o componente que voc acabou de colocar no formulrio e
digite Adicionar msica e pressione ENTER. Depois, digite Remover
faixa e pressione ENTER. Voc ter algo semelhante a isto:
O nosso pequeno menu j tem opes suficientes agora. Mas, bvio,
falta codific-las, mas faremos isso depois. Por enquanto, precisamos de mais
dois componentes: um Timer (paleta System) e um OpenDialog,
da paleta Dialogs.
Codificando o aplicativo
Agora que entramos na parte mais trabalhosa. D dois
cliques no seu formulrio para entrarmos na Unit1, onde iremos iniciar a
codificao. Antes da seo Implementation, vamos declarar algumas
variveis que sero necessrias:
Lista :
TStringList;
PLAYING : Boolean = FALSE;
Cont : Integer = 0 ;
A varivel Lista, do tipo TStringList, capaz de
armazenar uma lista de textos: ideal para guardar nossa playlist, que nada
mais do que uma poro de caminhos de pastas e arquivos de udio. O objetivo
que a lista sempre carregue e salve um arquivo .TXT (texto
simples) contendo os nomes das msicas escolhidas. A varivel
PLAYING, do tipo Boolean, permite que o sistema saiba se ainda h msica
em execuo ou no: sempre que se pressionar o boto Play, PLAYING dever ser
True (isto , est em execuo); sempre que se pressionar o boto Stop, ela
dever ser False. Note que ela j foi declarada e, ao mesmo tempo,
iniciada como False, pois o aplicativo no inicia tocando msica de imediato. E,
por fim, a varivel Cont, que armazenar qual faixa da varivel Lista
est sendo tocada. Isso necessrio para que, ao retomarmos uma msica depois
de uma pausa (boto Pause), o player continue executando a mesma msica, ao
invs de retornar para a primeira da lista de novo. Note tambm que Cont
j foi iniciada com 0 (zero), pois 0 o primeiro item de uma TStringList,
1 o segundo, 2 o terceiro, e assim por diante. Ou seja, ao comear a tocar,
inicia-se pela primeira msica da Lista.
Vamos usar a varivel Lista agora: no evento OnCreate
do formulrio, aps a linha Panel3.Align := alClient,
digite o seguinte:
Lista :=
TSTringList.Create;
if FileExists(ExtractFilePath(ParamStr(0))+'Lista.txt') then begin
Lista.LoadFromFile(ExtractFilePath(ParamStr(0))+'Lista.txt');
for i:=0 to Lista.Count-1 do
ListBox1.Items.Add(ExtractFileName(Lista.Strings[i]));
end;
Vamos analisar o que fizemos: toda lista de Strings precisa
ser criada na memria primeiro para poder ser usada; por isso, usamos
TStringList.Create e atribumos essa nova lista varivel j declarada.
Depois, verificamos se j existia previamente um arquivo texto com alguma
playlist salva anteriormente com a funo FileExists. Se FileExists
for True, ento carrega a lista com as msicas atravs da funo LoadFromFile.
Note a utilizao de uma funo adicional:
ExtractFilePath(ParamStr(0)). Este um meio que se tem de descobrir
onde est o executvel do nosso programa. Como desejamos armazenar nosso arquivo
texto (Lista.txt) no mesmo local do executvel para facilitar, usamos ParamStr
(0),
que contm todo o caminho de pastas at o nome do arquivo executvel e, ao mesmo
tempo, extramos com ExtractFilePath apenas a informao que nos
interessava: o diretrio do executvel.
Por fim, usamos um lao for...do para adicionarmos ao
componente ListBox, um a um, todos os arquivos contidos em Lista.txt, mas
sem o caminho das pastas, deixando apenas o nome do
arquivo listado. O caminho de pastas pode ser retirado usando-se a funo
ExtractFileName(), que extrai de uma string apenas a poro que corresponde
exatamente o nome do arquivo.
Estes procedimentos acontecem todos no evento OnCreate do
form. Vamos codificar agora a opo do menu Popup Adicionar Msica. Em
seu evento OnClick, digite este cdigo:
if
OpenDialog1.Execute
then begin
Lista.Add(OpenDialog1.FileName);
ListBox1.Items.Add(ExtractFileName(OpenDialog1.FileName));
end;
O cdigo acima faz com que uma caixa de dilogo "Abrir Arquivo", tpica
do Windows, aparea na tela para que o usurio possa escolher qual arquivo
deseja adicionar playlist. Com o mtodo Execute, estamos dizendo que,
se o usurio escolher um arquivo e clicar no boto abrir, o nome do arquivo ser
passado nossa Lista (atravs do mtodo Add()) e tambm playlist que
aparece na ListBox (atravs de Items.Add()), mas no sem antes remover
todo o caminho de pastas (de novo!) para que possamos exibir apenas o nome da
msica.
O menu Popup Remover faixa faz o inverso. Ele
pergunta, em primeiro lugar, se desejamos mesmo remover a faixa selecionada.
Para isso, usamos Application.Messagebox, que mostra uma caixa de mensagens na
tela, tpica do Windows tambm, e que retorna IDYES se o usurio clicar
em "Sim", e IDNO se escolher "No":
if
application.messagebox
(pchar('Remover faixa '+ ListBox1.Items.strings[ListBox1.ItemIndex] + '?'), pchar(Caption),36) =
IDYES then
begin
Lista.Delete(ListBox1.ItemIndex);
ListBox1.DeleteSelected;
if
Cont > 0
then
Cont := Cont - 1;
end;
Note que, para sabermos em qual msica o usurio clicou, usamos uma propriedade
interessante da ListBox chamada ItemIndex. Ela armazena a posio em que
est o texto sobre o qual o mouse clicou. O que precisamos fazer depois pedir
que esse item seja removido da lista - alis, de ambas: da lista que armazena
todo o caminho de pastas at as msicas e tambm das ListBox. A linha
Lista.Delete(ListBox1.ItemIndex)
apaga o nome do arquivo que contm o caminho completo e
ListBox1.DeleteSelected
apaga o item selecionado na ListBox que, teoricamente, o que mais
importa para o usurio, pois o item que ele v na tela. O que vem depois um
complemento para evitar falhas na execuo da playlist: o nosso contador Cont,
que guarda o nmero da msica em execuo, precisa tambm saber que a msica
atualmente clicada foi removida e que, em virtude disso, ele deve voltar para a
faixa anterior. Foi o que fizemos em Cont := Cont -
1. Mas note que ele s subtrair 1 do valor de Cont se
realmente houver mais msicas na listagem - ou seja, se Cont > 0
pois, se Cont for zero, significa que no h como voltar para a msica anterior:
a lista est vazia.
Os botes Play, Pause, Stop, Avanar e Voltar
Agora, vamos melhor parte: codificar os botes de Play e
Stop. Primeiro, o Play. No seu evento OnClick, coloque isto:
if PLAYING
then MediaPlayer1.Resume
else begin
MediaPlayer1.Close;
MediaPlayer1.FileName := Lista.Strings[Cont];
ListBox1.Selected[Cont] := True;
MediaPlayer1.Open;
MediaPlayer1.Play;
Timer1.Enabled := True;//habilita timer
end;
PLAYING := True;
Ao clicar em Play, nosso software precisa verificar se ele
dever comear a tocar uma faixa desde o comeo ou se para continuar uma faixa
anteriormente pausada. Para isso, testamos nossa varivel PLAYING: se ela
for True, indica que a faixa j estava em execuo e, portanto, provavelmente
agora estava pausada, devendo continuar a partir do ponto de parada. Isso pode
ser feito com o mtodo Resume do MediaPlayer: ele prossegue
tocando a msica exatamente a partir do ponto onde ela se encontrava. o que
faz a linha if PLAYING then
MediaPlayer1.Resume. Mas se PLAYING no era True, ento no havia
msica em execuo, devendo comear uma desde o incio.
Precisamos, ento,
mostrar ao player qual a faixa que ele deve tocar, escolhendo a atual da nossa
lista atravs de Lista.Strings[Cont].
Lembre-se que Cont guarda qual msica da nossa lista deve ser tocada e, passando
Cont como parmetro para nossa Lista atravs da propriedade Strings, pegamos o
nome do arquivo a ser executado na seqncia. Isso quer dizer que, se Cont
contiver o valor 5, ao fazermos Lista.Strings[Cont], nossa Lista saber que deve
pegar a sexta linha e atribuir ao MediaPlayer. o que acontece em
MediaPlayer1.FileName := Lista.Strings[Cont].
Adicionalmente, a ListBox deve mostrar qual a faixa selecionada com
ListBox1.Selected[Cont] := True.
Essa linha permite isso, usando a mesma varivel Cont para que a ListBox possa
indicar qual linha deve estar marcada. O que vem a seguir apenas uma
consequencia: o MediaPlayer deve ser aberto com Open e executar a cano
com Play. Alm disso, o Timer deve ser habilitado com
Timer1.Enabled:=True e
nossa varivel PLAYING deve passar para True, indicando ao software que
h uma faixa sendo reproduzida.
O boto de Stop mais fcil:
if PLAYING
then begin
MediaPlayer1.Stop;
PLAYING := FALSE;
Timer1.Enabled := False;
end;
Aqui, se h faixa sendo tocada, o
MediaPlayer deve ser parado atravs da funo Stop. Alm disso,
PLAYING deve se tornar False e o Timer deve ficar desabilitado, com
Timer1.Enabled := False.
E, mais fcil ainda, o boto de pausa:
MediaPlayer1.Pause;
Aqui, nada de duvidoso: apenas chamamos a funo Pause do componente
MediaPlayer. Mas, para os botes de Avanar e Retroceder, as coisas so um pouco
diferentes. Para cada vez que clicarmos num deles, a execuo da faixa atual e o
timer devero ser parados; o MediaPlayer deve ser fechado, um novo arquivo
musical da lista deve ser atribudo a ele em sua propriedade FileName para,
ento, ele ser aberto novamente e ter sua funo Play chamada. Como os dois
botes precisaro da mesma funcionalidade, melhor criarmos uma procedure
separada e depois apenas cham-la em cada um dos eventos OnClick. Para isso,
localize o incio dos cdigos da sua Unit e, entre as declaraes Type e
Private,
acrescente esta:
procedure
MudaFaixa(Valor : Integer);
Isso apenas indica ao Delphi que desejamos criar uma nova
procedure. Para cri-la de fato, clique com o cursor do mouse sobre ela e
pressione CTRL+SHIFT+C no teclado. Isso far com que o "corpo" da funo
seja criado. Nele, digite o seguinte:
if (Valor <> -1)
and (Valor <> 1) then exit;
if PLAYING then begin
MediaPlayer1.Stop;
Timer1.Enabled := False;
PLAYING := FALSE;
end;
Cont := Cont + Valor;
MediaPlayer1.Close;
if (Cont > (ListBox1.Items.Count -1))
then
Cont := 0
else
if (Cont < 0)
then
Cont := (ListBox1.Items.Count -1) ;
MediaPlayer1.FileName := Lista.Strings[Cont];
ListBox1.Selected[Cont]:=true;
MediaPlayer1.Open;
MediaPlayer1.Play;
Timer1.Enabled := True;
PLAYING := True;
Note o uso de uma varivel extra que estamos usando desde que
a funo foi declarada, na parte superior da Unit: a varivel Valor.
Atravs dela, passaremos um parmetro para a funo que dever ser 1 se
desejamos avanar uma msica; -1 se quisermos retroceder uma msica.
Qualquer valor diferente de 1 e -1 ser ignorado pela nossa
procedure. o que nos diz a primeira linha: if
(Valor <> -1) and (Valor <> 1) then exit. Isso significa
que
se Valor receber algo diferente de 1 ou -1, simplesmente "caia
fora", ou seja, no execute o resto da funo.
O prximo bloco de cdigo responsvel por interromper a
execuo da faixa sempre que quisermos avanar ou voltar em nossa playlist. Por
isso, precisamos parar o MediaPlayer (usando o mtodo Stop), parar
o Timer (deixando Enabled em False) e dizer que, naquele
instante, a msica que estava sendo reproduzida parou, atravs de
PLAYING:=False.
Depois disso, nossa varivel Cont dever "pular" de
faixa, adicionando o contedo da varivel Valor, para saber se ela deve
buscar a prxima faixa da Lista ou a anterior. nesse ponto que nosso programa
usar o 1 ou -1, pois um destes valores estar armazenado em
Valor. Alm disso, o MediaPlayer deve ser fechado com o mtodo
Close.
Agora, um detalhe importante, para o qual o internauta
Flvio Bernardes, que
leu este artigo, me chamou a ateno: note que se j estivermos executando a
ltima faixa da lista e a procedure receber, novamente, o valor 1, para
tentar ir para uma faixa posterior, o nosso aplicativo ir disparar um
erro, j que no h mais faixas. O mesmo acontecer se, estando na primeira
faixa, nossa procedure receber de novo o valor -1, como que tentando
voltar para uma faixa anterior que no existe.
Para resolver este problema, precisamos fazer o seguinte: se
estivermos no final da lista (onde a quantidade total de faixas ser
ListBox1.Items.Count-1), deveremos voltar para a primeira faixa (e Cont
ser zero de novo, pois a primeira msica est na posio zero). Do mesmo modo,
se estivermos na primeira (onde Cont j zero) e tentarmos voltar para
uma anterior, devemos, ento, executar a ltima da lista, e Cont dever
ser atribudo de ListBox1.Items.Count-1. Observe:
if
(Cont > (ListBox1.Items.Count -1))
then
Cont := 0
Portanto, para quando Cont ultrapassar o valor final
da lista, Cont dever receber zero de novo, para tocar a primeira faixa.
Mas, se Cont receber um nmero menor que zero, ento no h faixas antes da
atual e, portanto, dever ir para a ltima da lista:
if
(Cont < 0)
then
Cont := (ListBox1.Items.Count -1) ;
Feito isso, um novo arquivo de udio deve ser atribudo ao MediaPlayer,
atravs de sua propriedade FileName, usando o valor atual do contador Cont, que
pegar a faixa correta da lista de Strings. o que acontece na linha
MediaPlayer1.FileName := Lista.Strings[Cont].
Mais uma vez, precisamos mostrar qual , ento, a nova msica que est
selecionada na ListBox, atravs da linha ListBox1.Selected
[Cont]:=true.
Por fim, abre-se o player com a funo Open e inicia-se a reproduo
novamente, com a funo Play. Neste momento, o Timer novamente
habilitado e PLAYING passa, outra vez, para True.
Com isso, j podemos codificar os botes Avanar e Voltar. No
primeiro, coloque o seguinte no seu evento OnClick:
MudaFaixa(1);
No segundo, coloque isto no evento OnClick:
MudaFaixa(-
1);
Isso faz com que a funo MudaFaixa() receba o valor 1
para avanar, sabendo que dever ir para a faixa seguinte, e -1 para retroceder,
sabendo que dever voltar uma faixa.
O Timer do Aplicativo
Vamos codificar o Timer agora. J habilitamos e
desabilitamos o Timer diversas vezes em nosso cdigo, mas o que ele far
realmente? Eis o que deve ser digitado no evento OnTimer do componente
Timer1:
if
MediaPlayer1.Position = MediaPlayer1.Length then begin
with MediaPlayer1 do begin
Cont := Cont + 1;
if Cont > Lista.Count-1 then
Cont := 0;
Close ;
if FileExists(Lista.Strings[Cont]) then begin
FileName := Lista.Strings[Cont];
Open ;
Play;
end
else
Cont := Cont + 1;
end; //with MediaPlayer
end; //if MediaPlayer
ListBox1.Selected[Cont]
:= True ;
A primeira linha verifica o andamento da msica do MediaPlayer; se a posio da
faixa (Position) for igual a sua largura (Length), ento significa
que aquela faixa chegou ao final e o player deve mudar para a seguinte.
Ele faz isso somando 1 ao valor do contador Cont, fechando o MediaPlayer com
Close e obtendo o novo nome de arquivo de udio a
executar. Abre-se, ento, o novo arquivo (com Open) e inicia-se sua reproduo
com o mtodo Play. Note que, aqui, antes de iniciar a nova faixa,
recomendvel verificar se o arquivo contido na playlist ainda existe no disco do
computador com a funo FileExists(), conforme mostrado na linha
if FileExists(Lista.Strings[Cont]) then...
Do contrrio, pode-se tentar executar um MP3 que nem sequer est mais no HD e a
teremos um erro na tela. A funo FileExists() retorna True se o
arquivo existir e False se no existir. Caso o arquivo em questo no mais
exista, o if pula para o ltimo else do bloco e adiciona mais 1
ao Cont, para tentar a faixa subseqente - at que uma faixa presente no disco seja
encontrada. Note tambm outro teste com if que foi realizado: nas linhas
if Cont > Lista.Count-1 then Cont := 0
estamos orientando nosso programa a buscar novamente a primeira
msica da playlist (Cont := 0) caso o valor de Cont ultrapasse a
quantidade de msicas existentes na listagem (isto , quando Cont > Lista.Count-
1,
o que significa que no h prxima msica, mas que deve-se retornar ao comeo).
Ao mesmo tempo, aps iniciar a msica, pedimos que a ListBox mostrasse qual a
faixa atualmente em execuo, selecionando-a com
ListBox1.Selected[Cont] := True.
Observe tambm uma maneira diferente de nos referirmos ao
MediaPlayer: logo no incio do cdigo, temos with MediaPlayer1 do
begin.
Isso no de todo necessrio, mas serve para tornar mais rpida a digitao.
Sem a palavra reservada with, toda vez que nos referssemos a um mtodo ou
propriedade do MediaPlayer, teramos que digitar o nome do componente:
MediaPlayer1.FileName := Lista.Strings[Cont];
MediaPlayer1.Open ;
MediaPlayer1.Play;
Englobando esta mesma poro de cdigo em um with, basta
chamar seus mtodos e propriedades que o Delphi j sabe a qual componente
estamos nos referindo:
with
MediaPlayer1 do begin
...
FileName := Lista.Strings[Cont];
Open ;
Play;
...
end; //with MediaPlayer
Observe quer todo With deve terminar com um end (note o
end que delimita seu final na linha terminada com
end;//with MediaPlayer).
Ajustando o menu Popup
Devemos, neste momento, fazer uma pequena modificao num
cdigo j implementado: o do menu Popup Remover faixa. Volte ao seu
evento OnClick e adicione ao cdigo existente a linha em destaque abaixo:
if
application.messagebox(pchar('Remover
faixa '+ ListBox1.Items.strings[ListBox1.ItemIndex] + '?'), pchar(Caption),36) =
IDYES then
begin
BtnStopClick(self);
Lista.Delete(ListBox1.ItemIndex);
ListBox1.DeleteSelected;
if
Cont > 0
then
Cont := Cont - 1;
end;
A linha que adicionamos faz uma chamada estratgica ao boto
Stop. Como ainda no havamos codificado esse boto ao escrever o cdigo
deste menu Popup, deixamos temporariamente esta linha de lado. Mas agora ela
deve ser usada - e por um motivo muito simples: se a faixa que for excluda
coincidir de ser justamente aquela que estiver em execuo naquele momento, o
player ir se perder ao tentar continuar executando-a. Por isso, o melhor a
fazer par-lo (chamando o prprio evento OnClick do boto BtnStop)
para que o contador possa fazer os ajustes necessrios e a listagem possa ser
ajustada nova quantidade de msicas (afinal, excluir uma faixa altera a
quantidade de msicas presentes na lista).
Controlando o Volume do Som
Vamos ver como podemos aumentar ou diminuir o som dos
alto-falantes. Para isso, adicione a Unit MMSystem clusula uses
do seu aplicativo (observe o detalhe em vermelho na figura ao lado).
Depois, entre as sesses type e private, digite o
seguinte:
procedure TestaVolume;
Pressione CTRL+SHIFT+C para criar o corpo dessa nova
procedure e, nela, implemente o seguinte cdigo:
procedure
TForm1.TestaVolume;
var
WaveCaps : TWaveOutCaps;
Volume : DWord;
begin
if waveOutGetDevCaps(WAVE_MAPPER, @WaveCaps, sizeof(TWaveOutCaps)) =
MMSYSERR_NOERROR then
if (WaveCaps.dwSupport and WAVECAPS_VOLUME) <> 0 then begin
WaveOutGetVolume(Integer(WAVE_MAPPER), @Volume);
with TrackBar1 do
Position := 100 - Trunc(LoWord(Volume) / $FFFF * 100);
end;
end;
Aqui, temos uma varivel do tipo TWaveOutCaps e outra
do tipo DWord. TWaveOutCaps um objeto que armazena dados do hardware de
udio presente no sistema.
Para descobrir se teremos condio de modificar em tempo real
o volume dos auto-falantes, usamos a funo WaveOutGetDeviceCaps( ) que
armazenar as capacidades de udio do sistema na varivel WaveCaps. Se a funo
retornar MMSYSERR_NOERROR significa que o
hardware de udio est presente e no apresentou nenhum erro. A, testamos a
propriedade dwSupport de TWaveOutCaps com WAVECAPS_VOLUME.
Quando testadas juntas, dessa maneira:
if
(WaveCaps.dwSupport and WAVECAPS_VOLUME)...
o resultado obtido ser diferente de zero (<>
0) se houver suporte para alterao de volume, e igual a zero caso
contrrio. Portanto, se for diferente de zero, devemos obter qual a "posio"
deste volume com a funo WaveOutGetVolume. Esta funo obtm um "id"
(identificador) para o dispositivo de udio atravs do parmetro WAVE_MAPPER
(que deve ser convertido para inteiro com Integer( ) para poder
ser usado) e um "ponteiro" para a varivel Volume (@Volume).
O Windows trabalha muito com "ponteiros", referenciados no Delphi por
"arroba" (@).
Uma vez que os dados do volume esto armazenados na varivel
Volume, precisamos "quebrar" esses dados em partes para poder atribuir o
valor correto propriedade Position da TrackBar. A varivel
Volume, do tipo DWord, um cardinal (um tipo de Inteiro) que armazena
valores entre 0 e 65.535. O Windows costuma unir em um s nmero
vrias informaes. Por exemplo, a varivel Volume contm, na verdade,
informaes sobre os dois canais de udio - o da esquerda e o da direita. Mas
precisamos de apenas um para determinar o volume atual - por essa razo,
quebra-se a informao com LoWord(), para obtermos apenas uma parte dela.
Depois, divide-se o valor obtido por $FFFF (que 65.535 em hexadecimal).
A funo Trunc() serve apenas para "truncar" o resultado da diviso,
garantindo que tenhamos um nmero inteiro como resposta. Ao final, a
linha Position := 100 - Trunc(LoWord(Volume) / $FFFF
* 100) atribui, em
percentuais, a posio correta do volume do sistema naquele instante.
Agora, precisamos criar a funo que nos permitir modificar
o volume. Para isso, entre as sesses type e private, digite o seguinte:
procedure MudaVolume;
Pressione CTRL+SHIFT+C e complete o corpo da
procedure conforme segue:
procedure
TForm1.MudaVolume;
var
WaveCaps : TWaveOutCaps;
VolDir, VolEsq : Word;
begin
VolEsq := Trunc((TrackBar1.Position-100) / 100 * $FFFF);
VolDir := Trunc((TrackBar1.Position-100) / 100 * $FFFF);
if waveOutGetDevCaps(WAVE_MAPPER, @WaveCaps, sizeof(TWaveOutCaps)) =
MMSYSERR_NOERROR then
if (WaveCaps.dwSupport and WAVECAPS_VOLUME) <> 0 then
WaveOutSetVolume(Integer(WAVE_MAPPER), MakeLong(VolEsq,VolDir));
end;
Aqui, as duas primeiras linhas so simples: apenas capturam a
posio da TrackBar e atribuem, em percentuais, ao volume dos alto-falantes
esquerdo e direito. Depois, testa-se novamente se possvel alterar o volume
usando WaveOutGetDevCaps() e, em caso positivo, ajusta o novo volume com
a funo WaveOutSetVolume(). Esta funo tambm usa o parmetro
WAVE_MAPPER, que obtm um id para o dispositivo de udio e, depois,
"une" os dois canais obtidos em um nico nmero inteiro longo (Longint), atravs
da funo MakeLong().
ltimas Modificaes
Uma vez criadas as funes de volume, devemos cham-las nos
locais corretos de nossa aplicao. A funo que testa o suporte modificao
de volume deve ser chamada logo no evento OnCreate do formulrio:
TestaVolume;
A funo que altera o volume deve estar no evento OnChange da TrackBar:
MudaVolume ;
Para incrementar o software, podemos ainda colocar um
componente Image (paleta Additional) no Panel2 para que
possamos exibir uma figura no local. O arquivo zipado traz trs figuras JPG
de sugesto, mas voc pode modificar a seu critrio. Ajuste o tamanho do
componente Image para que fique quase igual s dimenses do Panel2. Depois,
ajuste as propriedades Anchors do Image, deixando todos os itens em True. Por
fim, altere a propriedade Stretch para True tambm. A propriedade
Stretch, quando configurada dessa maneira, faz com que a figura escolhida
ajuste-se automaticamente ao tamanho do componente.
Para que o componente Image funcione a contento, ainda
devemos acrescentar a Unit JPEG na clusulas Uses. Somente assim o
componente estar apto a receber tambm figuras no formato JPG ou JPEG.
Melhorando o Programa
Podemos ainda acrescentar algumas outras funcionalidades ao
programa. Por exemplo, que tal uma barra de progresso que mostre o andamento da
faixa atual? Podemos usar o Timer que j temos no nosso form e adicionar uma
ProgressBar, da paleta Win32. Posicione-a abaixo do controle de
volume. Altere sua propriedade Smooth para True e ajuste sua propriedade
Anchors para que akLeft, akRight e akBottom fiquem configuradas como True.
No evento OnTimer do Timer1, faa as modificaes marcadas em destaque:
if
MediaPlayer1.Position = MediaPlayer1.Length then begin
with MediaPlayer1 do begin
Cont := Cont + 1;
if Cont > Lista.Count-1 then
Cont := 0;
Close ;
if FileExists(Lista.Strings[Cont]) then begin
TimeFormat := tfHMS;
FileName := Lista.Strings[Cont];
Open ;
Play;
end
else
Cont := Cont + 1;
end; //with
MediaPlayer
end; //if MediaPlayer
if PLAYING then begin
ProgressBar1.Max := MediaPlayer1.Length;
ProgressBar1.Position := MediaPlayer1.Position;
end;
A linha TimeFormat := tfHMS apenas
configura o formato de tempo adotado pelo MediaPlayer. Aqui, estamos
instruindo-o para que adote o padro, que Hora-Minuto-Segundo. Ao final do
cdigo, se houver msica em execuo (isto , quando PLAYING = true)
, ento a barra de progresso (ProgressBar1) dever ter sua
posio mxima ajustada ao tamanho (Length) da faixa e sua posio
atual igual posio da msica. Assim, sempre que a faixa do MediaPlayer
estiver em "andamento", a posio (Position) da ProgressBar dever
acompanh-lo.
Fonte: ASMC
|