Voltar ao Sumário
Songbook - Parte 2
Músicas com Cifras para Violão.
Na parte 1 deste projeto, foi apresentado o código para a tela inicial do aplicativo, com botões de navegação e busca. Nesta parte, vai ser apresentado o código da tela de Música, juntamente com a discussão sobre decisões de arquitetura e implementação.Revisitando o Problema
Os dados recebidos na tela de música são as linhas de uma música, na forma de uma lista. Você já viu que a música tem um título, informações sobre a mesma, como os compositores, ritmo e o tom do arranjo, e, em seguida, diversas linhas entremeadas, com a letra da música precedida por uma linha com cifras, que marcam os acordes a utilizar.Veja abaixo um conjunto típico de verso e cifras, tirado de um dos exemplos já apresentados:
A7 D
Como pode um peixe vivo
Se o objetivo fosse simplesmente apresentar a música no tom em que o arranjo foi criado, não haveria nenhum grande desafio. Uma caixa de texto rolável preenchida com o texto da música seria suficiente. Mesmo o requisito de alterar o Tamanho da Fonte pode ser acomodado com facilidade, mas um outro requisito demanda um pouco mais de trabalho: Deve ser possível transpor a música para outros tons. Para fazer isso, todas as notas representadas pelas cifras devem ser deslocadas o mesmo número de semi-tons.
A primeira implicação desse último requisito é que as linhas que contêm cifras devem ser marcadas com um caractere especial, assim como ocorre com as linhas de título. Dessa vez, o caractere escolhido é o '&'. Isso permite que o programa identifique as linhas que precisam ser alteradas quando for necessária a transposição.
Agora, você precisa analisar mais de perto a formação das cifras. Veja alguns exemplos abaixo:
D Am C7 G/B Bb Eb° C7/9 F#m7
Parece complicado, mas tudo que é preciso entender sobre essas cifras, do ponto de vista do algoritmo de transposição, é que existem notas em letra maiúscula seguidas ou não dos caracteres 'b' ou '#', que deslocam a nota de um semi-tom para baixo ou para cima. A cifra contém outros símbolos que determinam a formação do acorde. Estes símbolos devem simplesmente ser repetidos na linha transposta.
Para realizar a transposição, basta deslocar as notas de forma circular em uma escala com 12 semi-tons (ou seja, se passar da última, volte à primeira) conforme a lista abaixo.
A, Bb, B, C, C#, D, Eb, E, F, F#, G, G#
Esta é a escala cromática das notas musicais. Depois de G#, temos novamente a nota A, uma oitava acima (na prática, isto significa que a nota tem dobro da frequência).
Em algumas músicas, entre as estrofes da letra, o músico deve tocar uma sequência de baixos, ou uma melodia em solo. Para representar essas sequências melódicas, foi escolhida uma representação em que as notas soltas são escritas em letra minúscula, seguidas ou não dos caracteres 'b' ou '#', como no caso das cifras, e, depois disso, opcionalmente seguidas de um número que representa a duração da nota. Outro modificador pode ser um apóstrofo ou vírgula, para marcar mudança de oitava. Mais uma vez, tudo que o programa tem que fazer é identificar as notas (letras de 'a' a 'g') e o caractere seguinte, que pode indicar deslocamento de 1 semi-tom. Essas notas também devem ser transpostas, e os símbolos adicionais devem ser simplesmente repetidos.
Veja um exemplo de linha de melodia, já no formato proposto, com um caractere '&' no início:
& c#4 d8 e f# e d c#
Máquina de Estados
Ao desenvolver um algoritmo para a transposição das cifras, seria necessário descrever a forma de interpretar as sequências de caracteres recebidos. Uma técnica muito útil para tratar esse tipo de problemas é utilizar uma máquina de estados. Nessa 'máquina', em cada estado, são esperados caracteres pertencentes a grupos específicos, que provocam mudanças para outros estados e ações associadas a essas mudanças. Nessas ações, pode estar, por exemplo, a formação de um resultado. Veja o exemplo abaixo, inicialmente apresentado na forma de texto (parcialmente), e, depois, na forma de um diagrama a ser utilizado para o algoritmo de transposição.Comece com o estado = O (origem).
No estado O,
se receber uma letra maiúscula de 'A' a 'G',
guarde a nota e passe ao estado C (cifra);
senão, se receber uma letra minúscula, de 'a' a 'g',
guarde a nota e passe ao estado n (nota);
senão, se receber um espaço, ou um dos outros símbolos esperados
na notação das cifras,
permaneça no estado O, e copie o símbolo recebido para o resultado.
senão,
passe ao estado I (ignorar), que vai copiar o restante da linha
para o resultado, sem transposição.
No estado C,
se receber um 'b' ou '#',
desloque a nota de um semi-tom, conforme o símbolo,
copie a nota para o resultado e passe ao estado A (acorde)
...
Os estados necessários na máquina de transposição são: Origem (um estado inicial); Cifra, em que foi recebida a primeira nota de uma cifra, e se espera o símbolo que pode alterar a nota em um semi-tom; Acorde, que copia para o resultado os demais símbolos do acorde; nota, em que foi recebida uma nota da melodia, e se espera o símbolo que pode alterar a nota em um semi-tom; tempo, que copia para o resultado os demais símbolos que determinam a oitava e duração da nota; e Ignorar, que copia para o resultado o restante da linha, que já não possui notas e nem cifras.
Diagramas de Cifras
Outro requisito é mostrar um diagrama das cifras utilizadas na música. Este diagrama precisa ser criado em um componente gráfico, e não é essencial quando se está tocando. Como decisão de projeto, para maximizar a tela de música com a canção a tocar, um botão nessa tela causa a abertura de outra tela, em que os diagramas serão desenhados.Neste ponto, foi necessário tomar uma decisão de projeto, considerando os seguintes fatores: A ferramenta de desenvolvimento utilizada, o AppInventor, tem limitações que dificultam o compartilhamento de estruturas de dados globais entre todas as telas; O projeto, apesar de ter por objetivo criar um aplicativo funcional, continua sendo um projeto educativo, e, por isso, deve evitar soluções complexas; As cifras a mostrar para cada música deveriam acompanhar a transposição, e mudar todas as notas de acordo, mas isto implicaria na necessidade de passar para a tela de Música um dicionário de cifras, no qual os diagramas de cifras pudessem ser consultados; Além disso, em arranjos de músicas mais elaboradas, a escolha da forma do acorde utilizado pode alterar o resultado musical, e a transposição não é tão simples.
Considerando todos esses fatores, optou-se por uma solução, nesta primeira versão do aplicativo, em que os diagramas de cifras são passados juntamente com cada música, ao final da letra, e não são transpostos. Para que o arquivo de músicas continue representado como texto sem formatação, é necessária uma notação para cada diagrama. A notação proposta é uma linha por cifra, com a cifra seguida por um sinal de igual e uma sequência de até 6 dígitos representando o trasto em que cada corda deve ser pressionada (X em cordas mudas). Esta notação acomoda diagramas para outros instrumentos de corda, como ukulele e cavaquinho, com 4 cordas, e viola, com 5 pares. Você vai precisar de mais um marcador início de linha. Pode ser '@'.
Veja abaixo um exemplo:
@ Dm = XX0231
Componentes da Tela de Música
Com os principais detalhes resolvidos, você tem que projetar a arrumação da tela. Veja abaixo uma possível solução:
Segue a lista de componentes nesta tela:
- txTom - Uma caixa de texto que só aceita números, que recebe o número de semi-tons a utilizar na transposição. O valor inicial é 0, ou seja, sem transposição.
- btTrasto - O botão que aciona a função de transposição.
- btAumentaLetra - O nome é auto-explicativo
- btReduzLetra - Auto-explicativo
- btAcordes - Botão que ativa a tela de diagramas das cifras.
- txMusica - Caixa de texto onde é apresentada a música. Esta caixa de texto é multi-linhas.
- TinyDB1 - Memória permanente, onde ficará guardada a escolha mais recente para o Tamanho da Fonte para as letras em txMusica.
Blocos da Tela de Música
Definida a arrumação dos componentes, você pode passar à lógica que trata os diversos eventos.Comece com algumas estruturas de dados:
A variável tom guarda o deslocamento em semi-tons da música a apresentar na tela, com relação à música original.
A lista linhas_musica é auto-explicativa. Armazena as linhas recebidas durante a ativação desta tela.
A lista acordes é gerada durante o preenchimento da tela, com os diagramas de acordes encontrados na música (marcados com '@' no início da linha).
O primeiro evento ativado quando TelaMusica é aberta a é quando TelaMusica.Iniciar.
Neste evento, as linhas de música são copiadas para a estrutura local, e o tom é inicializado com 0, ou seja, a apresentação original da música é no tom original. Em seguida, é ativado o procedimento AtualizarTela.
O procedimento AtualizarTela recupera da memória permanente do dispositivo o último tamanho da fonte escolhido, e atualiza o TamanhoDaFonte de txMusica. Em seguida, copia as linhas da música para o texto de txMusica, transpondo as notas. Esta última parte foi separada em um outro procedimento, TransporMusica.
TransporMusica recebe as linhas da música e de quantos semi-tons a mesma deve ser transposta, e gera o texto para preencher a caixa de texto da tela. O procedimento percorre as linhas, e analisa o primeiro caractere. Se o mesmo é '#', ele é saltado ao copiar a linha; se é '&', a linha é repassada ao procedimento TransporNotas, que vai tratar das cifras, ou melodia; se o primeiro caractere é '@', a linha é copiada para a lista de acordes; e, finalmente, em qualquer outro caso, a linha é copiada integralmente para o resultado. Este resultado é construído como uma lista, que, ao final do procedimento, é transformado em texto, com caracteres de mudança de linha como separadores.
Embora o procedimento seja simples, os diversos níveis de alinhamento geram uma imagem muito larga. Para mostrar esta imagem na página do documento, a letra ficaria muito pequena. Por isso, vamos mostrar o procedimento em fragmentos que têm uma coesão lógica.
No início do procedimento, são declaradas a lista local que vai armazenar as linhas de texto já processadas, e uma variável para armazenar o primeiro caractere da linha. A lista de acordes é esvaziada, e se inicia uma repetição, executada para cada linha recebida. Se a linha não é vazia, o primeiro caractere é obtido.
Em seguida, como pode ser visto na imagem seguinte, são feitos testes com este primeiro caractere, para os três casos especiais possíveis - '#', '&' ou '@', com o tratamento já descrito.
Por fim, ainda dentro da repetição, a linha já processada, com o caractere especial removido, se for o caso, e com as notas transpostas, é copiada para o resultado (texto).
Terminada a repetição, a lista texto é convertida com a adição de separadores de linha para gerar o resultado final.
Veja agora o detalhamento do procedimento TransporNotas, implementando a máquina de estados descrita antes.
É necessário declarar algumas variáveis globais. Na verdade, essas não são propriamente variáveis, já que não mudam ao longo da execução do programa. São constantes que serão utilizadas no procedimento: Uma lista com as 12 notas musicais, as letras que dão nome às notas, de 'a' a 'g', em minúsculas e maiúsculas, números que aparecem na formação de acordes, e separadores de notas.
Como no procedimento anterior, apresentamos o código em fragmentos lógicos.
O procedimento recebe o texto com cifras e notas a transpor, e quantos semi-tons de deslocamento (desl) devem ser aplicados. Na preparação, são declaradas algumas variáveis locais, e um teste verifica se o deslocamento é zero. Se é o caso, não há nada a fazer, e o texto recebido é copiado integralmente para o resultado, sem modificações.
Se o deslocamento não é zero, é acrescentado um espaço no fim da linha, para facilitar o funcionamento da máquina de estados.
O programa percorre o texto, caractere a caractere, decidindo o que fazer a partir do estado em que se encontra e o caractere lido. O primeiro bloco trata o estado O, o estado inicial da máquina.
Segue a parte truncada no teste acima:
Seguindo o código, você vai ver que o estado muda de O para n (nota) se for encontrada uma nota em letra minúscula e de O para C (cifra) se for encontrada uma nota em letra maiúscula. O restante do código trata dos separadores adicionais e espaços que podem ser encontrados, e que devem ser copiados para o texto transposto. Um teste com a posição no texto original e o tamanho do texto transposto procura manter o alinhamento das cifras.
Depois do estado O, vem o tratamento de mais alguns estados:
O estado I (ignorar) é alcançado se algum caractere não esperado for encontrado. Pode ser algum texto auxiliar após as cifras, como um marcador de repetições. A partir daí, o texto lido é simplesmente copiado para a saída.
Os estados n (nota) e C (cifra) têm tratamento semelhante: O caractere esperado é o marcador de semi-tom ('#' ou 'b'), que é usado em conjunto com a nota e o deslocamento para gerar a nota transposta. Esta nota é um número de 1 a 12, que indica qual ítem da lista de notas deve ser copiado para o texto transposto.
Tratada a nota, a máquina passa para um estado que trata os modificadores do acorde (A), ou o tempo de duração da nota (t).
Nesses novos estados, ocorre a verificação se o caractere seguinte é um dos esperados, ou se é um espaço. Conforme o caso, a máquina permanece no mesmo estado, volta ao estado original (O), ou passa ao estado de ignorar o restante do texto (I). O caractere lido é sempre copiado para o texto. No caso dos espaços, mais espaços podem ser adicionados, para manter o alinhamento das notas e cifras.
Ao fim da repetição que trata todo o texto de entrada, resta retornar o resultado:
No código mostrado, a transposição da nota foi delegada a outro procedimento - TransporNota. Este é um procedimento simples, que faz contas com os valores recebidos, e garante que o resultado fique entre 1 e 12, sendo um índice válido na lista de notas.
Os blocos restantes no tratamento de TelaMusica tratam dos botões de Tamanho da Fonte, o botão de Transposição e o botão de Acordes, que provoca a criação de uma terceira tela - TelaAcordes.
Com esse código, você já pode fazer muitos testes com o aplicativo. Veja a seguir um exemplo de arquivo de músicas que pode ser usado. A tela de acordes envolve manipulação gráfica, e será tratada em uma outra parte deste projeto.
#Parabéns Pra Você
Mildred J Hill/Patty Hill/Bertha Celeste
& A
& A E
Parabéns pra você
& A
Nesta data querida
& A7 D
Muitas felicidades
& A E A
Muitos anos de vida
(repete)
@ A = X02220
@ A7 = X02020
@ D = XX0232
@ E = 022100
#Peixe Vivo
Cantiga de Roda (domínio público)
& D
(introdução)
& D A7 D
& A7 D
Como pode um peixe vivo
& A7 D
viver fora da água fria
& G D
Como poderei viver
& G D
Como poderei viver
& A7 D
Sem a tua, sem a tua,
& A7 D
Sem a tua companhia
& A7 D
Os pastores dessa aldeia
& A7 D
fazem prece noite e dia
& G D
Por me ver assim chorando
& G D
Por me ver assim chorando
& A7 D
Sem a tua, sem a tua,
& A7 D
Sem a tua companhia
@ A = X02220
@ A7 = X02020
@ D = XX0232
@ G = 320003
Nota de Implementação
Se você analisar atentamente o diagrama e o código que implementa a máquina de estados que interpreta as linhas com cifras, vai notar que o algoritmo aceita linhas mal-formadas sem passar ao estado I. Esta foi uma decisão de projeto, para simplificar a criação da máquina de estados. O objetivo do aplicativo não é corrigir erros de notação musical, e pode-se assumir com segurança que as linhas com cifra estão corretas, pois, caso contrário, não fariam sentido para o músico que vai usar a ferramenta. Como o arquivo de músicas é um arquivo de texto, fica fácil corrigir qualquer erro no mesmo.Já um programa que precisa analisar arquivos de músicas para publicar livros impressos deveria ser bem mais rigoroso, e apontar qualquer erro, pois o custo de corrigir um erro depois de milhares de cópias impressas seria muito alto. Para esse caso, existem ferramentas que auxiliam a construir analisadores sintáticos bem complexos.
Distribuído sob a licença: Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) : https://creativecommons.org/licenses/by-sa/3.0/deed.pt_BR
Passar à Parte 3
















Nenhum comentário:
Postar um comentário