Você, provavelmente, já desejou criar seu
próprio player de áudio. E isso não é difícil, se usarmos o componente MediaPlayer
do
Delphi, presente na paleta System. Então, mãos à obra.
Crie um novo projeto e vamos adicionar a ele três componentes
Panel: um ficará alinhado na parte superior do formulário, 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 não deve
ser alterado: faremos isso via código posteriormente. Assim, sua aplicação, por
enquanto, tem essa aparência:
OK, é uma aparência nada agradável, 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 três, simplesmente apague o texto dos Captions - eles ficarão vazios.
Agora, da paleta Additional, pegue um
componente Splitter e coloque próximo 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á, também,
se auto-ajustar ao espaço que lhe sobrou. Mas, para que isso ocorra, vamos
inserir o seguinte código no evento OnCreate do formulário:
//Código
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 formulário. Podemos também eliminar as bordas dos
painéis, 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 músicas que serão 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 espaço próximo ao rodapé da Listbox, pois lá iremos adicionar os
botões que controlarão 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 dimensões dos Panels 2 e 3 e,
conseqüentemente, 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. Nós não desejamos ver
os botões deste componente, pois iremos criar nossos próprios botões de comando
para nossa playlist - isso nos permitirá um controle maior sobre as ações do
aplicativo.
Para os botões, usaremos seis SpeedButtons
(),
da paleta Additional. Coloque-os abaixo da ListBox. É interessante
alterar a propriedade Name de cada um deles de acordo com a função que
irá exercer. Assim, na ordem, renomeie-os para BtnBack, BtnNext, BtnPlay,
BtnPause, BtnStop e BtnSair - eles serão, respectivamente, os
botões de voltar, avançar, tocar, pausar e parar as músicas da playlist; o
último irá fechar o aplicativo. Devemos também colocar pequenas figuras nestes
botões. No arquivo zipado disponibilizado para download estão as figuras usadas
para cada botão, prontas para você utilizar. Basta associá-las à propriedade
Glyph de cada SpeedButton.
Ainda, abaixo da seqüência de botões, 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 também
a propriedade TickMarks para tmTopLeft. Assim, as marcas
indicadoras de posição (os "risquinhos" milimétricos da TrackBar) ficarão na
parte superior do componente, e não abaixo dele. Agora, ajuste a propriedade
TickStyle para tsManual. Isso eliminará todos os "risquinhos" da
TrackBar, deixando apenas os indicadores inicial e final de posição,
proporcionando ao
componente um visual mais "limpo". Por fim, altere o valor da propriedade
Max para 99. Esse será o volume máximo que o componente deverá atingir. Cabe
aqui uma explicação: teoricamente, o volume máximo 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 não pode acontecer. Por isso, deixe-o com o valor de
99. Essa diferença de 1 ponto não faz diferença ao ouvido humano.
De
volta à paleta Standard, adicione ao formulário, em qualquer local, um
componente PopupMenu. Este é um menu especial, daqueles que são acionados
quando clicamos em cima de algum objeto com o botão direito do mouse. O que
queremos aqui é que, ao clicarmos com o botão direito do mouse na Listbox, surja
um menu com as opções de adicionar e remover faixas da playlist. Para isso,
clique na ListBox e busque a propriedade PopupMenu. Clique na caixa de
seleção logo à frente e escolha PopupMenu1. Pronto: a ligação
entre o nosso menu e a Listbox está feita.
Falta adicionar opções ao menu. Para isso,
clique duas vezes sobre o componente que você acabou de colocar no formulário e
digite Adicionar música e pressione ENTER. Depois, digite Remover
faixa e pressione ENTER. Você terá algo semelhante a isto:
O nosso pequeno menu já tem opções 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 formulário para entrarmos na Unit1, onde iremos iniciar a
codificação. Antes da seção Implementation, vamos declarar algumas
variáveis que serão necessárias:
Lista :
TStringList;
PLAYING : Boolean = FALSE;
Cont : Integer = 0 ;
A variável Lista, do tipo TStringList, é capaz de
armazenar uma lista de textos: é ideal para guardar nossa playlist, que nada
mais é do que uma porção 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 músicas escolhidas. A variável
PLAYING, do tipo Boolean, permite que o sistema saiba se ainda há música
em execução ou não: sempre que se pressionar o botão Play, PLAYING deverá ser
True (isto é, está em execução); sempre que se pressionar o botão Stop, ela
deverá ser False. Note que ela já foi declarada e, ao mesmo tempo,
iniciada como False, pois o aplicativo não inicia tocando música de imediato. E,
por fim, a variável Cont, que armazenará qual faixa da variável Lista
está sendo tocada. Isso é necessário para que, ao retomarmos uma música depois
de uma pausa (botão Pause), o player continue executando a mesma música, ao
invés de retornar para a primeira da lista de novo. Note também 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 começar a tocar,
inicia-se pela primeira música da Lista.
Vamos usar a variável Lista agora: no evento OnCreate
do formulário, após 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 memória primeiro para poder ser usada; por isso, usamos
TStringList.Create e atribuímos essa nova lista à variável já declarada.
Depois, verificamos se já existia previamente um arquivo texto com alguma
playlist salva anteriormente com a função FileExists. Se FileExists
for True, então carrega a lista com as músicas através da função LoadFromFile.
Note a utilização de uma função adicional:
ExtractFilePath(ParamStr(0)). Este é um meio que se tem de descobrir
onde está o executável do nosso programa. Como desejamos armazenar nosso arquivo
texto (Lista.txt) no mesmo local do executável para facilitar, usamos ParamStr
(0),
que contém todo o caminho de pastas até o nome do arquivo executável e, ao mesmo
tempo, extraímos com ExtractFilePath apenas a informação que nos
interessava: o diretório do executável.
Por fim, usamos um laço 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 função
ExtractFileName(), que extrai de uma string apenas a porção que corresponde
exatamente o nome do arquivo.
Estes procedimentos acontecem todos no evento OnCreate do
form. Vamos codificar agora a opção do menu Popup Adicionar Música. Em
seu evento OnClick, digite este código:
if
OpenDialog1.Execute
then begin
Lista.Add(OpenDialog1.FileName);
ListBox1.Items.Add(ExtractFileName(OpenDialog1.FileName));
end;
O código acima faz com que uma caixa de diálogo "Abrir Arquivo", típica
do Windows, apareça na tela para que o usuário possa escolher qual arquivo
deseja adicionar à playlist. Com o método Execute, estamos dizendo que,
se o usuário escolher um arquivo e clicar no botão abrir, o nome do arquivo será
passado à nossa Lista (através do método Add()) e também à playlist que
aparece na ListBox (através de Items.Add()), mas não sem antes remover
todo o caminho de pastas (de novo!) para que possamos exibir apenas o nome da
música.
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, típica do Windows também, e que retorna IDYES se o usuário clicar
em "Sim", e IDNO se escolher "Não":
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 música o usuário clicou, usamos uma propriedade
interessante da ListBox chamada ItemIndex. Ela armazena a posição em que
está o texto sobre o qual o mouse clicou. O que precisamos fazer depois é pedir
que esse item seja removido da lista - aliás, de ambas: da lista que armazena
todo o caminho de pastas até as músicas e também das ListBox. A linha
Lista.Delete(ListBox1.ItemIndex)
apaga o nome do arquivo que contém o caminho completo e
ListBox1.DeleteSelected
apaga o item selecionado na ListBox que, teoricamente, é o que mais
importa para o usuário, pois é o item que ele vê na tela. O que vem depois é um
complemento para evitar falhas na execução da playlist: o nosso contador Cont,
que guarda o número da música em execução, precisa também saber que a música
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 músicas na listagem - ou seja, se Cont > 0
pois, se Cont for zero, significa que não há como voltar para a música anterior:
a lista está vazia.
Os botões Play, Pause, Stop, Avançar e Voltar
Agora, vamos à melhor parte: codificar os botões 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á começar a tocar uma faixa desde o começo ou se é para continuar uma faixa
anteriormente pausada. Para isso, testamos nossa variável PLAYING: se ela
for True, indica que a faixa já estava em execução e, portanto, provavelmente
agora estava pausada, devendo continuar a partir do ponto de parada. Isso pode
ser feito com o método Resume do MediaPlayer: ele prossegue
tocando a música exatamente a partir do ponto onde ela se encontrava. É o que
faz a linha if PLAYING then
MediaPlayer1.Resume. Mas se PLAYING não era True, então não havia
música em execução, devendo começar uma desde o início.
Precisamos, então,
mostrar ao player qual é a faixa que ele deve tocar, escolhendo a atual da nossa
lista através de Lista.Strings[Cont].
Lembre-se que Cont guarda qual música da nossa lista deve ser tocada e, passando
Cont como parâmetro para nossa Lista através da propriedade Strings, pegamos o
nome do arquivo a ser executado na seqüência. 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 variável 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 canção
com Play. Além disso, o Timer deve ser habilitado com
Timer1.Enabled:=True e
nossa variável PLAYING deve passar para True, indicando ao software que
há uma faixa sendo reproduzida.
O botão de Stop é mais fácil:
if PLAYING
then begin
MediaPlayer1.Stop;
PLAYING := FALSE;
Timer1.Enabled := False;
end;
Aqui, se há faixa sendo tocada, o
MediaPlayer deve ser parado através da função Stop. Além disso,
PLAYING deve se tornar False e o Timer deve ficar desabilitado, com
Timer1.Enabled := False.
E, mais fácil ainda, é o botão de pausa:
MediaPlayer1.Pause;
Aqui, nada de duvidoso: apenas chamamos a função Pause do componente
MediaPlayer. Mas, para os botões de Avançar e Retroceder, as coisas são um pouco
diferentes. Para cada vez que clicarmos num deles, a execução da faixa atual e o
timer deverão ser parados; o MediaPlayer deve ser fechado, um novo arquivo
musical da lista deve ser atribuído a ele em sua propriedade FileName para,
então, ele ser aberto novamente e ter sua função Play chamada. Como os dois
botões precisarão da mesma funcionalidade, é melhor criarmos uma procedure
separada e depois apenas chamá-la em cada um dos eventos OnClick. Para isso,
localize o início dos códigos da sua Unit e, entre as declarações 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 função
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 variável extra que estamos usando desde que
a função foi declarada, na parte superior da Unit: a variável Valor.
Através dela, passaremos um parâmetro para a função que deverá ser 1 se
desejamos avançar uma música; -1 se quisermos retroceder uma música.
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, não execute o resto da função.
O próximo bloco de código é responsável por interromper a
execução da faixa sempre que quisermos avançar ou voltar em nossa playlist. Por
isso, precisamos parar o MediaPlayer (usando o método Stop), parar
o Timer (deixando Enabled em False) e dizer que, naquele
instante, a música que estava sendo reproduzida parou, através de
PLAYING:=False.
Depois disso, nossa variável Cont deverá "pular" de
faixa, adicionando o conteúdo da variável Valor, para saber se ela deve
buscar a próxima faixa da Lista ou a anterior. É nesse ponto que nosso programa
usará o 1 ou -1, pois um destes valores estará armazenado em
Valor. Além disso, o MediaPlayer deve ser fechado com o método
Close.
Agora, um
detalhe importante, para o qual o internauta
Flávio Bernardes, que
leu este artigo, me chamou a atenção: 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 não 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 não 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 música está na posição zero). Do mesmo modo,
se estivermos na primeira (onde Cont já é zero) e tentarmos voltar para
uma anterior, devemos, então, executar a última da lista, e Cont deverá
ser atribuído 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 número menor que zero, então não 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 atribuído ao MediaPlayer,
através 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 é, então, a nova música que está
selecionada na ListBox, através da linha ListBox1.Selected
[Cont]:=true.
Por fim, abre-se o player com a função Open e inicia-se a reprodução
novamente, com a função Play. Neste momento, o Timer é novamente
habilitado e PLAYING passa, outra vez, para True.
Com isso, já podemos codificar os botões Avançar 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 função MudaFaixa() receba o valor 1
para avançar, 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 código, 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 música do MediaPlayer; se a posição da
faixa (Position) for igual a sua largura (Length), então 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, então, o novo arquivo (com Open) e inicia-se sua reprodução
com o método Play. Note que, aqui, antes de iniciar a nova faixa, é
recomendável verificar se o arquivo contido na playlist ainda existe no disco do
computador com a função FileExists(), conforme mostrado na linha
if FileExists(Lista.Strings[Cont]) then...
Do contrário, pode-se tentar executar um MP3 que nem sequer está mais no HD e aí
teremos um erro na tela. A função FileExists() retorna True se o
arquivo existir e False se não existir. Caso o arquivo em questão não mais
exista, o if pula para o último else do bloco e adiciona mais 1
ao Cont, para tentar a faixa subseqüente - até que uma faixa presente no disco seja
encontrada. Note também 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
música da playlist (Cont := 0) caso o valor de Cont ultrapasse a
quantidade de músicas existentes na listagem (isto é, quando Cont > Lista.Count-
1,
o que significa que não há próxima música, mas que deve-se retornar ao começo).
Ao mesmo tempo, após iniciar a música, pedimos que a ListBox mostrasse qual a
faixa atualmente em execução, selecionando-a com
ListBox1.Selected[Cont] := True.
Observe também uma maneira diferente de nos referirmos ao
MediaPlayer: logo no início do código, temos with MediaPlayer1 do
begin.
Isso não é de todo necessário, mas serve para tornar mais rápida a digitação.
Sem a palavra reservada with, toda vez que nos referíssemos a um método ou
propriedade do MediaPlayer, teríamos que digitar o nome do componente:
MediaPlayer1.FileName := Lista.Strings[Cont];
MediaPlayer1.Open ;
MediaPlayer1.Play;
Englobando esta mesma porção de código em um with, basta
chamar seus métodos 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 modificação num
código já implementado: o do menu Popup Remover faixa. Volte ao seu
evento OnClick e adicione ao código 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 estratégica ao botão
Stop. Como ainda não havíamos codificado esse botão ao escrever o código
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 excluída
coincidir de ser justamente aquela que estiver em execução naquele momento, o
player irá se perder ao tentar continuar executando-a. Por isso, o melhor a
fazer é pará-lo (chamando o próprio evento OnClick do botão BtnStop)
para que o contador possa fazer os ajustes necessários e a listagem possa ser
ajustada à nova quantidade de músicas (afinal, excluir uma faixa altera a
quantidade de músicas 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 à cláusula
uses
do seu aplicativo (observe o detalhe em vermelho na figura ao lado).
Depois, entre as sessões
type e
private, digite o
seguinte:
procedure TestaVolume;
Pressione CTRL+SHIFT+C para criar o corpo dessa nova
procedure e, nela, implemente o seguinte código:
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 variável 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 condição de modificar em tempo real
o volume dos auto-falantes, usamos a função WaveOutGetDeviceCaps( ) que
armazenará as capacidades de áudio do sistema na variável WaveCaps. Se a função
retornar MMSYSERR_NOERROR significa que o
hardware de áudio está presente e não 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 alteração de volume, e igual a zero caso
contrário. Portanto, se for diferente de zero, devemos obter qual a "posição"
deste volume com a função WaveOutGetVolume. Esta função obtém um "id"
(identificador) para o dispositivo de áudio através do parâmetro WAVE_MAPPER
(que deve ser convertido para inteiro com Integer( ) para poder
ser usado) e um "ponteiro" para a variável Volume (@Volume).
O Windows trabalha muito com "ponteiros", referenciados no Delphi por
"arroba" (@).
Uma vez que os dados do volume estão armazenados na variável
Volume, precisamos "quebrar" esses dados em partes para poder atribuir o
valor correto à propriedade Position da TrackBar. A variável
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ó número
várias informações. Por exemplo, a variável Volume contém, na verdade,
informações 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 razão,
quebra-se a informação com LoWord(), para obtermos apenas uma parte dela.
Depois, divide-se o valor obtido por $FFFF (que é 65.535 em hexadecimal).
A função Trunc() serve apenas para "truncar" o resultado da divisão,
garantindo que tenhamos um número inteiro como resposta. Ao final, a
linha Position := 100 - Trunc(LoWord(Volume) / $FFFF
* 100) atribui, em
percentuais, a posição correta do volume do sistema naquele instante.
Agora, precisamos criar a função que nos permitirá modificar
o volume. Para isso, entre as sessões 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 são simples: apenas capturam a
posição da TrackBar e atribuem, em percentuais, ao volume dos alto-falantes
esquerdo e direito. Depois, testa-se novamente se é possível alterar o volume
usando WaveOutGetDevCaps() e, em caso positivo, ajusta o novo volume com
a função WaveOutSetVolume(). Esta função também usa o parâmetro
WAVE_MAPPER, que obtém um id para o dispositivo de áudio e, depois,
"une" os dois canais obtidos em um único número inteiro longo (Longint), através
da função MakeLong().
Últimas Modificações
Uma vez criadas as funções de volume, devemos chamá-las nos
locais corretos de nossa aplicação. A função que testa o suporte à modificação
de volume deve ser chamada logo no evento OnCreate do formulário:
TestaVolume;
A função 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 três figuras JPG
de sugestão, mas você pode modificar a seu critério. Ajuste o tamanho do
componente Image para que fique quase igual às dimensões do Panel2. Depois,
ajuste as propriedades Anchors do Image, deixando todos os itens em True. Por
fim, altere a propriedade Stretch para True também. 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 cláusulas Uses. Somente assim o
componente estará apto a receber também figuras no formato JPG ou JPEG.
Melhorando o Programa
Podemos ainda acrescentar algumas outras funcionalidades ao
programa. Por exemplo, que tal uma barra de progressão 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, faça as modificações 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 padrão, que é Hora-Minuto-Segundo. Ao final do
código, se houver música em execução (isto é, quando PLAYING = true)
, então a barra de progressão (ProgressBar1) deverá ter sua
posição máxima ajustada ao tamanho (Length) da faixa e sua posição
atual igual à posição da música. Assim, sempre que a faixa do MediaPlayer
estiver em "andamento", a posição (Position) da ProgressBar deverá
acompanhá-lo.