AudioKit e síntese de áudio no iOS / OSX



O AudioKit é uma estrutura de áudio desenvolvida por engenheiros de áudio, programadores e músicos especificamente para iOS e OSX. Ele fornece ferramentas para processar e sintetizar som. Sob o capô, há uma mistura de Swift, Objective-C, C ++ e C e a API de unidade de áudio da Apple. Tecnologias impressionantes (e bastante sofisticadas) estão envolvidas em uma API Swift muito amigável, que pode ser acessada diretamente do Xcode Playgrounds!

Neste tutorial, faremos uma jornada pelo AudioKit, além da história da síntese sonora. Você aprenderá o básico da física do som e como funcionaram os primeiros sintetizadores como o Hammond Organ. Além disso, técnicas modernas, por exemplo, amostragem, serão consideradas.

Faça a sua bebida favorita, sente-se e vá!

Primeiro passo


A partir do AudioKit 3.6, a configuração de playgrounds para trabalhar com a estrutura tornou-se bastante simples. Faça o download e descompacte a lista de reprodução inicial aqui .

A jornada começa com algumas etapas para configurar os playgrounds para trabalhar com o AudioKit.

Abra o arquivo AudioKitPlaygrounds.xcodeproj no Xcode. Clique no botão + no canto inferior esquerdo da tela, selecione Arquivo ... e, em branco, na seção Playground , salve o novo arquivo na pasta Playgrounds, juntamente com os playgrounds de demonstração.

O playground recém-adicionado será iniciado e terá a seguinte aparência:


Substitua o código gerado pelo seguinte:

import AudioKitPlaygrounds import AudioKit let oscillator = AKOscillator()  AudioKit.output = oscillator try AudioKit.start() oscillator.start() sleep(10) 

O playground não será iniciado até que você monta pelo menos uma vez o projeto. Para isso, você pode usar o item de menu Produto / Construção ou a combinação de teclas ⌘-B . Depois disso, execute o playground novamente e ouça um zumbido por 10 segundos. (Nota do tradutor: às vezes o erro não desaparece e você precisa mudar para outro playground e voltar para fazê-lo funcionar). Você pode usar o botão Reproduzir / Parar no canto inferior esquerdo da janela de reprodução para interromper ou reiniciar a reprodução.
Nota: Se você ainda encontrar erros, tente reiniciar o Xcode. Infelizmente, estruturas e playgrounds não são muito bons amigos entre si e podem se comportar de forma imprevisível.

Osciladores e física do som


A humanidade toca música através de vários objetos físicos há milhares de anos. Muitos de nossos instrumentos habituais, como guitarras ou bateria, têm centenas de anos. A primeira experiência registrada do uso de circuitos eletrônicos para gerar som foi realizada em 1874 por Elias Gray. Eliseu trabalhou no campo das telecomunicações e inventou o oscilador - o mais simples dos sintetizadores musicais. Com ele, começaremos nosso mergulho.

Clique com o botão direito do mouse no seu playground, selecione Nova Página do Playground e substitua o código gerado pelo seguinte:

 import AudioKitPlaygrounds import AudioKit import PlaygroundSupport // 1. Create an oscillator let oscillator = AKOscillator() // 2. Start the AudioKit 'engine' AudioKit.output = oscillator try AudioKit.start() // 3. Start the oscillator oscillator.start() PlaygroundPage.current.needsIndefiniteExecution = true 

O playground começará a gerar um burburinho contínuo - como pretendido. Você pode clicar em parar para pará-lo.

É quase o mesmo que fizemos no playground anterior, mas desta vez vamos nos aprofundar nos detalhes.

Considere todas as etapas em ordem:

  1. Aqui criamos um oscilador. O oscilador é o sucessor do AKNode . Os nós são os elementos que compõem uma cadeia de áudio que gera e modifica o som.
  2. Aqui, conectamos a saída do nosso último nó ao mecanismo AudioKit. No nosso caso, apenas um nó. Além disso, a estrutura direcionará a saída do nó para o dispositivo de reprodução de áudio.
  3. Bem, começamos o oscilador, na saída ele começa a enviar uma onda sonora.

O oscilador gera um sinal repetido que não para. Neste manual, o AKOscillator gera uma onda senoidal. Usando o AudioKit, um sinal digital de onda senoidal é enviado para alto-falantes ou fones de ouvido. Como resultado, ouvimos um som que oscila na mesma frequência que a onda senoidal que geramos. Essa onda senoidal não soa muito musical.



Dois parâmetros são responsáveis ​​pelo som deste oscilador: amplitude - a altura da onda senoidal, determina o volume e a frequência do som - a altura do som depende disso.

