Projeto Atual:

Programando Aplicativos com Javascript

05/05/2020

Songbook - Aplicativo para Android - Parte 1

Voltar ao Sumário

Songbook - Parte 1

Músicas com Cifras para Violão

Para você que acompanhou os projetos anteriores, este é um projeto bem completo, e pode ser útil para quem gosta de criar seus arranjos para violão.

Preparação

Neste projeto, você vai notar uma mudança no estilo das instruções. Assumindo que você já domina os recursos mais básicos, este documento terá a forma de um projeto completo, com foco nos requisitos, decisões de arquitetura, algoritmos e detalhes de implementação. Diversos fragmentos de código vão continuar sendo apresentados, mas o passo a passo da construção de cada conjunto já não vai ser apresentado. O início não muda: precisamos conhecer o problema e os requisitos do sistema.

Vamos continuar utilizando a plataforma de desenvolvimento AppInventor 2. Veja nos artigos anteriores como criar sua conta e começar a programar aplicativos.

O Problema

Um Songbook, literalmente um Livro de Músicas, contém letras de músicas anotadas com símbolos que um músico utiliza para tocar o acompanhamento das mesmas. Estes símbolos se chamam cifras, e representam notas musicais e outros detalhes do acorde a utilizar em cada parte da música. As notas são representadas por letras, sendo Dó = C, Ré = D, Mi = E, Fá = F, Sol = G e Lá = A. As outras notas do acorde são representadas por diversos símbolos conhecidos pelo músico. Por exemplo: m, 7, M, etc.

Para o músico, é importante que as cifras fiquem bem alinhadas com a sílaba da palavra onde o acorde deve mudar. Por isso, em geral, as letras de músicas com cifras são apresentadas em fontes com mono-espaçamento (e.g.: Courier New).

Junto com a letra da música, seguem outras informações, como o título, o autor e o tom da música. O tom define a nota fundamental da escala em que a música vai ser cantada. A música pode ser transposta para outro tom (todas as notas mudam), de forma que possa ser cantada por alguém com voz mais aguda ou mais grave. Algumas vezes, também é indicado o ritmo da música (eg. Samba, Valsa, Rock, etc).

Para auxiliar músicos iniciantes, diagramas ao final da música apresentam a digitação das cifras utilizadas.


Nos Songbooks impressos, cada música fica em uma folha, e um sumário apresenta os títulos, indicando em que página está a música.

Veja abaixo um exemplo de música:

Peixe Vivo
    Cantiga de Roda
                               Tom: D
Intro.:
     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


Requisitos

Crie uma lista de requisitos para o seu novo projeto. Se possível, entreviste pessoas que gostariam de usar seu App para criar arranjos para músicas e tocar violão usando estes arranjos.

Veja alguns requisitos possíveis:

  • Permitir a leitura de um arquivo de músicas personalizadas, criadas pelo usuário;
  • Apresentar uma lista de músicas navegável, que permite escolher uma música para tocar. A navegação deve permitir voltar à primeira tela de músicas, avançar para a próxima tela e voltar à anterior, e avançar para a última tela;
  • Permitir a busca de músicas por título, autor, ou palavras nos versos da letra;
  • Guardar a posição da última música tocada, para continuar deste ponto quando o aplicativo for reaberto;
  • Apresentar a música escolhida no maior espaço da tela possível;
  • Permitir a mudança do tamanho da fonte to texto da música, para melhor aproveitamento da tela;
  • Permitir a transposição do tom da música;
  • Ajuda visual com cifras dos acordes menos comuns usados no arranjo (ou todos os acordes da música).


A partir destes requisitos, você vai tomar diversas decisões sobre a arquitetura do seu aplicativo. 


Formato do Arquivo de Músicas

Uma das decisões é sobre como armazenar as músicas de uma forma que possam ser facilmente alteradas pelo usuário, e que possam ser lidas pelo aplicativo. Para manter o formato simples e não ter que reinventar um editor de textos, faz sentido que o arquivo de músicas seja um arquivo de texto sem formatação, em que cada linha é um verso da música, um conjunto de cifras ou um dos outros detalhes, como título, autor, etc.

