terça-feira, 13 de março de 2012

Manipulando música e sons no Android

Hoje aprenderemos algo muito simples: como fazer um dispositivo Android tocar uma música ou fazer algum som. Iremos utilizar 2 classes nativas do Android: MediaPlayer e SoundPool. Basicamente falando, MediaPlayer é utilizado para tocar músicas (videos também, mas não será tratado aqui), ou seja, arquivos de "grande" duração que não serão manipulados constantemente, enquanto que SoundPool é utilizado para tocar pequenos sons, de maneira mais ativa, como os sons de jogos, por exemplo.


Para utilizar o MediaPlayer basta fazer uma chamada ao método estático create, passando como parâmetros o Context e o id do recurso de som ou a Uri do arquivo de som. Por exemplo:


MediaPlayer musica = MediaPlayer.create(this, R.raw.minha_musica);
musica.start();
Pronto, sua música será tocada. Simples não? E com a referência ao objeto musica você pode manipula-la como quiser, pausando-a, parando-a, definindo loop, volume, pulando para um dado tempo, etc. Mas fique atento pois o MediaPlayer trabalha como uma máquina de estados, assim ele não está sempre pronto para qualquer operação. Veja aqui mais informações sobre isso.

Já o SoundPool funciona como uma mesa de som. Primeiro se cria a "mesa" através do construtor passando como parâmetros: a quantidade máxima de sons que pode ser tocados ao mesmo tempo, o tipo de audio, e a qualidade (atualmente sem efeito). Por exemplo: 
SoundPool sound = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
Com a "mesa" criada, vamos carregar os sons que serão utilizados através do comando load que recebe como parâmetros o arquivo de som (pode ser recurso, AssetFileDescriptor, um path, etc..) e a prioridade (que atualmente não tem efeito), e retorna um inteiro que é o id daquele som. Por exemplo:
int soundIDtiro = sound.load(this, R.raw.som_tiro, 1);
Importante: SoundPool não carrega arquivos com mais de 1 MB, apesar desta limitação não ser mencionada nas referencias, empiricamente nunca consegui carregar sons maiores que 1 MB. Talvez em versões posteriores isso seja possível.

Você pode carregar quantos sons quiser, desde que guarde o soundID associado, e eles estarão carregados na memória prontos para uso. Se em algum momento no futuro você não for mais utilizar um som, descarregue-o através do unload, passando o soundID como parâmetro.

Para tocar os sons basta executar o método play, passando como parâmetros: o soundID, o volume esquerdo e direito (float variando de 0.0 a 1.0), a prioridade (int, 0 = menor prioridade, usada caso o número de sons exceda o especificado na criação do SoundPool, e caso aconteça o de menor prioridade é parado), o loop (int, -1 = loop infinito, 0 = sem loop, 1 >= numéro de repetições), e o rate (float, entre 0.5 e 2.0, indica a velocidade, 1.0 = velocidade normal). Como retorno temos um int que é um streamID associado ao som tocado agora. Por exemplo:
int streamIDtiro = sound.play(soundIDtiro, 1f, 1f, 0, 0, 1f);
Com o streamID é possível manipular o som que está sendo tocado, parando-o, mudando o loop, o rate e/ou a prioridade. Entretanto, no caso geral, você não precisará se preocupar com o streamID, e nem ao menos precisará guarda-lo quando der um play.

Quando não precisar mais usar os sons você deve fazer a chamada do método release() que irá liberar todos os sons carregados da memória, e em seguida setar a referência do SoundPool para null. Por exemplo:
sound.release();
sound = null;
Se precisar usar sons novamente crie um novo SoundPool.

Por hoje é só. Lembrando que qualquer dúvida é só perguntar, cometários e e-mail estão aí para isso. =]

12 comentários:

Felipe Albertti at 1 de maio de 2012 22:01 disse...