No playground, adicione as seguintes linhas de código logo após a criação do oscilador:

 oscillator.frequency = 300 oscillator.amplitude = 0.5 

O som mudou, agora soa duas vezes mais baixo e muito mais baixo. A frequência do sinal é medida em hertz (número de repetições por segundo) e determina o tom da nota. A amplitude (amplitude) é definida de 0 a 1 e é responsável pelo volume.

A invenção de Elijah Gray foi registrada na primeira patente de um instrumento musical eletrônico.



Muitos anos depois, Leo Theremin inventou um instrumento musical levemente estranho usado até hoje - o theremin. No theremin, você pode alterar a frequência do som com os movimentos das mãos acima do instrumento. Para entender como o Theremin soa, você pode ouvir as vibrações dos Beach Boys, o som do Theremin não é nada para ser confundido.

Você pode simular o som do thereminvox, para isso, adicione o seguinte código às configurações do oscilador:

 oscillator.rampDuration = 0.2 

E substitua a linha que inicia o AudioKit ( try AudioKit.start() ) pelo seguinte:

 let performance = AKPeriodicFunction(every: 0.5) { oscillator.frequency = oscillator.frequency == 500 ? 100 : 500 } try AudioKit.start(withPeriodicFunctions: performance) performance.start() 

A propriedade rampDuration permite que o oscilador altere suavemente os valores de seus parâmetros (por exemplo, frequência ou amplitude). AKPeriodicFunction é um utilitário útil do AudioKit para execução periódica de código. No nosso exemplo, ele altera a frequência da onda senoidal de 500Hz para 100Hz a cada 0,5 segundos.

Parabéns! Você acabou de fazer seu primeiro theremin. Um oscilador simples pode gerar notas musicais, mas não soa muito agradável. Existem muitos fatores que afetam o som de instrumentos físicos, como o piano, por exemplo. E ainda consideraremos alguns deles.

Envelopes de som


Quando um instrumento musical toca uma nota, o volume do som muda com o tempo e a natureza das alterações varia de instrumento para instrumento. Um modelo que pode simular esse efeito é chamado de envelope ADSR (Attack-Decay-Sustain-Release) (Nota: os sintetizadores disponíveis para compra nunca são localizados, portanto o nome da curva é o mesmo que pode ser visto no painel deste sintetizador).



O envelope ADSR consiste em:

  • Ataque : ataque ou tempo em que o som atinge seu volume máximo.
  • Decadência : selvagem ou tempo durante o qual o volume cai do máximo para o principal
  • Sustentar : o volume principal, diferentemente dos dois parâmetros anteriores, não é o tempo, após o ataque e os selvagens passarem e antes de você soltar a tecla do sintetizador, o som será gerado com este volume
  • Liberação : liberação ou hora em que o volume se torna zero

No piano, o som é extraído por martelos batendo nas cordas e, portanto, é rápido ou, dizem eles, ataques curtos e violentos. O violino pode ter um ataque longo, selvagem e sustentado, o músico pode influenciar esses parâmetros pela maneira como usa o arco.

Um dos primeiros instrumentos musicais eletrônicos foi Hammond Novachord. Este instrumento foi fabricado em 1939, consistia em 163 tubos de vácuo e mais de 1000 capacitores, e pesava 230 kg. Infelizmente, apenas algumas centenas de cópias foram feitas e ele nunca recebeu sucesso comercial.



Clique com o botão direito do mouse no Journey Playground , selecione New Playground Page e crie uma nova página chamada ADSR . Substitua o código gerado pelo seguinte:

 import AudioKitPlaygrounds import AudioKit import PlaygroundSupport          let oscillator = AKOscillator() 

Simplesmente cria um oscilador com o qual já estamos familiarizados. Em seguida, adicione o seguinte código no final do playground:

 let envelope = AKAmplitudeEnvelope(oscillator) envelope.attackDuration = 0.01 envelope.decayDuration = 0.1 envelope.sustainLevel = 0.1 envelope.releaseDuration = 0.3 

Isso cria um AKAmplitudeEnvelope que define o envelope ADSR. Os parâmetros de duração (attackDuration, decayDuration, releaseDuration) são especificados em segundos e o volume (sustainLevel) é definido no intervalo de 0 a 1.

AKAmplitudeEnvelope é o sucessor do AKNode da mesma maneira que o AKOscillator código acima, passamos os nós do envelope do oscilador para o inicializador, conectando assim os nós.