Para que cada música seja apresentada separadamente, e para que se possam criar índices de títulos e compositores, é necessário marcar o título, que vem no início de cada música com algum caractere especial. Uma escolha natural seria o caractere de quebra de página, já que em um livro de músicas cada uma deveria vir mesmo em uma nova página. Mas nem todo editor de textos tem facilidades para se criar e armazenar quebras de páginas em arquivos. Escolha, então, um caractere arbitrário, que nunca apareça no início de um título de música. Uma sugestão: "#".

Com isso, a primeira decisão de projeto é que o arquivo de músicas será um arquivo de texto em que cada título de música vem precedido do caractere "#". Você pode também definir que a linha seguinte ao título será a música com o nome do(s) compositor(es), e que estará vazia caso não exista essa informação. Isso vai facilitar a busca por compositor. Mais tarde, outros marcadores serão escolhidos, mas por enquanto, o marcador de título é suficiente.

A partir deste formato de arquivo, voce já pode pensar em um algoritmo para ler o arquivo de músicas e armazenar as informações relevantes:

Criar uma lista de títulos, que começa vazia;
Criar uma lista de compositores, que começa vazia;
Criar uma lista para as letras de músicas, que começa vazia;
Para cada linha do arquivo de músicas:
  Se a linha inicia com o marcador de início de título,
    Guardar a linha na lista de títulos;
    Lembrar que a próxima linha deverá ser guardada na lista de compositores;
  Se a linha é a linha de compositores,
    Guardar a linha na lista de compositores;
  Guardar a linha na lista de letras de músicas.




Tela Principal

Observando os requisitos, você vai notar que em uma tela inicial são necessários componentes para escolher um arquivo, apresentar uma lista de títulos das músicas contidas neste arquivo e botões para navegar pela lista. Também faz sentido incluir nesta primeira tela os botões de busca por título, autor, etc. Certamente, a apresentação da música deverá ser feita em uma segunda tela, com menos componentes, para que sobre mais espaço para a letra da música.

Adotando o método de desenvolvimento incremental, comece por implementar esta primeira tela.

Há pouco o que aproveitar dos projetos anteriores, mas se você quiser aproveitar o código de escolha de arquivos, pode abrir o projeto Enquete, e salvar como Songbook. Uma alternativa é usar a "Mochila", onde você pode guardar uma parte do código (no caso, o procedimento uri_para_nome_arquivo), e reutilizá-la no seu novo projeto.

Você terá que decidir para que dispositivos seu aplicativo vai estar disponível. Se criar a diagramação para celulares, os botões e outros componentes podem ficar pequenos, e difíceis de ler em tablets. Por outro lado, se usar botões grandes para ter uma boa diagramação nos tablets, estes podem não caber na tela de um celular.


Após testar algumas arrumações em diversos dispositivos, a que funcionou melhor em tablets e celulares foi a arrumação abaixo, com o Tamanho da Fonte em todos os componentes igual a 14. Para visualizar as músicas com um bom tamanho de fonte em celulares, eles devem estar com a tela deitada.




