SchultzGames
Para tirar dúvidas, crie um tópico especifico na área "Dúvidas em Geral" e aguarde ser respondido. Evite comentar em tópicos não relacionados a sua dúvida :D
TÓPICOS RECENTES:
Tópico:
Postado em:
Postado por:
Como evitar que personagem se levante onde não há espaço suficiente?
Som falhando no Android
Resolução Nativa Fixa
Como anular uma das teclas no Unity
Botão UI que troca a cor dos objetos
Ativar um objeto quando desativar outro e vice-versa (Unity)
Objeto não continua associado
Necessário Level Designer para criar uma cidade
Como criar um Sistema de Trein na Unity.
[TUTORIAL] Agachar, correr e sistema de estamina ( C# )
FPSController travado no lugar após animações usando seu transform
OnTriggerEnter
Unity - Áudios deixam a Scene pesada pra abrir
[RESOLVIDO] URP QUE NÃO RENDERIZA. UNITY 2020.3.18 ARQUIVO DAE DO SKetchfab
Criar input mobile depois do jogo "quase pronto" vale a pena ?
Mudar a densidade da grama pelo script de outra cena
Como Pegar DesseObjeto.GetComponent<ScriptName.Boolean>
Como pausar a renderização do Blender
Como trocar todas as SpritesSheets do animator no Unity2D?
Como Fazer Espelho perfeito fácil na Unity, Apenas 4 linhas de código
[TUTORIAL] AI Enemy 2.0 + animações ( Jogos de terror )
app para aquaristas
Serializar Dictionary no Scriptable Object
Camera gira errada no eixo z ao entrar no carro!!
Referencias entre objetos pai e filho
Quem aqui tem jogos publicados no Steam?
Erro ao criar "Truck Trailer" Realisti Car Controller RCC
Unity - O jogo não roda no Celular
Reviver o Car Town EX
[TUTORIAL] Criando Menu Modular na Unity
QUAL MELHOR LOCAL OU CURSO PARA APRENDER PROGRAMAÇÃO DO 0?
Meu script de movimentação não funciona, alguém pode me ajudar?
Como faço para fazer 'Objeto' piscar Aleatoriamente
Duvida boba sobre UI
FORMAÇAO DE EQUIPE PARA GAME PARKOUR
Colisão Seletiva
Unity 2021.3.4f1 - Adicionar script em um gameObject por código
[Curso Grátis para iniciantes] Um Ótimo Lugar para aprender Unity
Erro de ArgumentNullException no WebGL da Unity
como desativar um text depois de 10 segundos?
Como eu faria o inimigo reagir a um tiro ?
player empurrando o outro
Vida do player e variaveis static
Contagem de GameObjects presentes em um Scene
Stamina/Sede - Movimentação
Pegar objeto e rotacionar
Efeito Smoke na Asa do Ace Combat
Passar informações de um script pro outro
PROCURA-SE PARCEIRO PARA LEVEL DESIGN - SIMULADOR DE COMBATE
como verificar se um objeto com um nome especifico nao esta na cena
Jogo fecha do nada
Meus jogos publicados no google play
preciso de um programador que entenda de Photon pago via Pix pela ajuda!!
Blender Faces Transparentes
Unity - Aba Game Preta no Display1. No Display2 fica normal
Duvida sobre bool na transição de animações
Tem Como Fazer um Shader com o Shader Graph que Deixa a Escala Infinita?
Câmera Com Render Texture Para HUD
[RESOLVIDO] Destroy object quando toca no chao
Inimigo Com Movimento de Ondas(ZigZag)
Movimentação para todas as direções em um jogo multiplayer online
DKG - Dynamic Kit Generator
Emissão de luz em objeto não estático.
Gerenciar carregamento de texturas
Texturas rosas ao extrair materiais do objeto, com modelo .dae
Modelador (Personagem + Roupa) com Direito a Remuneração
Pegar material especifico do objeto
ERRO AO UPAR NA GOOGLE PLAY STORE
[RESOLVIDO] Navegation Unity 3D
JOGO "CHALLENGE" FINALIZADO E DISPONÍVEL PARA BAIXAR.
[RESOLVIDO] Desativar e ativar objeto com o mesmo botão
Objetos da Unity com cores erradas.
[RESOLVIDO] Botão não está desativando pelo GetComponent
Adição de um Bone à outra Armature no Blender não funciona na Unity
Posição local do pixel de um quad
Shader Graph UI
Rotacionar objeto em apenas um eixo
[ASSET] Sistema completo de Auto Save para Editor
Criar uma aplicação tipo controle remoto bluetooth.
Easy Road 3d - Preciso de Ajuda
Alguem ai Entende de Multiplayer?
alguem pode me ajudar com essa adição de item numa lista?
APK para Android 12 não executa aplicação, Help Please
[TUTORIAL] Sprites Animados
REMOVER RESOLUÇOES
Unity > Editor > Any Android Device bugado!
Erro de Referência
terminei meu jogo, mas algo deu errado.
Erro ao iniciar jogo após a build
Posição Invertida No Multiplayer
Unity 5 - Invalid serialized file header
Character Controller Slide
Sombras desaparecem qnd o bake das luzes termina
Blender - Programa ou site que faça o Rig da face do Personagem
Meu PC deu pro mundo! e agora?
[RESOLVIDO] Player atravessa Parede mesmo com os Colliders
Movimentação 3D
[RESOLVIDO] - Blender - Erro deixa objeto Transparente
[ASSET] Criar TerrainLayer utilizando textura selecionada
Ontem à(s) 9:55 pm
Ontem à(s) 10:48 am
Ter Ago 16, 2022 7:07 pm
Ter Ago 16, 2022 2:45 am
Seg Ago 15, 2022 9:06 pm
Seg Ago 15, 2022 5:38 pm
Seg Ago 15, 2022 4:41 pm
Dom Ago 14, 2022 10:26 pm
Dom Ago 14, 2022 3:54 pm
Sab Ago 13, 2022 11:16 am
Qua Ago 10, 2022 3:13 pm
Ter Ago 09, 2022 8:26 pm
Seg Ago 08, 2022 4:00 pm
Sex Ago 05, 2022 8:48 pm
Sex Ago 05, 2022 12:39 pm
Qui Ago 04, 2022 4:18 pm
Qua Ago 03, 2022 11:36 am
Seg Ago 01, 2022 5:04 pm
Seg Ago 01, 2022 1:29 pm
Dom Jul 31, 2022 12:06 am
Sab Jul 30, 2022 11:39 pm
Sab Jul 30, 2022 11:24 am
Sab Jul 30, 2022 10:41 am
Sex Jul 29, 2022 8:46 pm
Qui Jul 28, 2022 6:02 pm
Qui Jul 28, 2022 12:44 pm
Qua Jul 27, 2022 11:39 pm
Qua Jul 27, 2022 10:04 pm
Qua Jul 27, 2022 4:41 pm
Qua Jul 27, 2022 11:01 am
Qua Jul 27, 2022 9:44 am
Ter Jul 26, 2022 4:38 pm
Ter Jul 26, 2022 4:23 pm
Seg Jul 25, 2022 9:40 pm
Seg Jul 25, 2022 6:45 pm
Dom Jul 24, 2022 4:27 pm
Sex Jul 22, 2022 8:55 pm
Sex Jul 22, 2022 4:08 pm
Sex Jul 22, 2022 12:11 pm
Sex Jul 22, 2022 11:43 am
Qui Jul 21, 2022 8:36 pm
Seg Jul 18, 2022 10:04 pm
Seg Jul 18, 2022 2:24 pm
Dom Jul 17, 2022 6:48 pm
Dom Jul 17, 2022 11:48 am
Sab Jul 16, 2022 7:02 pm
Sab Jul 16, 2022 11:21 am
Qua Jul 13, 2022 5:55 pm
Qua Jul 13, 2022 9:59 am
Ter Jul 12, 2022 11:43 pm
Sab Jul 09, 2022 4:09 pm
Sex Jul 08, 2022 10:41 pm
Sex Jul 08, 2022 10:26 pm
Sex Jul 08, 2022 7:06 am
Qui Jul 07, 2022 8:23 pm
Qui Jul 07, 2022 8:16 am
Qua Jul 06, 2022 8:48 pm
Qua Jul 06, 2022 6:03 pm
Seg Jul 04, 2022 9:30 am
Qua Jun 29, 2022 12:52 am
Ter Jun 28, 2022 7:44 pm
Ter Jun 28, 2022 4:16 pm
Dom Jun 26, 2022 6:03 pm
Sab Jun 25, 2022 3:03 pm
Qua Jun 22, 2022 6:21 pm
Qua Jun 22, 2022 1:28 am
Ter Jun 21, 2022 11:42 pm
Ter Jun 21, 2022 2:27 pm
Seg Jun 20, 2022 4:08 pm
Dom Jun 12, 2022 12:52 pm
Ter Jun 07, 2022 7:47 pm
Ter Jun 07, 2022 5:20 pm
Seg Jun 06, 2022 10:16 pm
Dom Jun 05, 2022 4:44 pm
Dom Jun 05, 2022 10:45 am
Dom Jun 05, 2022 9:59 am
Sab Jun 04, 2022 11:24 pm
Sab Jun 04, 2022 4:18 pm
Sab Jun 04, 2022 3:21 pm
Sab Jun 04, 2022 2:24 pm
Sab Jun 04, 2022 2:15 pm
Sex Jun 03, 2022 4:28 pm
Sex Jun 03, 2022 4:11 pm
Qui Jun 02, 2022 8:48 pm
Dom Maio 29, 2022 6:00 pm
Sex Maio 27, 2022 11:32 pm
Sex Maio 27, 2022 3:50 pm
Sex Maio 27, 2022 8:38 am
Qui Maio 26, 2022 6:47 pm
Ter Maio 24, 2022 4:28 pm
Ter Maio 24, 2022 11:01 am
Dom Maio 22, 2022 1:43 pm
Dom Maio 22, 2022 1:38 pm
Dom Maio 22, 2022 11:21 am
Sab Maio 21, 2022 8:01 am
Sex Maio 20, 2022 10:30 pm
Sex Maio 20, 2022 3:36 pm
Sex Maio 20, 2022 3:16 pm
Qui Maio 19, 2022 10:06 pm
dutrabr100
mama2401
juraulh
SteveRogers
AGAMENOM
eleganceu
SteveRogers
EricknhYT
NoctisDregon
Édipo
Rangel Oblivion
dutrabr100
Magnatah
marciosilva
SteveRogers
jeancvo3
dutrabr100
Alex Jun
tecnoato
Yuri Heinz
Yuri Heinz
Édipo
gabrimo
SteveRogers
Pokedlg
thales.ulisses
EricknhYT
WLCS22
fragas42
MayLeone
Magnatah
EmmaFriboi
lovuxd
Tomas Turbando
SeTk
Rangel Oblivion
dutrabr100
dutrabr100
Atho
dutrabr100
MRX
dutrabr100
Pokedlg
Nimue
dutrabr100
SpartanoLeonidas300
Eris
thiagograssi
Eris
SteveRogers
claudiano2020
claudiano2020
claudiano2020
Eris
WLCS22
Rangel Oblivion
MarcosSchultz
Eris
stratengine
MarcosSchultz
kessisdiones
gabrimo
cyborggp
MarcosSchultz
MarcosSchultz
EricknhYT
SteveRogers
SteveRogers
Mozinhas2
lauderson
BlesseD
Emerson Beaver
kessisdiones
WLCS22
gabrimo
Eris
SteveRogers
AnderGames
Diomaker
EricknhYT
claudiano2020
Pokedlg
SteveRogers
lauderson
lauderson
WLCS22
Arcebispo
JoSanInk
Rangel Oblivion
claudiano2020
erickfabio366
Rangel Oblivion
Crash Psycho
WLCS22
Callyde Jr
Pedro1saac
dutrabr100
dutrabr100
AnderGames

[TUTORIAL] BeatMapping com Unity

3 participantes

Ir para baixo

TUTORIAL [TUTORIAL] BeatMapping com Unity

Mensagem por Matrirxp Ter Dez 14, 2021 9:19 pm

Beatmapping em Tempo Real usando FFT na Unity

Olá!
Hoje vou ensinar como fazer um sistema de mapeamento de ritmo em tempo real com a Unity.

Pode ser usado para jogos de ritmo como demonstrado aqui:

Exemplo feito usando as técnicas deste artigo.

Dito isso vamos começar!

O Som

Algo muito importante na hora de se mexer com áudio e saber como ele funciona.
O som é uma vibração que caminha pelo ar e também pode caminhar por líquidos e sólidos, a forma de propagação de um som e por meio de ondas longitudinais, que são tipos de onda em que a direção de vibração não se altera sendo a mesma direção do estímulo que a produziu.

[TUTORIAL] BeatMapping com Unity Zoomda
Comparação entre uma onda longitudinal e uma transversal.

As ondas possuem alguns componentes importantes, como:

-Comprimento de onda
-Amplitude
-Frequência

A amplitude de uma onda sonora diz o quão intenso este som é, ou seja, a amplitude da onda está ligada ao volume do som.
Já a frequência de uma onda sonora diz o quão agudo ou grave um som é, desse modo podemos usá-la para identificar componentes nesse som, como notas musicais e o tom.

Transformada de Fourier

A grosso modo, a transformação de Fourier serve para mudar o modo como analisamos um sinal.
Quando olhamos para o gráfico de uma onda sonora, vemos como a amplitude se modifica ao longo do tempo, se aplicarmos uma transformada de fourier neste som teremos um gráfico da amplitude sonora em relação à frequência.
Ou seja, teremos um gráfico do volume de cada banda de frequência do som.

O unity retorna esses valores dividindo a frequência máxima do aparelho de reprodução (Para computadores esta frequência e 48 kHz) por uma potência de 2.

Desse modo, o retorno é um array de float com os valores da média do volume de cada intervalo de frequência e não o volume de todas as frequências desse som (já que gastaria muito tempo).

[TUTORIAL] BeatMapping com Unity Design-sem-nome
Retorno da amplitude das bandas de frequência.


Pegando dados do FFT

Para pegar esses dados na Unity podemos usar o  AudioSource.GetSpectrumData(a,b,c).
a = Número de samples (O potência de 2 que irá dividir o som em intervalos, quando maior mais demorado porém mais preciso o resultado será).
b = Canal de áudio, 0 para Mono, 1 para direito e 2 para o canal esquerdo.
c = Tipo de janela de banda usada, no nosso caso usaremos a FFTWindow.Blackman.
(Filtro que evita a saída de frequência entre bandas)


Desse modo podemos criar uma função para retornar uma array de float com os dados que queremos.

Primeiro crie uma script C# com o nome BeatMapping.
Para pegar os dados vamos criar uma função com o nome getSamples() onde fornecemos o audioSource da cena e o número de samples que queremos.

E no retorno vamos colocar o nosso GetSpectrumData().

Código:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BeatMapping : MonoBehaviour

{
    public AudioSource audioSource;//AudioSource da cena
    public enum samplesCountPresets { _256 = 256, _512 = 512, _1024 = 1024, _2048 = 2048 };//Preset das samples em potencia de 2
    public samplesCountPresets Samples;//Numero de samples que sera usado no FFT

    float[] getSamples(AudioSource audioSource, int samplesCount)
    {
        return audioSource.GetSpectrumData(samplesCount, 0, FFTWindow.Blackman);
    }

}

Criando um Espectro de Áudio

Uma primeira aplicação muito interessante dos dados do FFT é a possibilidade de criar espectros de áudio que mostrem o volume de cada faixa de frequência de acordo com o som tocado pelo AudioSource.
Para isso precisamos criar um GameObject para cada banda de frequência, ou seja, se estamos utilizando 1024 samples, precisamos de 1024 Objetos.

Para criar esses objetos podemos usar o Instantiate da unity dentro de um ciclo for que passa por todas as samples.

Desse modo, cria uma classe dentro da script “BeatMapping” com o nome Spectrum e com a subclasse MonoBehaviour:

Código:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class BeatMapping : MonoBehaviour

{
    public AudioSource audioSource;//AudioSource da cena
    public enum samplesCountPresets { _256 = 256, _512 = 512, _1024 = 1024, _2048 = 2048 };//Preset das samples em potencia de 2
    public samplesCountPresets Samples;//Numero de samples que sera usado no FFT

    float[] getSamples(AudioSource audioSource, int samplesCount)
    {
        return audioSource.GetSpectrumData(samplesCount, 0, FFTWindow.Blackman);
    }

}
class Spectrum : MonoBehaviour
{

}

Essa classe será responsável por criar e atualizar nosso espectro.

Para criar o espectro, crie uma função, dentro da classe “Spectrum”, com o nome createAudioSpectrum() e que retorna uma List<GameObject>, também precisamos passar alguns dados para essa função.

Esses dados são:

-O número de samples
-Prefab usado para os elementos do espectro
-Distância entre eles.

Dentro desta função vamos colocar um ciclo for, e dentro do ciclo vamos instanciar os objetos.

Código:

public static List<GameObject> createAudioSpectrum(int samples, GameObject SpectrumPrefab, float elementOffset)
{
    List<GameObject> elementsList = new List<GameObject>();

    for (int i = 0; i < samples; i++)
    {
        GameObject obj = Instantiate(SpectrumPrefab, new Vector3(0, 0, 5), Quaternion.identity);//Adiciona o objeto na cena
        obj.name = "Element " + i;//Renomeia o objeto para Element + index

        float objectSizeX = obj.transform.localScale.x;//Pega o tamanho do objeto em X

        float offsetX = (objectSizeX + elementOffset);//Calcula a distancia entre cada objeto do nosso espectro

        obj.transform.position = new Vector3(offsetX * (i - samples / 2), 0, 5);//Muda o objeto de posicao, -samples/2 serve para colocar metade do spectro para a esquerda e a outra metade para a direita.

        elementsList.Add(obj);//Adiciona o objeto na lista
    }

    return elementsList;
}

Essa função é estática já que não precisamos associá-la a uma instância de classe, ou seja, podemos usar a função apenas digitando Spectrum.createAudioSpectrum().

Vamos criar nosso espectro no void Start da nossa script “BeatMapping”.
Para isso crie uma variável GameObject para armazenar o nosso prefab.

E uma List<GameObject> para armazenar nosso espectro.

Código:

public List<GameObject> spectrum = new List<GameObject>();
public GameObject spectrumPrefab;

void Start()
{

    spectrum = Spectrum.createAudioSpectrum((int)Samples, spectrumPrefab, 0.2f);

}
Dentro da classe “BeatMapping”

Para atualizar nosso espectro com os valores de amplitude das bandas de frequencia vamos criar uma outra função estática na classe Spectrum com o nome updateAudioSpectrum e que retorna void.
Essa função vai precisar dos seguintes dados:

-Elementos do espectro(variável spectrum)
- Número de samples
- Altura máxima do espectro

Nessa função, vamos colocar um ciclo for passando pelos elementos do espectro:

Código:

public static void updateAudioSpectrum(List<GameObject> elements, float[] samples, float spectrumSize)
{
    for (int k = 0; k < (elements.Count); k++)
    {
        elements[k].transform.localScale = new Vector3(elements[k].transform.localScale.x, samples[k] * spectrumSize, elements[k].transform.localScale.z);
        //Atualiza o tamanho do objeto em y de acordo com a amplitude/Volume da sample
    }
}

E vamos chamá-la no void Updade() da classe BeatMapping.
Crie uma variável array de float para armazenar as samples.

Código:

float[] samples;

void Update()
{
    samples = getSamples(audioSource, (int)Samples);
    Spectrum.updateAudioSpectrum(objs, samples, 1000f);
}

Após configurar tudo teremos:

[TUTORIAL] BeatMapping com Unity Asdfsdfdasfg-1
Espectro de áudio em tempo real na Unity
Cada barra do espectro representa uma banda de frequência do FFT.

Obtendo a Frequência Real

Como já mostrado acima, o FFT na Unity retorna uma banda de frequências, mas como podemos fazer para pegar a maior frequência que está tocando?

As frequências podem ter vazamentos para as bandas vizinhas, isso quer dizer que, para frequências na faixa de 23kHz a 46kHz quanto mais próximo do 46kHz mais influencia ela terá na faixa 46kHz a 69kHz, e quanto mais próximo de 23kHz mais influência em 0kHz a 23kHz.
Veremos isso plotado em um gráfico:

[TUTORIAL] BeatMapping com Unity Design-sem-nome-5-1
[TUTORIAL] BeatMapping com Unity Design-sem-nome-4-1

Perceba que o volume das bandas vizinhas é afetado, quanto mais perto a maior frequência estiver, ou seja, para a frequência 42kHz o vazamento acontece para a banda 43kHz a 69kHz, o inverso para a frequência 25kHz que tem o vazamento na banda 0kHz a 23kHz.

Desse modo podemos achar uma boa aproximação da maior frequência usando uma interpolação com as faixas vizinhas.

Para isso, vamos criar uma nova função na classe BeatMapping com o nome getCurrentFrequency, essa função irá retornar uma float que é a maior frequência sendo tocada atualmente pelo AudioSource.

Também vamos precisar do tamanho do intervalo das bandas de frequência, que neste exemplo e 23kHz, mas varia de acordo com o número de samples usado.
Para adquirir o intervalo vamos criar uma função getFrequecyBandRange() que vai retornar uma float.
Nesta funcao usaremos o componente AudioSettings.outputSampleRate() que retorna a taxa de amostragem da usada para reproduzir o sinal, como a taxa de amostragem mínima para a reprodução é o dobro da frequência do sinal, teremos que dividir essa taxa por 2 e depois dividir pelo número de samples.

Código:
float getFrequecyBandRange(int samplesCount)
{
    return (float)AudioSettings.outputSampleRate / 2f / samplesCount;
}

Desse modo, usando o número de samples = 1024 teremos aproximadamente 23kHz por banda.

Agora que temos o intervalo de frequências podemos pegar a frequência atual:

Código:

float getCurrentFrequency(float[] Samples)
{
    float maxAmplitude = 0;//Amplitude da banda
    int index = 0;//Index da banda de maior amplitude
                  //Seleciona a banda com a maior amplitude
    for (int k = 0; k < Samples.Length; k++)
    {
        if (Samples[k] > maxAmplitude)//Compara todas as samples
        {
            maxAmplitude = Samples[k];
            index = k;
        }
    }
    float frequencyIndex = index;//Com indices interios teremos resultados fixos como 23kHz ou 46kHz, usando float podemos chegar em qualquer frequencia
    if (maxAmplitude > 0 && maxAmplitude < Samples.Length - 1)
    {
        float dL = Samples[index - 1] / Samples[index];//Comparar faixas vizinhas (vizinha a esquerda)
        float dR = Samples[index + 1] / Samples[index];//Comparar faixas vizinhas (vizinha a direita)

        frequencyIndex += 0.5f * (dR * dR - dL * dL);//dR - dL pois oque esta a esquerda tem frequecia menor
    }
    return frequencyIndex * getFrequecyBandRange(Samples.Length);//Multiplica o indice pelo intervalo de frequencias
}

Em termos matemáticos teremos:

[TUTORIAL] BeatMapping com Unity Captrurar
Deslocando o índice de acordo com o vazamento nas faixas vizinhas

Ou seja, se após a interpolação o índice for 2.1 e nosso intervalo for 23kHz a frequência atual será:

[TUTORIAL] BeatMapping com Unity Captrurar

[TUTORIAL] BeatMapping com Unity Asdfsdfd3asfg

Notas Musicais

Agora vamos identificar as notas musicais de acordo com a frequência atual.
Para isso vamos criar uma classe Note dentro do arquivo BeatMapping.cs (arquivo atual).
Essa classe servida como objeto, então precisamos adicionar variáveis e um construtor a ela.

As variáveis são:
-O nome da nota
-Multiplicador
-Frequência

Código:

class Note
{
    public string name;
    public float frequency;
    public int multiplier;

    public Note(string name, float frequency, int multiplier = 0)
    {
        this.name = name;
        this.frequency = frequency;
        this.multiplier = multiplier;
    }
}

Sempre que quisermos criar uma nota chamaremos esse objeto e passaremos os valores para ele armazenar:

Código:
Note C = new Note("C", 16.35f);

Vamos adicionar a esse objeto uma função que retorna as notas musicais padrões com a frequência de base.

Código:
public static List<Note> getStandardNotes()
{
    Note C = new Note("C", 16.35f);
    Note Cs = new Note("C#", 17.32f); ;
    Note D = new Note("D", 18.35f);
    Note Eb = new Note("Eb", 19.45f);
    Note E = new Note("E", 20.6f);
    Note F = new Note("F", 21.83f);
    Note Fs = new Note("F#", 23.12f);
    Note G = new Note("G", 24.5f);
    Note Gs = new Note("G#", 25.96f);
    Note A = new Note("A", 27.5f);
    Note Bb = new Note("Bb", 29.14f);
    Note B = new Note("B", 30.87f);

    List<Note> Notes = new List<Note>();
    Notes.Add(C); Notes.Add(Cs); Notes.Add(D); Notes.Add(Eb); Notes.Add(E); Notes.Add(F);
    Notes.Add(Fs); Notes.Add(G); Notes.Add(Gs); Notes.Add(A); Notes.Add(Bb); Notes.Add(B);
    return Notes;
}

Fonte: https://pages.mtu.edu/~suits/notefreqs.html

Agora vamos criar uma função na classe BeatMapping para retornar a nota atual, com o nome getCurrentNote(), para isso vamos comparar a frequência atual com as notas padrões definidas em Note e achar qual a nota mais próxima da frequência atual.

Código:
Note getAudioNote(float frequency)
{
    Note nearNote = new Note("", 0f);

    List<Note> Notes = Note.getStandardNotes();

    for (int k = 0; k < Notes.Count; k++)
        for (int j = 1; j < 8; j++)
        {
            if (Mathf.Abs(frequency - nearNote.frequency) > Mathf.Abs(frequency - Notes[k].frequency * j) || nearNote.frequency == 0)
            {
                nearNote = new Note(Notes[k].name, Notes[k].frequency * j, j);
            }
        }

    if (Mathf.Abs(frequency - nearNote.frequency) < 2)
        return nearNote;
    else
        return new Note("", 0f);
}

Multiplicamos a frequência da nota pelo multiplicador que vai de 1 a 8, se a diferença entre a frequência atual e a nota que estamos comparando for menor que a diferença da frequência atual e a nota mais próxima (Definida anteriormente em outra comparação).
A nota mais próxima da frequência atual passa a ser a que estamos comparando no ciclo for e o loop continua. Ao final de todas as comparações teremos a nota mais próxima da frequência, para uma maior precisão verificamos se a diferença entre a nota selecionada e a frequência atual é menor que 2, se sim retornamos a nota, se não retornamos vazio.

Código:
void Update()
{
    samples = getSamples(audioSource, (int)Samples);
    Spectrum.updateAudioSpectrum(spectrum, samples, 1000f);

    //Debug.Log("Nota musical detectada em ("+Mathf.Round(audioSource.time)+"s): "+ getAudioNote(getCurrentFrequency(samples)).name);//Printar nome da nota
}


[TUTORIAL] BeatMapping com Unity Asdfsdfdas5fg

Na classe BeatMapping
Essa função pode não ser 100% precisa e muitas vezes acaba retornando a nota vazia porém serviu bem para os propósitos deste artigo.

Detecção de Batida

Para detectar a presença de uma batida vamos comparar as samples atuais com as samples anteriores, se a média das samples atual for maior que a das anteriores quer dizer que tivemos um aumento na intensidade sonora que pode ser classificado como Beat.
Crie uma nova array de float com o nome oldSamples.

No método Update coloque samples.CopyTo para salvar os valores das samples anteriores em oldSamples antes de atualizar as samples.

Código:
void Update()
{
    samples.CopyTo(oldSamples, 0);

    samples = getSamples(audioSource, (int)Samples);
    Spectrum.updateAudioSpectrum(spectrum, samples, 1000f);

    Debug.Log("Nota musical detectada em (" + Mathf.Round(audioSource.time) + "s): " + getAudioNote(getCurrentFrequency(samples)).name);//Printar nome da nota
}

Agora podemos detectar a batida com uma nova função na classe BeatMapping:
Coloque o nome de beatDetector e faça a função retornar uma bool.

Passe os valores de oldSamples e de samples, dentro da função crie 2 ciclos foreach que pegam um valor float em samples e em oldSamples.
Faremos a média aritmética dos valores:

[TUTORIAL] BeatMapping com Unity Ewrt

Pode ser escrito como:
[TUTORIAL] BeatMapping com Unity Ersadf


Código:
bool beatDetector(float[] samples, float[] oldSamples, float tolerance = 0)
{
    float oldSamplesAverage = 0;//Armazena a media das samples velhas
    float samplesAverage = 0;//Armazena a media das samples atuais

    foreach (float i in oldSamples)
        oldSamplesAverage += i / oldSamples.Length;
    foreach (float i in samples)
        samplesAverage += i / samples.Length;

    if ((samplesAverage - oldSamplesAverage) > tolerance)//Se a diferenca for maior que um valor de tolerancia
        return true;//Batida detectada
    else
        return false;
}

Usamos o valor de tolerância para deixar o programa menos sensível a qualquer mudança de batida, mas para os testes vamos defini-lo como 0, mas para tornar o sistema um pouco menos sensível tente valores como: 0.04f.
Por fim para evitar erros de Null, adicione as seguintes linhas no void Start() da classe BeatDetector:

Código:
void Start()
{
    oldSamples = new float[(int)Samples];
    samples = new float[(int)Samples];
    spectrum = Spectrum.createAudioSpectrum((int)Samples, spectrumPrefab, 0.2f);
}

Identificando Tons de Áudio

Por último, mas não menos importante, vamos identificar os tons que estão sendo reproduzidos de acordo com a frequência atual.

Para isso vamos criar um enum que contenha os tons que queremos identificar:

Código:
enum Tones { SubBass, Bass, LowMiddle, Middle, HighMiddle, High }

E uma função na classe BeatMapping com o nome getCurrentTone(), essa função irá comparar a frequência atual com os seguintes intervalos:

[TUTORIAL] BeatMapping com Unity Frd1e

E retornará o tom atual de acordo com isso.


Código:
Tones getCurrentAudioTone(float frequency)
{
    if ((frequency) < 63)
        return Tones.SubBass;
    if ((frequency) > 63 && (frequency) < 250)
        return Tones.Bass;
    if ((frequency) > 250 && (frequency) < 640)
        return Tones.LowMiddle;
    if ((frequency) > 640 && (frequency) < 2500)
        return Tones.Middle;
    if ((frequency) > 2500 && (frequency) < 5000)
        return Tones.HighMiddle;
    if ((frequency) > 5000)
        return Tones.High;
    return 0;
}


[TUTORIAL] BeatMapping com Unity Asdfsdfd6asfg

Desse modo, temos um detector de batida capaz de pegar a frequência atual, nota e tom de um áudio source em cena.

https://pt.wikipedia.org/wiki/Transformada_r%C3%A1pida_de_Fourier
https://www.nti-audio.com/pt/suporte/saber-como/transformacao-rapida-de-fourier-fft
https://docs.unity3d.com/ScriptReference/AudioSource.GetSpectrumData.html

Script Completa: https://gist.github.com/MatheusMarkies/c951b329ddad405bf179aa131369c4be
Meu Canal: https://www.youtube.com/channel/UCkngjEDMx9y_vW0t7Io05gg

Tutorial Completo: https://docs.google.com/document/d/e/2PACX-1vTS15dpUZMTA_5JVhw37PjNjjDFzsyX_AziyaQmnBZeogw1sSPDn3f21vDqlkGNEPmeGClcqlTUqrfV/pub



Última edição por Matrirxp em Qua Dez 15, 2021 11:39 am, editado 4 vez(es)
Matrirxp
Matrirxp
ProgramadorMaster

Masculino PONTOS : 2564
REPUTAÇÃO : 85
Idade : 20
Áreas de atuação : Programação: C#, Java, HLSL, CG, GLSL.
Modelagem 3D.
Respeito as regras : [TUTORIAL] BeatMapping com Unity Aad8pUi

https://www.youtube.com/channel/UCkngjEDMx9y_vW0t7Io05gg

Ir para o topo Ir para baixo

TUTORIAL Re: [TUTORIAL] BeatMapping com Unity

Mensagem por MarcosSchultz Qua Dez 15, 2021 8:22 am

Nuss, olha a qualidade do tutorial. Parabéns, top demais.
MarcosSchultz
MarcosSchultz
Administrador

Masculino PONTOS : 64072
REPUTAÇÃO : 2614
Idade : 25
Áreas de atuação : Administrador do fórum
Respeito as regras : [TUTORIAL] BeatMapping com Unity Aad8pUi

https://www.schultzgames.com

Ir para o topo Ir para baixo

TUTORIAL Re: [TUTORIAL] BeatMapping com Unity

Mensagem por MayLeone Qua Dez 15, 2021 12:54 pm

Caramba! Que qualidade, hein? Tópico muito precioso e informativo, que não só mostra como fazer o sistema (código e mais código) mas também explica o conceito por meio de equações matemáticas e casos reais! Muito bom, vou favoritar aqui.
MayLeone
MayLeone
Instrutor

Feminino PONTOS : 2930
REPUTAÇÃO : 568
Áreas de atuação : Unity & C#
Respeito as regras : [TUTORIAL] BeatMapping com Unity Aad8pUi

http://compilemosfacil.blogspot.com.br

Ir para o topo Ir para baixo

Ir para o topo

- Tópicos semelhantes

 
Permissões neste sub-fórum
Não podes responder a tópicos