Boa Noite Gustavo, descobri seu blog baixando suas apps para meu Tablet, está show parabéns. Em relação a minha duvida é o seguinte: Estou tentando desenvolver uma APP que transmita minha WEB RÁDIO, busquei alternativas na internet, consegui montar uma app para inserir a URL da rádio ou do arquivo MP3 e tocar. Porem, o Mp3 toca, mas a web rádio não. Como será que montamos uma app assim? Tem ideia?

Gustavo Carvalho at 2 de maio de 2012 08:33 disse...

Bom Dia Felipe, obrigado por estar usando e gostar do blog. Quanto a sua duvida eu não tenho certeza mas talvez usando o AudioTrack (http://developer.android.com/reference/android/media/AudioTrack.html) se consiga fazer isso.

Felipe Albertti at 2 de maio de 2012 11:06 disse...

Beleza, vou dar uma olhada aqui, se conseguir algo volto para passar os passos de como consegui fazer.

Henrique at 17 de outubro de 2012 22:19 disse...

Amigo, como faço para parar a aplicação enquanto ela está tocando o som?

Gustavo Carvalho at 18 de outubro de 2012 15:41 disse...

@Henrique: Parar a aplicação geralmente se utiliza o finish() se estiver numa Activity. Mas acho que você quis dizer para a música, certo? Se estiver usando MediaPlayer é só dar o comando myMediaPlayerIntance.stop() e myMediaPlayerIntance.release() se não for mais utilizar. Para parar um SoundPool use soundPoolIntance.stop(streamId).

Diego Fernandes at 21 de novembro de 2012 21:04 disse...

Ola amigo. O meu som está tocando somente em modo debug, passando linha-a-linha. Já passou por esta situação? Estou usando o SoundPool.
Obrigado pela atenção e parabéns pelo artigo.

Gustavo Carvalho at 6 de dezembro de 2012 16:10 disse...

@Diego: Muito estranho... Será que o código não está parando a música logo depois de mandar executar? Assim quando usa o debug para ir passo a passo é possível ouvir a música.

Diego Fernandes at 31 de janeiro de 2013 07:43 disse...

Desculpem a demora em voltar. Eu estava fazendo os testes com o Emulador. Quando coloquei a aplicação em vários celulares diferentes funcionou perfeitamente. Acredito ser alguma limitação do próprio emulador. Obrigado.

Anônimo at 29 de março de 2013 13:11 disse...

Cara, show de bola, execelente tutorial. Esse aqui também me ajudou http://blog.glaucocustodio.com/2013/03/29/usando-media-player-do-android-evitando-sobrecarga-de-recursos-do-sistema/

Abraços.

Jéssica Freitas at 9 de junho de 2013 16:08 disse...

Olá, parabéns pelo tutorial, ajudou muito!
Mas lá vai a minha dúvida,
como faço para o som que parou devido a prioridade menor, voltar a tocar logo após o som principal parar?

SoundPool sound = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);

int sound1 = sound.load(this, R.raw.a, 1);
int sound2 = sound.load(this, R.raw.b, 2);

sound.play(sound1, 1f, 1f, 0, 0, 1f);

quando um botão é selecionado{
sound.play(sound2, 1f, 1f, 1, 0, 1f);
}

Bem, o som 1 vai parar quando o botão for selecionado, mas como faço para ele voltar a tocar quando o som 2 parar?

Maria Tereza Blanco Strohschoen Tetê at 30 de agosto de 2013 14:11 disse...

Como eu posso fazer gerar um som? A aplicação que estou manipulando calcula a média RGB da imagem em tempo real, e gostaria de que a app falasse essa média e não só mostrasse na tela.

Anônimo at 13 de janeiro de 2016 15:05 disse...

Boa tarde. Parabéns pelo tutorial. Estou desenvolvendo um app que transforma texto em som em tempo real, o problema é que gostaria de mudar a voz de default do android para uma voz infantil, sem usar sintetizadores de voz. Será que você poderia me dar uma luz de como fazer isso? Desde já agradeço.

Postar um comentário

 
© 2011 Tutoriandroid | Recode by Ardhiansyam | Based on Android Developers Blog