A imagem não mostra todos os componentes. Segue uma lista, com a explicação e detalhes sobre cada um.

  • Screen1 - É a tela principal, que sempre tem esse nome em projetos do AppInventor. Lembre-se de criar um ícone para seu aplicativo.
  • OrganizaçãoHorizontal1 - Vai conter os botões para leitura do arquivo e posicionamento da música.
  • btArquivo - Ao ser acionado, permite a escolha do arquivo de músicas. O tamanho da fonte de todos os botões foi mantido em 14, para funcionarem em diversos dispositivos. Se você preferir, pode usar valores maiores, se quiser um visual melhor em tablets, mas isso pode prejudicar o uso em celulares.
  • btRota - Serve para guardar a rota que aponta para a raiz do sistema de arquivos. Seu uso será explicado na implementação.
  • btCarregar - Ao ser acionado, é lido o arquivo de músicas, cuja rota de acesso está na caixa de texto abaixo do botão.
  • btPos - Ao ser acionado, posiciona a lista de músicas de forma que o primeiro elemento seja a última música visualizada. Essa informação é armazenada em memória permanente, e funciona mesmo se o aplicativo é fechado e reaberto.
  • txNomeArquivo - Usado para indicar a rota de acesso do arquivo de músicas, e também para indicar a rota da raiz, quando o botão btRota é acionado.
  • txBusca - É utilizado para indicar o texto a buscar, quando um dos botões btAutor, btTítulo ou btLetra é acionado.
  • btPrimeira, btAnterior, btProxima e btUltima - São botões de navegação, que atuam na lista de músicas mostrada (a lista mostra 15 títulos de músicas de cada vez).
  • btAutor, btTitulo e btLetra - Acionam operações de busca, na lista de compositores, na de títulos ou em toda a letra das músicas, respectivamente.
  • lsTitulos - É a lista que apresenta 15 títulos de músicas de cada vez.
  • Notificador1 - É usado para mensagens nas operações com arquivos.
  • IniciadorDeAtividades1 - É usado para ativar um gerenciador de arquivos, para escolha do arquivo de músicas.
  • TinyDB1 - Provê memória permanente para armazenar o nome do arquivo de músicas, a posição da última música visualizada na lista, a rota da raiz do sistema de arquivos e informações das demais telas do aplicativo.
  • Arquivo1 - É o componente que trata da leitura do arquivo de músicas.

Código para Screen1

Uma vez escolhidos os componentes. É hora de passar ao código.

Comece com as estruturas de dados e o código para escolher e ler o arquivo de músicas.

A partir do algoritmo proposto para leitura do arquivo, você pode identificar a necessidade de criar três listas: para os títulos, para os autores e para as músicas. Veja a declaração das variáveis abaixo:
Para escolha do arquivo de músicas, você vai precisar de código semelhante ao utilizado no aplicativo de enquetes. Veja abaixo o tratamento do botão btArquivo:

O procedimento uri_para_nome_arquivo também já apareceu antes. Desta vez, você pode melhorá-lo um pouco. Na versão anterior, a sequencia que marca a raiz do sistema de arquivos tinha um valor fixo, mas, após testar o aplicativo Enquete em dispositivos diferentes, foi determinado que esta sequencia muda de um dispositivo para outro. Com isso, fica melhor armazenar essa sequencia em memória permanente, usando o componente TinyDB1.



Veja abaixo como ficou o procedimento.




O código mantém a sequencia original, como o padrão, caso nada tenha sido armazenado em TinyDB1, na chave "SongbookSeparadorRota", mas permite que outro valor seja definido.



Para definir outro valor, com o aplicativo em uso, você deve usar o botão Arquivo para escolher algum arquivo no dispositvo, apagar a sequencia final, que tem a rota do arquivo a partir da raiz na caixa de texto, e usar o botão btRota, para armazenar a sequencia que precede a raiz. Segue o código que falta:


Quando há um nome de arquivo válido (com a rota completa) na caixa de texto txNomeArquivo, o botão btCarregar pode ser acionado. A lógica de leitura do arquivo vai ser organizada em um procedimento, que é ativado através desse botão e também quando o aplicativo é reiniciado. O nome escolhido: CarregarMusicas.


O código implementa o algoritmo já apresentado, na fase de planejamento. Para poder carregar o mesmo arquivo ao reiniciar o aplicativo, o nome do mesmo é armazenado em um registro de TinyDB1, no tratamento do botão. Veja abaixo.



Para completar essa parte do tratamento do arquivo de músicas, seguem mais dois blocos, ativados quando aplicativo é iniciado:



Note que já no primeiro uso, o programa assume que existe um arquivo de músicas armazenado em /AppInventor/Songbook/musicas.txt. Ao instalar o aplicativo, você deve criar este diretório e copiar para lá seu arquivo de músicas. O arquivo pode ter outro nome, ou estar em outra pasta do dispositivo. Para alterar estas informações, basta preencher o novo nome,  junto com a nova rota, e acionar o botão btCarregar.

