Mostrando postagens com marcador sound. Mostrar todas as postagens
Mostrando postagens com marcador sound. Mostrar todas as postagens

sexta-feira, 22 de agosto de 2008

Playback de Áudio

Existem dois tipos de line que podem ser usados para tocar som: Clip e SourceDataLine. A diferença principal entre estas duas interfaces é que com um Clip você especifica todas as informações do som uma única vez antes da execução. Com um SourceDataLine, escrevemos continuamente em buffers de informação durante a execução. Embora hajam situações em que ambas as classes possam ser utilizadas, o critério seguinte ajuda a identificar que tipo de line é melhor para determinada situação:
  • Utilize um Clip quando você não tem informações de som em tempo real que podem ser pré-carregadas na memória.
    Ex.: Loops, iniciar o playback em uma posição arbitrária.
  • Utilize um SourceDataLine para stream de informações tais como um arquivo de som muito longo que não irá caber todo na memória de uma vez, ou um som cuja informações não podem ser conhecidas antes do playback.
    Ex.: síntese interativa de sons.

quinta-feira, 21 de agosto de 2008

Como recuperar um Line

Existem duas maneiras:
  1. Diretamente do objeto AudioSystem
  2. A partir de um Mixer que você já obteve de um objeto AudioSystem
Recuperando um Line diretamente de um AudioSystem
Assumindo que ainda não obtemos um mixer e é preciso recuperar um line, podemos utilizar o método static Line getLine(Line.Info info) da classe AudioSystem. A classe Line.Info usada como argumento deste método não armazena informação textual para especificar uma linha desejada, ela armazena informações da classe de linha desejada.

Line.Info é uma classe abstrata, então utilizamos uma de suas sub-classes Port.Info ou DataLine.Info para obter uma linha. O trecho de código abaixo usa a classe DataLine.Info para obter e abrir um target data line:

TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info)) {
// Handle the error.
}
// Obtain and open the line.
try {
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
} catch (LineUnavailableException ex) {
// Handle the error.
//...
}

Para portas, podemos utilizar instâncias estáticas de Port.Info:

