Usaremos a versão 7 do Java Development Kit e também o NetBeans. Este último não é essencial, mas ajuda na criação de formulários e na compilação.Você pode baixar o código fonte do JMetrônomo nesse link.
É importante saber um pouco de Java e Orientação a Objetos para não ficar totalmente perdido no código, porém, creio ter deixado comentários e análises suficientes para a compreensão. Não deixe ler o tutorial se ainda não dominar o assunto, pois assim já estará estudando esse modelo de programação de maneira prática.
Para começar, vamos primeiro entender o funcionamento de um metrônomo, utilizando um texto da Wikipédia e um vídeo no Youtube.
"O metrônomo é um relógio que mede o tempo (andamento) musical. Produzindo pulsos de duração regular, ele pode ser utilizado para fins de estudo ou interpretação musical."
Fica definido que a função do metrônomo é medir o tempo musical e que existem dois tipos de metrônomo: o mecânico e o eletrônico. Seus pulsos são regulares, isto é, têm uma duração e intervalo constante. Essa informação será fundamental para a realização do nosso software, afinal, também é a base do funcionamento do metrônomo.
Um ponto importante presente no vídeo é que há batidas fortes e fracas, que dependem do tipo de compasso da música. Apesar de serem sons diferentes, eles não deixam de formar pulsos regulares.
O metrônomo que vamos criar terá duas classes básicas:
- a classe frmMetronomo do formulário, onde o usuário insere a velocidade das batidas em BPM(batidas por minuto) e a quantidade de tempos em um compasso(o primeiro tempo do compasso é o tempo forte e os outros serão tempos fracos);
- a classe metronomo, onde o computador irá simular um metrônomo de acordo com as informações fornecidas.
Formulário do JMetrônomo, criado com auxílio da ferramenta NetBeans:
Nesta janela, o usuário pode tanto selecionar a velocidade pelo slidebar como especificar na caixa de texto. Depois, ele seleciona o compasso X por X, sendo que o segundo número não altera o funcionamento do compasso, servindo apenas de referência. O usuário pode iniciar ou parar a execução do metrônomo. Há ainda botões que enviam para a minha página na internet, exibem informações sobre o software e saem do mesmo.
Ainda não vamos programar esta janela. Julgo ser melhor trabalhar primeiro a classe metronomo.
Classe metronomo:
package jmetronomo;Fazendo uma rápida leitura, 'metronomo' é uma classe que têm como atributos:
import java.util.Timer;
import java.util.TimerTask;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.File;
import sun.audio.*;
//classe metrônomo
public class metronomo{
//atributos que serão enviados pelo formulário ou por outro lugar
private int BPM;
private int Tempos;
private int Nota;
//atributos que serão usados apenas nessa classe
private double sleep_timer;
private int tempoatual;
//cria um novo objeto Timer da classe que foi importada importado
Timer timer = new Timer();
//Construtor que 'pede' parâmetros
public metronomo(int BPM, int Tempos, int Nota) {
setBPM(BPM);
setTempos(Tempos);
setNota(Nota);
}
//Métodos GET e SET
public int getBPM() {
return BPM;
}
public void setBPM(int BPM) {
this.BPM = BPM;
}
public int getTempos() {
return Tempos;
}
public void setTempos(int Tempos) {
this.Tempos = Tempos;
}
public int getNota() {
return Nota;
}
public void setNota(int Nota) {
this.Nota = Nota;
}
public double getSleep_timer() {
return sleep_timer;
}
public void setSleep_timer(double sleep_timer) {
this.sleep_timer = sleep_timer;
}
public int getTempoatual() {
return tempoatual;
}
public void setTempoatual(int tempoatual) {
this.tempoatual = tempoatual;
}
//fim dos métodos GET e SET
//método principal que será usado para iniciar o metrônomo
public void run() {
//fórmula usada para transformar as Batidas por Minuto em um número compatível com o timer
setSleep_timer( 1.0 / getBPM() * 60000.0);
//iniciando o timer pela classe BEEP, que executará o som a cada intervalo de tempo definido no comando acima
timer.schedule(new beep(), 0, (long) getSleep_timer());
}
//classe do beep
public class beep extends TimerTask {
public void run() {
//se a variável tempoatual for 0, some um tempo (começa no 1º) e termine o método
if (getTempoatual() == 0) {
setTempoatual(getTempoatual() + 1);
return;
}
// se for o primeiro tempo, o beep será forte, caso o contrário, fraco
if (getTempoatual() == 1) {
//chama o método do beep forte(ver abaixo)
BeepForte();
}
else {
//chama o método do beep fraco(ver abaixo)
BeepFraco();
}
//se o tempo atual atingir a quantidade de tempos de compasso definida pelo usuário, é zerado o compasso
if (tempoatual == getTempos()) {
// zerando o tempo
setTempoatual(0);
}
// avancar um tempo
setTempoatual(getTempoatual() + 1);
}
}
//método para terminar a execução do programa, simplismente cancela o timer declarado no início e ligado no método run()
public void encerrar() {
timer.cancel();
}
//método do beep forte
public void BeepForte() {
try{
//comandos necessários para tocar o som presente no arquivo 'beepforte.wav'
//obs: acho que este arquivo fica fora do pacote .jar, o que está dentro não consegui executar ainda.
File diretorio = new File("beepforte.wav");
InputStream in = new FileInputStream(diretorio);
AudioStream as = new AudioStream(in);
AudioPlayer.player.start(as);
}
catch(java.io.IOException e) { System.out.println(e); }
}
public void BeepFraco() {
try{
//comandos necessários para tocar o som presente no arquivo 'beepfraco.wav'
//obs: acho que este arquivo fica fora do pacote .jar, o que está dentro não consegui executar ainda.
File diretorio = new File("beepfraco.wav");
InputStream in = new FileInputStream(diretorio);
AudioStream as = new AudioStream(in);
AudioPlayer.player.start(as);
}
catch(java.io.IOException e) { System.out.println(e); }
}
}
- BPM: Velocidade em Batidas por Minuto
- Tempos: Quantidade de tempos no compasso.
- Nota: Nota equivalente ao tempo. Não tem utilidade nessa classe, ficando aberto à possíveis implementações.
- Sleep_timer: Valor que indica o intervalo de tempo entre os beeps. É gerado pela conversão do BPM.
- tempoatual: Indica em qual tempo está o compasso durante a execução.
Após o construtor, estão os métodos GET/SET. É comum na programação orientada a objetos 'encapsular' os atributos da classe dentro desses métodos. Nesse exemplo esses métodos são praticamente 'inúteis', porém, poderia usá-los para limitar a velocidade BPM e os Tempos no compasso.
Após os métodos GET/SET, temos o método run(), que começa a executar o metrônomo. Ele possui dois comandos: o primeiro, que converte BPM para o intervalo de tempo que o timer irá usar, e o segundo, que configura o timer para executar a cada intervalo de tempo o beep(presente na classe 'beep').
Sobre o timer: é um recurso presente na maioria das linguagens de programação (talvez todas, não tenho ciência) que funciona executando uma determinada tarefa a cada período de tempo. Por isso, se enquadra perfeitamente em nosso projeto. O timer nesse caso só para com o método encerrar()
A classe 'beep' está contida dentro da classe 'metronomo'. Ela extende da classe TimerTask (algo como tarefa do timer), isso quer dizer que ela é um TimerTask com algo a mais: o nosso código. Há uma sobreescrita* do método run().
*Sobreescrita é uma substituição do método original por um novo. Nesse caso, o método run() que provavelmente não faria nada, agora irá gerar nossos beeps.
Dentro do método run() temos vários comandos:
- O primeiro é uma condição que se o tempo atual for 0, ele não executa mais nada e soma um tempo. Isso acontecerá apenas na primeira passagem do método beep.
- O segundo é outra condição que se o tempo atual for 1, ele exeuta o beep forte, senão, o fraco.
- O terceiro é outra condição que se o tempo for igual à quantidade informada pelo usuário, é zerado a quantidade atual de tempos.
- O quarto comando adiciona um tempo.
Por fim, os métodos BeepForte() e BeepFraco() executam o arquivo de som correspondente. Infelizmente não consegui rodar o arquivo dentro do pacote .jar, quando for executar é necessário que os dois arquivos de som estejem fora do arquivo .jar. Caso você saiba chamar um arquivo dentro do pacote .jar por favor comente.
Voltando para o nosso formulário, vamos programar o botão Iniciar. No NetBeans basta clicar duas vezes no botão e ele prepará automaticamente o método.
Início da classe frmMetrônomo:
public class frmMetronomo extends javax.swing.JFrame {Botão Iniciar:
metronomo metro;
int rodando = 0;
// ........
private void btnIniciarActionPerformed(java.awt.event.ActionEvent evt) {A classe do formulário possui muito código gerado automaticamente pelo NetBeans. Logo após a declaração da classe, criei o objeto metro da classe metronomo (se fosse criado no método do botão iniciar, poderiam rodar vários metronomos ao mesmo tempo e também seria impossível pará-los, o que não é desejado).
//'declarando' variáveis e lendo-as
int bpm;
int nota;
int tempos;
//se o radio button estiver selecionado para selecionar
if (rdbSelecionar.isSelected()) {
bpm = slideVelo.getValue();
}
//se estiver selecionado para especificar
else {
bpm = Integer.parseInt(txtVelocidade.getText());
}
//lendo os tempos e a nota
tempos = Integer.parseInt( (String) cboTempos.getSelectedItem());
nota = Integer.parseInt( (String) cboNota.getSelectedItem());
if (rodando == 1) {
metro.encerrar();
}
metro = new metronomo(bpm, tempos,nota);
metro.run();
rodando = 1;
}
No método do botão iniciar declaramos as variáveis que iremos enviar para a nossa classe 'metronomo'. A condição que vem logo após verifica qual modo de inserção do BPM está selecionado: se é pelo slidebar ou pela caixa de texto. Após isso ele lê, convertendo se necessário. Os tempos e a nota serão retirados de um combobox, por isso o comando está grande: nele, primero o objeto é convertido para string e depois para inteiro.
Antes de executar o metrônomo, ele verica se o mesmo já está sendo executado e, se sim, para-o. Após isso ele instancia o metrônomo passando os valores recebidos no formulário. Executamos assim o método run() e a variável rodando recebe 1.
Há ainda alguns outros métodos da classe frmMetronomo:
Parar:
private void btnPararActionPerformed(java.awt.event.ActionEvent evt) {Simplismente: se estiver rodando, chame o método encerrar do objeto metro.
if (rodando == 1) {
metro.encerrar();
rodando = 0;
}
}
slideVeloStateChanged:
private void slideVeloStateChanged(javax.swing.event.ChangeEvent evt) {Esse é um evento que diz: quando o valor do slideVelo mudar, ou seja, quando o usuário arrastar o slidebar, o sistema irá atualizar o texto que está logo abaixo indicano a velocidade.
// atualizando lblvelocidade
lblVelocidade.setText(Integer.toString(slideVelo.getValue()));
}
Botão Página na Web:
private void btnWebActionPerformed(java.awt.event.ActionEvent evt) {Este código abre a página indicada no navegador padrão.
// TODO add your handling code here:
Desktop d = Desktop.getDesktop();
try {
d.browse( new URI( "http://www.jonasweb.orgfree.com/softwares" ) );
}
catch ( IOException e ) {
System.out.println(e);
}
catch ( URISyntaxException e ) {
System.out.println(e);
}
}
Botão Sair:
private void btnSairActionPerformed(java.awt.event.ActionEvent evt) {System.exit(0) fecha todo o software.
System.exit(0);
}
Botão Sobre:
private void btnSobreActionPerformed(java.awt.event.ActionEvent evt) {
JOptionPane.showMessageDialog(rootPane, "JMetrônomo versão 0.9 BETA. \n"Exibe uma JOptionPane com meu texto.
+ "Desenvolvido por Jonas Oliveira Francisco em 23/07/2012. \n"
+ "Visite a página na web para mais informações");
}
Bem, acredito que isto seja o suficiente para o nosso projeto. Após compilar e empacotar o programa, o resultado será esse:
Download
Também fiz uma versão para web, apenas criando um formulário parecido só que para web. No NetBeans basta procurar por "Form Applet" para o software rodar no navegador como se fosse um programa em flash. Neste caso, o resultado será este.
Assim termina o nosso software de metrônomo e espero que tenham não só aprendido a programar um metrônomo, mas também adquirido mais experiência com programação em java e programação orientada a objetos. Ainda sou iniciante em java e não só aceito, como peço sugestões para melhorar o software.
Detalhes finais:
- A ideia de criar o metrônomo surgiu nas aulas de VB.NET do curso de Informática. Estava testando a funcionalidade Timer e coloquei para executar um beep(). Percebi a semelhança com o metrônomo e decidi programar um em Java, pois queria conhecer mais essa linguagem de programação.
- Se fisesse em VB.NET seria muito mais fácil, mas em Java aprendi muito sobre orientação a objetos, como por exemplo na hora de criar o timer: precisei criar uma classe que extende da TimerTask e sobreescreve o método run() da mesma. Considerando também que toda a programação em Java ocorre nesse modelo de programação, foi muito útil ter criado o software nessa linguagem. É mais difícil porém aprende-se mais.
- Se alguém poder me enviar sons melhores eu aceito. Eu queria executar um som de percursão MIDI, acho que ficaria melhor nesse programa.
- Eu criei outros softwares e também alguns jogos. Basta acessar meu site.
Bom dia. Pode me passar teu email? Estou querendo fazer meu projeto de estagio baseado nessa ideia.
ResponderExcluircontato@jonasof.com.br
Excluir