Você pode ter observado que ao final do procedimento que preenche a lista de títulos um outro procedimento é ativado: PreencherTitulos. Este é o procedimento que preenche a lista de títulos na tela, 15 de cada vez (por decisão de projeto). A ativação deste procedimento ao fim de um outro viola o princípio de que cada procedimento deveria executar uma tarefa bem definida. Aqui, CarregarMusicas, além de executar o que o nome sugere, também preenche a lista de títulos. A razão é que a leitura do arquivo de músicas é realizada de forma assíncrona (isto é, ocorre em um tempo que não pode ser controlado pelo programa), e a ativação de PreencherTitulos não funciona se movida para abaixo da chamada de CarregarMusicas no tratamento da inicialização de Screen1.  A seguir, será apresentado o código de PreencherTitulos e o tratamento dos botões de navegação.


Botões de Navegação

O procedimento PreencherTitulos recebe três parâmetros: A lista a utilizar, o índice do título inicial na lista e o número de títulos a apresentar. PreencherTitulos é de fácil implementação. 
Basta copiar da lista de títulos para uma nova lista o número indicado de títulos, com o formato com que serão apresentados em lsTitulos. O desafio é tratar todas as situações de contorno, para evitar o erro de tentar um elemento que não exista. Você pode estar se perguntando porque é necessário um parâmetro com a lista. A resposta é que este procedimento vai ser reaproveitado para mostrar os resultados de buscas por título, por autor ou por letra. Mais tarde você vai entender melhor a razão.


Veja abaixo o código do procedimento:

Na cópia, o terceiro elemento do registro é o índice do mesmo na lista de títulos, e o primeiro elemento, o texto do título. O resultado fica com o número da música seguido do título.


Usando esse PreencherTitulos, é fácil implementar o tratamento dos botões btPrimeira e btUltima:



Para btUltima, o procedimento tenta mostrar os últimos 12 títulos. O procedimento PreencherTitulos trata das condições de contorno.

A partir desse ponto, você já pode fazer testes com seu aplicativo. Para isso, além de gerar o .apk e instalar no dispositivo alvo, também é necessário copiar o arquivo de músicas para /AppInventor/Songbook/musicas.txt. Para testar toda a funcionalidade, é necessário que o arquivo tenha mais de 15 músicas. Não está no escopo deste documento apresentar arranjos para músicas. Para não violar direitos de autor, seria necessário escolher músicas em domínio público, e fica difícil prever as preferências musicais de cada usuário. De qualquer forma, para mostrar o formato do arquivo de músicas necessário neste ponto do desenvolvimento, foram selecionadas duas músicas em domínio público, reproduzidas logo abaixo. O texto que vem antes do primeiro marcador de títulos é ignorado, e serve apenas como comentário.

Arquivo de músicas com Cifras

Formato próprio para uso com o aplicativo Songbook
O início de cada música deve ser marcado com um caractere '#'
no início da linha de títulos.
A linha seguinte deve conter os nomes dos autores ou intérpretes.

#Parabéns Pra Você
    Mildred J Hill/Patty Hill/Bertha Celeste
                                                             Tom: A

    A          E
Parabéns pra você
              A
Nesta data querida
      A7     D
Muitas felicidades
       A    E  A
Muitos anos de vida

(repete)


#Peixe Vivo
    Cantiga de Roda (domínio público)
                                                             Tom: 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

O tratamento de btProxima é um pouco mais complicado. Pensando no caso mais geral, onde a lista pode conter resultados de uma busca, foi escolhido apresentar os títulos a partir do penúltimo da lista na tela, para que o usuário possa se orientar. Com uma lista de 15, este elemento é o 14º mas a lista pode ter outro tamanho. Para resolver isso, foi usada a posição que está a 7/8 do fim da lista. Já o tratamento de btAnterior ficou simples: o índice volta 12 unidades. Veja abaixo como ficou o código:



Nota: para manter o tamanho das letras minimamente legível, um fragmento da conta de 7/8 do comprimento da lista foi destacado, e mostrado abaixo da sua posição, como pode ser visto.


Botões de Busca