if (AudioSystem.isLineSupported(Port.Info.MICROPHONE)) {
try {
line = (Port) AudioSystem.getLine(
Port.Info.MICROPHONE);
} catch(Exception e) { //... }
}

Lembre-se que um sourceLine é uma entrada para um mixer, especificamente, um objeto Port se o mixer representa um dispositivo de entrada de áudio e um objeto SourceDataLine ou Clip se o mixer representa um dispositivo de saída de áudio.

Podemos utilizar métodos de AudioSystem para conhecer mais sobre source e target lines de um tipo específico que é suportado por qualquer mixer instalado.

static Line.Info[] getSourceLineInfo(Line.Info info)
static Line.Info[] getTargetLineInfo(Line.Info info)

Note que o array retornado por cada um desses métodos indicam tipos únicos de linha, não necessariamente todas as linhas. Por exemplo, se duas linhas de um mixer ou duas linhas de diferentes mixers possuem objetos Line.Info idênticos, as duas linhas serão representadas por apenas um Line.Info no array.

A interface Mixer inclui variações nos métodos de acesso aos source e target lines do AudioSystem. Além dos métodos que requerem um argumento do tipo Line.Info, o Mixer também inclui métodos que não possuem argumentos:

Line.Info[] getSourceLineInfo()
Line.Info[] getTargetLineInfo()

Estes métodos retornam arrays de objetos Line.Info de um mixer específico.

Os métodos apresentados para recuperar Lines são aplicados também na recuperação de portas (Ports). Podemos abrir um porta invocando o método open da interface Line. A abertura de uma porta significa permitir que o som entre ou saia por esta porta. De maneira análoga, podemos fechar portas.

No geral, é recomendado que o programa não abra/feche portas a não ser pelo desejo explícito do usuário. Deve-se respeitar as configurações que o usuário ou o Sistema Operacional já tenha selecionado. (Imagine um usuário que se encontra em um ambiente extremamente silencioso executando um programa que abre a porta dos alto-falantes sem sua devida autorização)

Como acessar os recursos de som do seu sistema?

A API Java Sound provê maneiras de informar os componentes de áudio disponíveis no seu sistema e maneiras do seu programa acessá-los.

A classe AudioSystem

A classe AudioSystem atua como um coletor e distribuidor de informações para componentes de áudio, incluindo serviços nativos e serviços instalados separadamente por meio de providers de terceiros. Por exemplo, um programa pode ser iniciado solicitando a classe AudioSystem onde existe um mixer que possua uma certa configuração.

Alguns recursos que um programa pode obter da classe AudioSystem:

  • Mixers: um sistema geralmente possui vários mixers instalados. Existe pelo menos um para entrada de áudio e outro para saída de áudio. A classe AudioSystem provê uma lista de todos os mixers instalados.
  • Lines: como as linhas estão associadas a mixers, um programa pode recuperar uma linha diretamente da classe AudioSystem.
  • Conversões de formatos: um programa pode querer traduzir um formato de áudio em outro.
  • Arquivos e streams: a classe AudioSystem provê métodos para traduzir arquivos de áudio e streams de áudio.

Objetos de Informação

Algumas classes na API Java Sound provêem informações úteis sobre interfaces associadas. Por exemplo, Mixer.Info provê detalhes (nome do fabricante, descrição e versão) sobre um mixer instalado.


Um pouco na correria... Em breve vou postar mais informações de como utilizar a classe AudioSystem.

Até mais!

terça-feira, 12 de agosto de 2008

3 Conceitos Principais - Mixer

Muitas APIs que trabalham com som fazem uso da noção de dispositivo de áudio. Um dispositivo geralmente é uma interface de software para um dispositivo físico de entrada e saída.
Na API Java Sound, dispositivos são representados por objetos da classe Mixer. O propósito de um mixer é manipular um ou mais streams de entrada ou saída de áudio. Tipicamente, o mixer mescla múltiplos streams de entrada em um stream de saída.

Na API Java Sound, um componente tal como um microfone conectado a uma placa de som não é considerado um dispositivo (como o mixer), mas é chamado de porta (port) entrando ou saindo do mixer. Tipicamente, uma porta provê um único stream de áudio para dentro ou para fora do mixer. O Mixer pode ter vários tipos de portas. Por exemplo, um mixer que representa a capacidade de saída de uma placa de som pode misturar vários streams de áudio juntos e então enviar o sinal mixado para qualquer uma das várias portas de saída conectadas ao mixer. Estas portas de saída podem ser, por exemplo, um fone de ouvido ou um alto falante.

A imagem abaixo ajuda a compreender a noção de mixer na API Java Sound (inclusive, algumas imagens que estou colocando aqui foram tiradas do Java Sound Programmer Guide) e mostra o console de um mixer físico.Imagine um show ao vivo que está sendo gravado em modo estéreo. Cabos vindos de muitos microfones e instrumentos elétricos do palco são plugados nas entradas do aparelho de mixagem. Cada entrada possui um canal específico no mixer. O engenheiro de som decide sobre as configurações de ganho, pan, e controles de reverb. A saída de todos os canais e a unidade de reverb são mixadas juntamente em 2 canais. Estes canais vão para duas saídas no mixer por cabos que estão plugados a um gravador e que também podem ser enviados, via um amplificador, para alto-falantes.

Agora imagine um estúdio de gravação em que cada instrumento é gravado em uma trilha particular de uma fita de gravação multi-trilhas. Após instrumentos e vocais serem gravados, o engenheiro de som executa um "mixdown" para combinar todas as trilhas gravadas em uma gravação de 2 canais. Novamente o engenheiro pode decidir os valores de ganho, pan e reverb para cada trilha.

Estes 2 exemplos ilustram dois diferentes usos de um mixer:
  1. capturar múltiplos canais de entrada, combiná-los em algumas trilhas
  2. executar múltiplas trilhas enquanto as mixamos em poucas trilhas.

Na API Java Sound, um mixer pode ser usado tanto para captura de áudio quanto para playback. No primeiro caso, a origem do áudio para o mixer é fornecida por uma ou mais portas de entrada. O mixer envia o áudio capturado e mixado para um target (um objeto com um buffer onde o programa pode recuperar as informações do áudio mixado). No caso de playback, as origens de áudio do mixer são objetos contendo buffers e os targets são as portas de saída.

domingo, 10 de agosto de 2008

javax.sound.sampled

O foco do pacote javax.sound.sampled é o de playback e captura de informações de áudio. Para isso é necessário conhecer 3 conceitos fundamentais: formato de informação de áudio, line e mixer.

A tarefa principal da API Java Sound é saber como mover bytes de áudio formatados para dentro e para fora do sistema. Esta tarefa envolve a abertura dos dispositivos de entrada e saída e o gerenciamento de buffers que são preenchidos com as informações de áudio em tempo real. Também envolve a mistura de múltiplos streams de áudio em apenas um stream. O transporte de som para dentro e fora do sistema tem que ser corretamente manipulado pois é preciso contemplar as necessidades do usuário quando este solicita que o fluxo de som seja iniciado, parado, resumido ou interrompido.

Manipulação de áudio com e sem buffer
A API Java Sound manipula o transporte de áudio nas formas de streaming, com buffer e sem buffer. O termo "streaming" é usado de forma genérica para referenciar a manipulação de bytes de áudio em tempo-real. Não se refere ao envio de áudio pela Internet. Em outras palavras, um stream de áudio é um conjunto simples de bytes de áudio que chegam mais ou menos na mesma taxa de amostragem que serão manipulados.
As operações nos bytes começam antes de toda a informação chegar. No modelo de streaming, particularmente no caso de entrada, não é necessário conhecer antecipadamente o tamanho do som e quando ele irá terminar. Devemos manipular um buffer de informações por vez até que a operação seja suspendida. No caso de saída, devemos entregar os bytes de áudio para a engine de som e ela cuida de tocar cada amostra no momento correto.

sábado, 9 de agosto de 2008

Service Provider Interfaces

As "interfaces provedoras de serviço", SPIs, permitem que desenvolvedores criem novos recursos de áudio ou MIDI separadamente, de forma que estes possam ser plugados a uma implementação existente da API Java Sound. É possível implementar, por exemplo:
  • um novo mixer
  • um novo sintetizador MIDI
  • um novo parser de arquivo que possa ler ou escrever um novo tipo de arquivo de áudio ou MIDI
  • um novo conversor entre diferentes formatos de som.
Uma implementação da API Java Sound contém um conjunto básico de serviços. As SPIs permitem que terceiros criem novos serviços. As classes AudioSystem e MidiSystem atuam como coordenadores, permitindo que os programas acessem os serviços explicitamente ou implicitamente.

Bem, finalizo aqui uma parte da introdução sobre a API Java Sound. O próximo passo é explicar de forma mais aprofundada as características do Java Sound e como esta API lida com as informações de áudio. Até lá!

MIDI

MIDI, ou Musical Instrument Digital Interface, descreve uma série de eventos que afetam o som que um sintetizador produz. Os eventos podem ser interpretados como ações sobre um teclado musical ou ações em pedais, sliders, dentre outros dispositivos.

Embora grande parte das vezes estes eventos sejam acionados por um instrumento musical (o hardware), é possível também criar tais eventos via software. Além disso, este conjunto de eventos podem ser armazenados em arquivo, permitindo a posterior edição e execução do mesmo.

Um programa que possui a capacidade de criar, editar e executar estes arquivos é chamado de sequencer.

Um arquivo MIDI padrão contém trilhas (tracks), cada uma delas com uma lista de eventos MIDI. O sequencer pode enviar as mensagens MIDI para algum outro dispositivo como um sintetizador, por exemplo. O sintetizador lê um arquivo de banco de sons (soundbank) contendo instruções para emular os sons de certos instrumentos musicais e executa tais instrumentos de acordo com o evento MIDI recebido do sequencer.

A imagem abaixo exemplifica como é esse esquema:
Neste exemplo, um arquivo MIDI contendo várias trilhas com eventos MIDI é carregado. A maioria dos eventos são representados por notas musicais. O arquivo MIDI é lido e é então executado por um sequencer. O sequencer envia as mensagens MIDI para outro dispositivo tal como um sintetizador interno ou externo. O sintetizador, pode ler um banco de sons contendo as informações necessárias para emular os sons de um instrumento musical. Caso contrário as notas serão executadas usando-se qualquer som que esteja carregado no sintetizador.

Como visto, as mensagens MIDI podem ser enviadas para um sintetizador externo por meio das portas de saída. Da mesma forma, um dispositivo externo (um teclado musical) pode enviar mensagens MIDI (via portas de entrada) diretamente para um sintetizador ou para que um sequencer armazene para futura execução.

Por hoje é só. Em breve mais detalhes. Estamos apenas na introdução do basicão.

quinta-feira, 7 de agosto de 2008

Áudio Amostrado (Sampled)

Nesse post, tento explicar como é a idéia de um sinal de áudio amostrado e como a API Java Sound aborda este conceito.

Imagine uma pessoa falando ao microfone. O microfone converte o sinal acústico da voz da pessoa em um sinal elétrico analógico correspondente (este processo se dá pela captura da variação da pressão do ar que é causada pela fala da pessoa). Um conversor AD (analógico-digital) transforma então este sinal analógico para uma forma digital amostrada conforme o gráfico a seguir:

O gráfico desenha a pressão do som (amplitude) no eixo vertical e o tempo no eixo horizontal. A amplitude de uma onda sonora é medida periodicamente a uma certa taxa, resultando em amostras discretas (os pontos vermelhos do gráfico) que compreendem o sinal de áudio digital. A precisão da aproximação do sinal analógico depende de sua resolução no tempo (taxa de amostragem) e sua quantização (ou resolução em amplitude - o número de bits usados para representar cada amostra).

A API Java Sound não possui uma configuração de hardware específica. É projetada para permitir que diferentes tipos de componentes de áudio sejam instalados em um sistemas e acessados pela API.
A figura anterior mostra o exemplo de uma placa de som contendo várias portas de entradas e saídas. O mixer geralmente recebe informções de áudio de alguma fonte: arquivo, streaming de rede, sintetizador MIDI, dentre outros. O mixer combina todas as entradas de áudio em um único stream, podendo ser enviado para um dispositivo de saída.

Voilà! Lembro que isto é apenas uma introdução.

Introdução a Java Sound



Este é o primeiro de uma série de posts que serão feitos sobre a API Java Sound.

Java Sound é uma API de baixo nível utilizada para controlar a entrada e saída de som de um computador.  Tais sons podem ser tanto sinais de áudio amostrados quanto eventos MIDI (Musical Instrument Digital Interface).

Esta API possui basicamente as seguintes utilizações:
  • Frameworks de comunicação (conferência e telefonia)
  • Media players
  • Programas interativos, jogos, web com conteúdo dinâmico
  • Criação e edição de conteúdo (composição musical, por exemplo)
  • Ferramentas, toolkits e outras utilidades
Java Sound não inclui editores ou ferramentas gráficas para a sua utilização, mas provê o ferramental necessário para a construção destes programas. Como já foi dito anteriormente, esta API tem por objetivo realizar o controle de baixo nível das operações de áudio de uma máquina.

Existem outras APIs que também contém elementos relacionados ao som. A JMF - Java Media Framework - é uma API que, ao contrário da API Java Sound, é de alto nível. É uma extensão padrão da plataforma Java composta por uma arquitetura unificada, protocolo de mensagens e interface de programação para a captura e execução de mídia com base no tempo (time-based). A JMF permite a sincronização de tipos de mídias diferentes, tais como áudio e vídeo.

Os pacotes principais da API Java Sound são:
  • javax.sound.sampled: este pacote especifica interfaces para captura, mixagem e playback de áudio digital amostrado
  • javax.sound.midi: provê interfaces para síntese MIDI, sequencer e transporte de eventos
  • javax.sound.sampled.spi e javax.sound.midi.spi: permite que provedores de serviços (services providers) criem componentes de software customizados que extendem as capacidades de uma implementação da API Java Sound.

A priori, é isso. Até mais!