Em seguida, adicione o seguinte código:

 AudioKit.output = envelope let performance = AKPeriodicFunction(every: 0.5) { if (envelope.isStarted) { envelope.stop() } else { envelope.start() } } try AudioKit.start(withPeriodicFunctions: performance) performance.start() oscillator.start() PlaygroundPage.current.needsIndefiniteExecution = true 

Ele iniciará o AudioKit, mas desta vez alimentamos a saída do nó ADSR para sua entrada. Para ouvir o efeito ADSR, AKPeriodicFunction e desativamos constantemente o nó usando o AKPeriodicFunction .



Agora você pode ouvir como a nota é tocada em ciclos, mas desta vez é mais como um piano.

O loop é executado duas vezes por segundo em cada iteração, iniciando ou parando o ADSR. Quando o ADSR começa com um ataque rápido, o volume atinge seu valor máximo em 0,01 segundo, após o qual o volume diminui em 0,1 segundos para o nível principal e permanece lá por 0,5 segundos e, finalmente, decai em 0,3 segundos.

Você pode tocar os parâmetros você mesmo e tentar tocar, por exemplo, o som de um violino.

Os sons que conhecemos são baseados na onda senoidal que o AKOscillator gera. Embora o ASDR ajude a suavizar sons severos, você ainda não pode chamar esses sons de musicais.

Além disso, consideraremos como obter um som mais profundo.

Síntese aditiva


Cada instrumento musical tem seu próprio som ou timbre especial. Um timbre é o que distingue um piano de um violino, mesmo que eles possam tocar a mesma nota. Um parâmetro importante do timbre é o espectro sonoro. O espectro sonoro descreve a faixa de frequências reproduzidas que, quando somadas, dão uma nota. Nosso playground atual usa um oscilador que soa apenas em uma frequência e soa bastante artificial.

Você pode obter um som mais animado usando um conjunto de osciladores para tocar uma única nota. Essa abordagem é conhecida como síntese aditiva, e este é o tópico do nosso próximo playground.

Clique com o botão direito do mouse no playground, selecione Nova Página de Playground e crie uma nova página chamada Síntese Aditiva . Substitua o código gerado pelo seguinte:

 import AudioKitPlaygrounds import AudioKit import AudioKitUI import PlaygroundSupport func createAndStartOscillator(frequency: Double) -> AKOscillator { let oscillator = AKOscillator() oscillator.frequency = frequency return oscillator } 

Para síntese aditiva, você precisa de vários osciladores, para isso usaremos. createAndStartOscillator

Em seguida, adicione o código:

 let frequencies = (1...5).map { $0 * 261.63 } 

Aqui tomamos um intervalo de números de 1 a 5 e multiplicamos cada um por 261,53, a frequência da nota. As múltiplas frequências resultantes são chamadas de harmônicas.

Agora adicione o código:

 let oscillators = frequencies.map { createAndStartOscillator(frequency: $0) } 

Aqui criamos um oscilador para cada uma das frequências que usamos.

Para combinar osciladores, adicione o seguinte código:

 let mixer = AKMixer() oscillators.forEach { $0.connect(to: mixer) } 

AKMixer é outro tipo de nó do AudioKit. Ele recebe entrada de um ou mais nós e os combina em um.

Adicione o seguinte código:

 let envelope = AKAmplitudeEnvelope(mixer) envelope.attackDuration = 0.01 envelope.decayDuration = 0.1 envelope.sustainLevel = 0.1 envelope.releaseDuration = 0.3 AudioKit.output = envelope let performance = AKPeriodicFunction(every: 0.5) { if (envelope.isStarted) { envelope.stop() } else { envelope.start() } } try AudioKit.start(withPeriodicFunctions: performance) performance.start() oscillators.forEach { $0.start() } 

Tudo deve ficar claro com este código: adicione ADSR à saída do mixer, faça a saída via AudioKit e ligue / desligue periodicamente.

Para lidar bem com a síntese aditiva, será útil tocar com várias combinações dessas frequências. E nisso, a oportunidade de playgrounds como o Live View é ideal para nós.

Para fazer isso, adicione o código:

 class LiveView: AKLiveViewController { override func viewDidLoad() { addTitle("Harmonics") oscillators.forEach { oscillator in let harmonicSlider = AKSlider( property: "\(oscillator.frequency) Hz", value: oscillator.amplitude ) { amplitude in oscillator.amplitude = amplitude } addView(harmonicSlider) } } } PlaygroundPage.current.needsIndefiniteExecution = true PlaygroundPage.current.liveView = LiveView() 

