Criando um metrônomo em Java com a IDE NetBeans
Autor: Jonas | Publicado: 2012-12-17T21:04:00-02:00

Esse é um tutorial cujo objetivo é criar um simulador de metrônomo em Java e analisar seu código fonte. Estarei utilizando como base o software criado por mim chamado JMetrônomo, lançado em 23/07/2012.

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.

&nbsp;"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;import java.util.Timer;import java.util.TimerTask;import java.io.InputStream;import java.io.FileInputStream; import java.io.File;import sun.audio.*;&nbsp;&nbsp; //classe metrônomopublic class metronomo{&nbsp;&nbsp;&nbsp; //atributos que serão enviados pelo formulário ou por outro lugar&nbsp;&nbsp;&nbsp; private int BPM;&nbsp;&nbsp;&nbsp; private int Tempos;&nbsp;&nbsp;&nbsp; private int Nota;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //atributos que serão usados apenas nessa classe&nbsp;&nbsp;&nbsp; private double sleep_timer;&nbsp;&nbsp;&nbsp; private int tempoatual;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //cria um novo objeto Timer da classe que foi importada importado&nbsp;&nbsp;&nbsp; Timer timer = new Timer();&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //Construtor que 'pede' parâmetros&nbsp;&nbsp;&nbsp; public metronomo(int BPM, int Tempos, int Nota) {&nbsp;&nbsp;&nbsp; setBPM(BPM);&nbsp;&nbsp;&nbsp; setTempos(Tempos);&nbsp;&nbsp;&nbsp; setNota(Nota);&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //Métodos GET e SET&nbsp;&nbsp;&nbsp; public int getBPM() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return BPM;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void setBPM(int BPM) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.BPM = BPM;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public int getTempos() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Tempos;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public void setTempos(int Tempos) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Tempos = Tempos;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public int getNota() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Nota;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public void setNota(int Nota) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Nota = Nota;&nbsp;&nbsp;&nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; public double getSleep_timer() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return sleep_timer;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public void setSleep_timer(double sleep_timer) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.sleep_timer = sleep_timer;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public int getTempoatual() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return tempoatual;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; public void setTempoatual(int tempoatual) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.tempoatual = tempoatual;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //fim dos métodos GET e SET&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //método principal que será usado para iniciar o metrônomo&nbsp;&nbsp;&nbsp; public void run() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //fórmula usada para transformar as Batidas por Minuto em um número compatível com o timer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setSleep_timer( 1.0 / getBPM() * 60000.0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //iniciando o timer pela classe BEEP, que executará o som a cada intervalo de tempo definido no comando acima &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.schedule(new beep(), 0, (long) getSleep_timer());&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //classe do beep&nbsp;&nbsp;&nbsp; public class beep extends TimerTask {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //se a variável tempoatual for 0, some um tempo (começa no 1º) e termine o método&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (getTempoatual() == 0) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTempoatual(getTempoatual() + 1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // se for o primeiro tempo, o beep será forte, caso o contrário, fraco&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (getTempoatual() == 1) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //chama o método do beep forte(ver abaixo)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BeepForte();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //chama o método do beep fraco(ver abaixo)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BeepFraco();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //se o tempo atual atingir a quantidade de tempos de compasso definida pelo usuário, é zerado o compasso&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tempoatual == getTempos()) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // zerando o tempo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTempoatual(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // avancar um tempo&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; setTempoatual(getTempoatual() + 1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; //método para terminar a execução do programa, simplismente cancela o timer declarado no início e ligado no método run()&nbsp;&nbsp;&nbsp; public void encerrar() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.cancel();&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //método do beep forte&nbsp;&nbsp;&nbsp; public void BeepForte() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //comandos necessários para tocar o som presente no arquivo 'beepforte.wav'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //obs: acho que este arquivo fica fora do pacote .jar, o que está dentro não consegui executar ainda.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File diretorio = new File("beepforte.wav");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream in = new FileInputStream(diretorio);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AudioStream as = new AudioStream(in);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AudioPlayer.player.start(as);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(java.io.IOException e) { System.out.println(e); }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void BeepFraco() {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //comandos necessários para tocar o som presente no arquivo 'beepfraco.wav'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //obs: acho que este arquivo fica fora do pacote .jar, o que está dentro não consegui executar ainda.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File diretorio = new File("beepfraco.wav");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream in = new FileInputStream(diretorio);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AudioStream as = new AudioStream(in);&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AudioPlayer.player.start(as);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(java.io.IOException e) { System.out.println(e); }&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; }
Fazendo uma rápida leitura, 'metronomo' é uma classe que têm como atributos:

 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.

O método construtor pede BPM, Tempos e Nota. Isso significa que você só poderá criar um objeto da classe 'metronomo' se passar esses atributos. Faz sentido, pois para iniciar o metrônomo precisaremos deles.

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&nbsp; 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().

&nbsp;*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:&nbsp;

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.

Vale lembrar que o timer criado funciona como um loop: é executado várias vezes e só para quando alcançar uma determinada condição. Nesse caso, só irá parar quando for executado o método encerrar().

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 {&nbsp;&nbsp;&nbsp; metronomo metro;&nbsp;&nbsp;&nbsp; int rodando = 0;

// ........
Botão Iniciar:

private void btnIniciarActionPerformed(java.awt.event.ActionEvent evt) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //'declarando' variáveis e lendo-as&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int bpm;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nota;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int tempos;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //se o radio button estiver selecionado para selecionar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rdbSelecionar.isSelected()) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bpm = slideVelo.getValue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //se estiver selecionado para especificar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bpm = Integer.parseInt(txtVelocidade.getText());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //lendo os tempos e a nota&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tempos = Integer.parseInt( (String) cboTempos.getSelectedItem());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nota = Integer.parseInt( (String) cboNota.getSelectedItem());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rodando == 1) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metro.encerrar();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metro = new metronomo(bpm, tempos,nota);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metro.run();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rodando = 1;&nbsp;&nbsp;&nbsp; }&nbsp;
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).

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,&nbsp; 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) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rodando == 1) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metro.encerrar();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rodando = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; } 
Simplismente: se estiver rodando, chame o método encerrar do objeto metro.

slideVeloStateChanged:

private void slideVeloStateChanged(javax.swing.event.ChangeEvent evt) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // atualizando lblvelocidade
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lblVelocidade.setText(Integer.toString(slideVelo.getValue()));
&nbsp;&nbsp;&nbsp; }
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.

Botão Página na Web:

private void btnWebActionPerformed(java.awt.event.ActionEvent evt) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO add your handling code here:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Desktop d = Desktop.getDesktop();&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d.browse( new URI( "http://www.jonasweb.orgfree.com/softwares" ) );&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch ( IOException e ) {&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch ( URISyntaxException e ) {&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; 
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
Este código abre a página indicada no navegador padrão. &nbsp; 

Botão Sair:

&nbsp;private void btnSairActionPerformed(java.awt.event.ActionEvent evt) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.exit(0);
&nbsp;&nbsp;&nbsp; }
System.exit(0) fecha todo o software.

Botão Sobre:

private void btnSobreActionPerformed(java.awt.event.ActionEvent evt) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOptionPane.showMessageDialog(rootPane, "JMetrônomo versão 0.9 BETA. \n"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + "Desenvolvido por Jonas Oliveira Francisco em 23/07/2012. \n"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + "Visite a página na web para mais informações");
&nbsp;}&nbsp;&nbsp;&nbsp; 
Exibe uma JOptionPane com meu texto.

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.