Para implementar os botões de busca, é necessário um procedimento que gere uma lista com registros idênticos aos da lista de títulos, mas apenas com os títulos das músicas que atendem ao critério de busca. Este procedimento recebeu o nome de ProcurarTitulos, e recebe dois parâmetros: a lista em que será feita a busca (que pode ser a lista de títulos ou a de autores), e o texto a buscar.

Quando se trata de procedimentos de busca, existem muitas decisões a considerar. No caso deste aplicativo, por se esperar que o número de títulos seja pequeno (menor do que mil), foi utilizada uma busca linear, sem a construção de nenhum índice auxiliar. O texto a buscar também é procurado literalmente, ou seja, qualquer espaço extra, mudança de acentuação ou mudança de ordem nas palavras resulta em falha na busca. O único tratamento do texto a procurar é que a caixa das letras (maiúscula x minúscula) é normalizada. Para realizar uma busca mais completa, seria necessário criar índices de palavras por título, por autor e por música. Fica o lançado o desafio.

Note que a busca é realizada na lista passada como parâmetro, mas o resultado armazenado vem da lista de títulos, pois o que deve ser mostrado é o título da música. O algoritmo assume que as duas listas têm o mesmo alinhamento entre autor e título. Melhor seria usar o índice na lista de títulos que fica armazenado em cada registro.

Veja abaixo o procedimento:



Usando esse procedimento, o tratamento de btTitulo e btLetra é simples:



Para buscar texto nas letras das músicas, é necessário um novo procedimento, porque ficaria difícil unificar as três buscas em um procedimento só. Para isso, foi criado o procedimento ProcurarTexto. O único parâmetro necessário é o texto a buscar, usando o seguinte algoritmo:

Crie uma lista de resultados vazia
Para cada título na lista de títulos,
  Obtenha a linha inicial da música que tenha esse título.
  Percorra as linhas de música a partir da linha obtida até
  encontrar um novo título (fim da música), e, para cada linha,
    se o texto da linha contém o texto procurado,
      adicione o título à lista de resultados e prossiga para um novo título.
Retorne a lista de resultados.

Você vai notar, na implementação, o uso do comando break. Este comando causa a interrupção de uma repetição. Ele é usado quando o texto é encontrado, ou quando o fim da música é alcançado.


Veja abaixo como ficou a implementação:



Segue o tratamento de btLetra:



Você pode testar todo esse código, mas falta uma parte importante: Uma vez escolhida uma música da lista, esta deve ser apresentada. Para melhor visualização usando o maior espaço possível, uma nova tela é criada para apresentar a música. A implementação da nova tela vai ser tratada em outro artigo, mas, por enquanto, ainda no código para Screen1, deve ser montada a estrutura de dados que será repassada à nova tela, contendo a música escolhida.

Preparação para a Tela de Música

Quando um item da lista é escolhido, pode-se utilizar o número inicial contido no texto do item para indicar o índice na lista de títulos relativo a esta música. No registro do título, na segunda posição, está a posição da música na lista de músicas. A partir desta posição pode ser montada a lista com as linhas da música.

No procedimento, o índice do título é passado como parâmetro, a linha inicial da música é recuperada como descrito acima, e, a partir daí, as linhas de música são copiadas para uma nova lista, até o fim da lista de linhas de música, ou até ser encontrado um novo marcador de início de música.


Veja abaixo:



Novamente, um detalhe do código foi cortado para manter a legibilidade. Segue o detalhe em destaque:

Com isso, o tratamento da seleção em lsTitulos fica assim:



Você deve ter observado que o índice do título é armazenado em memória permanente. Isto é feito para que a lista de títulos seja posicionada nesta última música apresentada quando o aplicativo for reiniciado, ou quando o botão Posicionar for acionado:





Testando o Aplicativo

O tratamento de Screen1 está completo, e você pode testar toda essa funcionalidade antes de passar à tela de Música (TelaMusica). Experimente procurar músicas por título, autor e letra, e use os botões de navegação em diversas ordens, para verificar se o funcionamento está conforme esperado.
Para baixar projeto no seu computador, use este link: ai2.appinventor.mit.edu/?galleryId=5779514622083072

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

O restante do código será discutido no próximo artigo.



Passar à Parte 2





Nenhum comentário:

Postar um comentário