No AudioKit, existem aulas especificamente para trabalhos convenientes em playgrounds. No nosso exemplo, usamos o AKLiveViewController , e colocamos elementos verticalmente. E também para cada oscilador, criamos um AKSlider . Os controles deslizantes são inicializados pelos valores da frequência e amplitude dos osciladores e causam um bloqueio ao interagir com eles. No bloco de cada controle deslizante, alteramos a amplitude do oscilador correspondente. Assim, você pode adicionar interatividade aos seus playgrounds.

Para ver os resultados do playground, você precisa ter o Live View exibido na tela. Para fazer isso, selecione o botão com círculos que se cruzam na parte superior direita da janela e verifique se a lista de reprodução correta está selecionada para a Exibição ao vivo.



Para alterar o tom do seu instrumento, você pode alterar os valores de cada controle deslizante individualmente. Para um som realista, sugiro que tente a configuração mostrada na captura de tela acima.

Um dos primeiros sintetizadores a usar síntese aditiva foi o teleharmonium e pesava 200 toneladas! Seu incrível peso e tamanho, provavelmente, se tornou o motivo de sua obscuridade. O órgão Hammond, mais bem-sucedido, usava rodas de tom semelhantes, mas era muito menor. Inventado em 1935, ainda é amplamente conhecido como um instrumento popular na era do rock progressivo.



A roda de tom é um disco rotativo com pequenas cavidades ao longo da borda e um captador localizado próximo à borda. O órgão Hammond tinha um conjunto de rodas de tom que podiam girar em velocidades diferentes. Uma maneira bastante incomum de gerar som é mais eletromecânica do que eletrônica.

Para gerar um espectro sonoro mais realista, existem várias outras técnicas: modulação de frequência (Modulação de Frequência ou FM) e modulação de largura de pulso (Modulação de Largura de Pulso ou PWM), ambas as técnicas estão disponíveis no AudioKit nas AKPWMOscillator e AKPWMOscillator respectivamente. Eu sugiro que você tente os dois, substituindo-os em vez do AKOscillator , que usamos anteriormente.

Polifonia


Na década de 1970, o movimento começou de sintetizadores modulares, consistindo em osciladores e filtros de envelope separados, para microprocessadores. Em vez de usar circuitos analógicos, o som começou a ser gerado em formato digital. Isso tornou os sintetizadores mais baratos e compactos, e os sintetizadores de marcas como Yamaha muito populares.



Todos os nossos playgrounds estavam limitados a tocar uma nota de cada vez. Muitos instrumentos são capazes de tocar mais de uma nota por vez; são chamados de polifônicos . Instrumentos que podem tocar apenas uma nota são chamados monofônicos .

Para obter um som polifônico, você pode criar vários osciladores e enviá-los para o mixer, mas no AudioKit há uma maneira mais adequada para isso.

Crie uma nova página no playground e chame-a de Polyphony. Substitua o código gerado pelo seguinte:

 import AudioKitPlaygrounds import AudioKit import AudioKitUI import PlaygroundSupport let bank = AKOscillatorBank() AudioKit.output = bank try AudioKit.start() 

Aqui criamos o banco de osciladores AKOscillatorBank . Se você for para a declaração de classe, poderá descobrir que é o herdeiro do AKPolyphonicNode , que, por sua vez, é o herdeiro do AKNode já conhecido por nós e também implementa o protocolo AKPolyphonic .

Como resultado, o banco de osciladores é o mesmo nó do AudioKit que analisamos anteriormente. Sua saída pode ser enviada para misturadores, envelopes ou quaisquer outros filtros e efeitos. O protocolo AKPolyphonic descreve como tocar notas em uma nota polifônica; vamos considerá-lo em mais detalhes.

Para testar nosso oscilador, precisamos de uma maneira de tocar várias notas ao mesmo tempo. Isso não é nada difícil!

Adicione o seguinte código à lista de reprodução e verifique se a Exibição ao vivo está aberta:

 class LiveView: AKLiveViewController, AKKeyboardDelegate { override func viewDidLoad() { let keyboard = AKKeyboardView(width: 440, height: 100) addView(keyboard) } } PlaygroundPage.current.liveView = LiveView() PlaygroundPage.current.needsIndefiniteExecution = true 

Quando o playground compilar, você verá o seguinte:



Legal, né? O teclado musical fica bem no parquinho!

AKKeyboardView é outro utilitário do AudioKit que facilita a exploração das possibilidades da estrutura. Pressione as teclas e você descobrirá que elas não estão emitindo nenhum som.

Atualize a setUp seu PlaygroundView com o seguinte:

 let keyboard = AKKeyboardView(width: 440, height: 100) keyboard.delegate = self addView(keyboard) 

Isso tornará o nosso PlaygroundView um delegado do teclado e permitirá que você responda às teclas digitadas.

