Última modificação em 16/01/11
Você, provavelmente, já desejou criar seu
próprio player de áudio. E isso não é difícil, se usarmos o componente MediaPlayer
Faça o download do programa pronto. Para adicionar músicas à Playlist, cique com o botão direito sobre a área em branco e escolha "Adicionar música". |
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.
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.
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 := 0Portanto, 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.
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).
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).
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().
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.
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.
Última modificação em 16/01/11