Atualize a declaração de classe da seguinte maneira:

 class LiveView: AKLiveViewController, AKKeyboardDelegate 


Adicione também alguns métodos logo após o setUp :

 func noteOn(note: MIDINoteNumber) { bank.play(noteNumber: note, velocity: 80) } func noteOff(note: MIDINoteNumber) { bank.stop(noteNumber: note) } 

Cada vez que você pressiona uma tecla, o método noteOn é noteOn , tudo o que faz é dizer ao banco de osciladores para começar a tocar a nota, respectivamente, no método noteOff , a noteOff é interrompida.

Segure o mouse e deslize as teclas; você ouvirá um belo crescendo (um termo musical para um aumento gradual na potência do som). O banco de osciladores já contém um efeito ADSR embutido, como resultado, a atenuação de uma nota é misturada com o ataque da próxima e soa muito bem.

Você deve ter notado que as notas que nos deram as teclas não vieram na forma de uma frequência. Eles são declarados como MIDINoteNumber . Se você for a um anúncio desse tipo, verá o seguinte:

 public typealias MIDINoteNumber = Int 

MIDI significa Interface Digital de Instrumento Musical. Este é um formato difundido para instrumentos musicais interagirem entre si. Os números das notas correspondem às notas em um teclado musical padrão. O segundo parâmetro - essa velocidade (velocidade) corresponde à força do acerto na tecla. Quanto menor o valor, mais suave o toque na tecla, mais silencioso o som final.

No final, você precisa ativar o modo polifônico nas teclas. Adicione o seguinte código ao método setUp :

 keyboard.polyphonicMode = true 

Agora você pode tocar várias notas ao mesmo tempo, como mostra a figura:



A propósito, isso está em dó maior :)

O AudioKit começou sua história há muito tempo. Hoje, ele usa o Soundpipe e o código da Csound (um projeto do MIT que foi lançado em 1985). Surpreendentemente, o código que estamos lançando nos playgrounds e adicionando ao iPhone foi escrito há quase 30 anos.

Amostragem


As técnicas de síntese de som que exploramos anteriormente tentam recriar som realista usando blocos básicos simples: osciladores, filtros e mixers. No início da década de 1970, o desenvolvimento das capacidades do computador levou ao surgimento de uma nova abordagem - a amostragem de som, cujo objetivo é criar uma cópia digital do som.

A amostragem é uma tecnologia bastante simples, semelhante à fotografia digital. Durante a amostragem em intervalos regulares, a amplitude das ondas sonoras é registrada:



Dois parâmetros afetam a precisão com que o som foi gravado:

  • Profundidade de bits : ou profundidade de bits, o número de níveis de volume individuais que o amostrador pode reproduzir
  • Taxa de amostragem : ou taxa de amostragem, indica com que frequência as medidas de amplitude são realizadas. Medido em hertz.

Vamos explorar essas propriedades em um novo playground. Crie uma nova página e nomeie-a como "Amostras". Substitua o código gerado pelo seguinte:

 import AudioKitPlaygrounds import AudioKit import PlaygroundSupport let file = try AKAudioFile(readFileName: "climax-disco-part2.wav", baseDir: .resources) let player = try AKAudioPlayer(file: file) player.looping = true 

O código acima carrega a amostra, cria um reprodutor de áudio e o reproduz sem fim.

Um arquivo com um arquivo WAV para este tutorial está disponível aqui . Faça o download e descompacte na pasta Resources do seu playground.

Em seguida, adicione o seguinte código no final do playground:

 AudioKit.output = player try AudioKit.start() player.play() PlaygroundPage.current.needsIndefiniteExecution = true 

Isso conectará seu reprodutor de áudio ao AudioKit, você só precisa aumentar o volume e aproveitar!

, .

MP3-, , , . :

 let bitcrusher = AKBitCrusher(player) bitcrusher.bitDepth = 16 bitcrusher.sampleRate = 40000 

AudioKit:

 AudioKit.output = bitcrusher 

. , .

AKBitCrusher — AudioKit, . , , ZX Spectrum BBC Micro. , .

, (. delay). , AKBitCrusher . :

 let delay = AKDelay(player) delay.time = 0.1 delay.dryWetMix = 1 

0.1 . dryWetMix . 1 , .

:

 let leftPan = AKPanner(player, pan: -1) let rightPan = AKPanner(delay, pan: 1) 

AKPanner , - . .

AudioKit. , AKBitCrusher AudioKit :

 let mix = AKMixer(leftPan, rightPan) AudioKit.output = mix 

, , .



O que vem a seguir?


AudioKit. , -, , , . , , .

.

Source: https://habr.com/ru/post/pt440226/


All Articles