Você está na página 1de 45

UNIVERSIDADE FEDERAL DE SANTA MARIA

CENTRO DE TECNOLOGIA
CURSO DE CIÊNCIA DA COMPUTAÇÃO

ANIMAÇÃO DE UM FRACTAL
UTILIZANDO MÚSICA EM PURE DATA

TRABALHO DE GRADUAÇÃO

Cleber Foletto Pedrozo

Santa Maria, RS, Brasil


2011
ANIMAÇÃO DE UM FRACTAL UTILIZANDO
MÚSICA EM PURE DATA

por

Cleber Foletto Pedrozo

Trabalho de Graduação apresentado ao Curso de Ciência da Computação


da Universidade Federal de Santa Maria (UFSM, RS), como requisito
parcial para a obtenção do grau de
Bacharel em Ciência da Computação

Orientador: Profa . Juliana Kaizer Vizzotto (UFSM)

Trabalho de Graduação N. 319


Santa Maria, RS, Brasil
2011
Universidade Federal de Santa Maria
Centro de Tecnologia
Curso de Ciência da Computação

A Comissão Examinadora, abaixo assinada,


aprova o Trabalho de Graduação

ANIMAÇÃO DE UM FRACTAL UTILIZANDO MÚSICA EM


PURE DATA

elaborado por
Cleber Foletto Pedrozo

como requisito parcial para obtenção do grau de


Bacharel em Ciência da Computação

COMISSÃO EXAMINADORA:

Profa . Juliana Kaizer Vizzotto (UFSM)


(Presidente/Orientador)

Profa . Andrea Schwertner Charão (UFSM)

Prof. Eduardo Kessler Piveta(UFSM)

Santa Maria, 15 de Julho de 2011.


RESUMO

Trabalho de Graduação
Curso de Ciência da Computação
Universidade Federal de Santa Maria

ANIMAÇÃO DE UM FRACTAL UTILIZANDO MÚSICA EM PURE DATA


Autor: Cleber Foletto Pedrozo
Orientador: Profa . Juliana Kaizer Vizzotto (UFSM)
Local e data da defesa: Santa Maria, 15 de Julho de 2011.
Este trabalho apresenta um método para animação de fractais a partir de músicas em
Pure Data. A partir do estudo da teoria de fractais e do ambiente de programação voltado
à multimídia chamado Pure Data implementa-se um componente que faz a sincronização
de música com a geração de um fractal de Julia. Usando o Pure Data foi possível extrair
características da música, que são usadas como parâmetros para a animação. Para manter
a característica do Pure Data que executa suas aplicações em tempo real, deparou-se com
um problema de concorrência, onde a CPU é sobrecarregada com a renderização do ví-
deo. Para resolver este problema, é adotada entre algumas soluções a utilização da GPU
para cálculos gráficos. O resultado obtido é um objeto de sincronização entre a estrutura
responsável pela música e a estrutura responsável pela animação. Assim, este trabalho
também dispõe de informações para futuras abordagens de otimização e sincronismo de
fractais e música. Também fornece informações e um breve tutorial sobre implementação
de componentes para Pure Data.

Palavras-chave: Pure Data, GEM, Fractal, Mandelbrot, Julia.


ABSTRACT

Trabalho de Graduação
Undergraduate Program in Computer Science
Universidade Federal de Santa Maria

IMPLEMENTAÇÃO DE INTEGRAÇÃO MUSICA-VÍDEO USANDO FRACTAIS


EM PURE DATA
Author: Cleber Foletto Pedrozo
Advisor: Profa . Juliana Kaizer Vizzotto (UFSM)

This paper presents a method for animating fractals from music in Pure Data software.
From the study of the fractal theory and the programming environment aimed at the media
called Pure Data to implement a component that synchronizes music with the Julia’s
fractal. Using the Pure Data it was possible to extract music caracteristics, which are
used as parameters for the animation. To maintain the characteristc of Pure Data that
runs their applications in real time, was faced with a concurrence problem, where the
CPU is overloaded with rendering the video. To solve this problem, is adopted among
some solutions, to use the GPU for math’s graphics. The result is a synchronization
object between the structure responsible for the music and the structure responsible for
the animation. Thus, this work also has information for future optimization approaches
and synchronism of fractals and music. It also provides information and a brief tutorial
on the implementation of components for Pure Data.

Keywords: Pure Data, GEM, Fractal, Mandelbrot, Julia.


LISTA DE FIGURAS

2.1 Componentes do Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 O código da direita sendo encapsulado no objeto "pd MusicStruct" . . . 15
2.3 Componentes do Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4 Fractal de Mandelbrot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5 Fractal de Julia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.1 Imagem do fractal de Mandelbrol e um fractal de Julia . . . . . . . . . . . . . . . 21


3.2 Imagem de um zoom tirado pelo programa Emndl . . . . . . . . . . . . . . . . . . . 21
3.3 Tela principal do programa escrito em Pd para geração de música fractal 22

4.1 Sequência de fractais de Julia utilizando o primeiro objeto criado na


implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.2 Código de Definições do External . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.3 Código de Renderização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.4 Configuração das funções de callback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.5 Programa em Pd para criação de fractais de Julia. . . . . . . . . . . . . . . . . . . . . 27
4.6 Diagrama onde mostra a necessidade do objeto de sincronização . . . . . 28
4.7 Função principal do Fragment Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.8 Função onde verifica o tempo de escape do pixel . . . . . . . . . . . . . . . . . . . . . 30
4.9 Função para gerar o raio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.10 Vetor Direção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.11 Função para gerar o deslocamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.12 Fractal sendo animado através da música . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5.1 Fractal de Julia gerado por Quatérnios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

A.1 Programa em Pd para criação de fractais de Julia. . . . . . . . . . . . . . . . . . . . . 41


A.2 Estrutura Principal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
A.3 Estrutura da música . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
A.4 Estrutura do shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
LISTA DE ABREVIATURAS E SIGLAS

PD Pure Data
GEM Graphics Environment for Multimedia
CPU Central Processing Unit
GPU Graphics Processing Unit
MIDI Musical Instrument Digital Interface
GLSL GL Shading Language
SUMÁRIO

1 INTRODUÇÃO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2 Contribuições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3 Estrutura do Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2 CONCEITOS E TECNOLOGIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1 Pure Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.1 Componentes visuais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.2 Externals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.3 Recursos do Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.4 GEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2 Fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.1 Números Complexos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.2 Mandelbrot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.3 Fractal de Julia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 Shading Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3 TRABALHOS RELACIONADOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1 Programas sobre Fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 Fractint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.2 Xaos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.3 Emndl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.4 Música Fractal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4 METODOLOGIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.1 Gerando os fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.1.1 Criando externals para Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.2 Utilizando música para gerar o fractal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2.1 Problemas Encontrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.3 Implementação com Fragment Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3.1 Estrutura Utilizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3.2 Objeto de Sincronização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3.3 Movimentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3.4 Programação em Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.4 Utilizando outros fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5 CONCLUSÕES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
REFERÊNCIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
APÊNDICE A CÓDIGOS FONTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
A.1 Implementação em C++ e Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
A.1.1 Códigos em C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
A.1.2 Código em Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2 Implementação em Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2.1 Programação do fragment shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2.2 Programação do external de sincronização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
A.2.3 Programação em Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1 INTRODUÇÃO

A geometria euclidiana representa figuras geométricas simples, como círculos, qua-


drados, polígonos, triângulos, etc. Fractais são imagens que representam uma geometria
não-euclidiana, ou seja, uma geometria irregular e caótica que pode ser dividido em infi-
nitas partes e em diferentes escalas, cada uma das quais semelhantes ao objeto inicial.
Além de ser um conceito matemático, as imagens fractais em geral são interessantes,
chamando a atenção de várias pessoas, inclusive alguns profissionais que trabalham com
arte. Cada fractal é criado a partir de uma fórmula, onde cada pixel sofre um processo
de iteração para verificar sua cor. Utilizando diferentes fórmulas, pode-se criar muitas
imagens interessantes no âmbito artístico.
Para auxiliar esses artistas, surgiram vários programas sobre fractais. Um dos primei-
ros a ficar conhecido é o Fractint (WEGNER, 2011), que possui mais de mil fórmulas de
geração de fractais para visualização. A aplicação de filtros, como passa baixa, que causa
um efeito de borramento, e passa alta, por sua vez realça detalhes nas bordas, são usados
em conjunto com técnicas de coloração para melhorar as imagens adquiridas.
Com popularização dos fractais, começaram a surgir músicas fractais (DIAZ, 1999),
onde a partir de uma imagem de um fractal, gera-se uma música. É necessário duas etapas
para a criação de uma música fractal, a primeira etapa consiste em mapear a posição x e
y de um pixel em uma tabela de sons do tipo MIDI. Após esse procedimento, um algo-
ritmo percorre as bordas de um fractal criando uma música a partir do mapeamento feito
anteriormente. Por ter uma alta complexidade, a execução destas músicas normalmente é
feita por computadores, pois geram sons em intervalos onde os músicos não conseguem
acompanhar.
Atualmente existem diversas linguagens multimídia para editar e processar esse tipo
de som. Algumas dessas linguagens utilizam ambiente gráfico, facilitando a programação
11

para iniciantes. Como exemplos tem-se o Max/MSP (CYCLING74, 2011), Csound (CLE-
MENTS, 2011), Supercollider (MCCARTNEY, 2011) e Pure Data (Pd)(ARMFIELD,
2006).
Para este estudo escolheu-se o Pure Data, que é um ambiente de programação de alto
nível baseado em diagramas de fluxo. O caminho dos dados é visualizado graficamente
através de linhas que ligam os componentes, facilitando a prática de programação. Além
disso, a execução é em tempo real, podendo-se adicionar, remover e alterar componentes
no ambiente em tempo de execução. Os componentes no Pure Data são chamados de
externals, que são funções desenvolvidas em outras linguagens de programação e que
aparecem no ambiente como objetos.

1.1 Objetivos

Neste contexto, este trabalho consiste na criação de um objeto em Pure Data que sin-
cronizará fractais a partir de músicas. Utilizando os atributos da música como parâmetros
é possível criar uma animação em tempo real. Serão apresentadas técnicas usadas para
concorrência e para a movimentação do fractal, assim como técnicas usadas em outros
programas de geração de fractais. Além disso, serão apresentados conceitos de fractais e
uma visão geral sobre o Pure Data.
O objetivo geral deste trabalho é desenvolver um objeto para sincronizar música com
fractal, utilizando o ambiente de programação chamado Pure Data. A idéia é que esse
objeto alterará o fractal usando a freqüência e a amplitude da música como parâmetros.
Assim, os objetivos específicos incluem uma série de pontos:

• Estudar o Pure data, seus objetos e prática de programação;

• Implementar a partir de estudos externals para Pure Data;

• Estudar fractais e números complexos;

• Buscar soluções para problemas de concorrência, como threads em Pure Data e


meios de usar a GPU para renderização;

1.2 Contribuições

A principal contribuição deste trabalho é fornecer um objeto sincronizador de música


e fractal de júlia para Pure Data. Além disso, foi criado um tutorial que ajudará os desen-
12

volvedores iniciais. Este ensina a criar objetos gráficos para Pure. Tal tutorial foi escrito
devido à falta de material sobre o assunto.

1.3 Estrutura do Texto

Este trabalho está estruturado como segue:

• No Capítulo 2 apresenta-se conceitos sobre os assuntos necessários para o desen-


volvimento deste trabalho, tais como Pure Data e seus objetos, números complexos,
fractais e Shading Language.

• No Capítulo 3 mostra-se alguns programas de geração de fractais, música fractal e


animações. Esses trabalhos são relacionados com o estudo proposto.

• No Capítulo 4 segue uma implementação inicial, que mostra os passos realizados


nesse trabalho. Devido a problemas de concorrência partiu-se para uma segunda
etapa de desenvolvimento utilizando a GPU para solucionar o problema.

• No Capítulo 5 apresenta-se um fechamento do trabalho citando o potencial do Pure


Data e a finalidade do trabalho, assim como exemplos de trabalhos futuros a partir
deste.
2 CONCEITOS E TECNOLOGIAS

Neste capítulo são apresentados os conceitos e as tecnologias utilizados para o desen-


volvimento deste trabalho. Primeiramente são vistos os conceitos do ambiente de progra-
mação utilizados. Logo após são apresentados conceitos e duas fórmulas de geração de
fractais, Mandelbrot (WEGNER; TYLER, 1995) e sua variação, Julia (COMMUNICA-
TIONS, 2011). Por fim discute-se Shading Language (ROST, 2009).

2.1 Pure Data

O Pure Data (Pd), inicialmente desenvolvido por Miller Puckette, é um ambiente de


programação multimídia de alto nível. Baseado em diagramas de fluxo, o Pd basicamente
é constituído por objetos funcionais, que são as entidades básicas de programação. Nor-
malmente desenvolvidas em C/C++ e encapsuladas.
A execução dos programas desenvolvidos no ambiente, que pode ser visto com um
interpretador, é em tempo real não havendo necessidade de compilação. Outro fator inte-
ressante é a adição e remoção dos componentes em tempo real. Esse recurso é explorado
em uma nova abordagem chamada Dynamic Patching (MCCARTNEY, 2010), que é o
uso de um programa externo, manipulando livremente os componentes do Pd através de
linhas de comando.
Muitos dos objetos criados são para manipular sons e vídeo, proporcionando uma in-
terface de programação útil aos usuários interessados em criação de música digital e com-
putação gráfica. Inicialmente, a maioria dos recursos para o Pd era voltado à multimídia,
mas existe outro potencial no Pd, que é voltado ao controle de um hardware externo. Este
recurso foi utilizado na robótica como em um projeto desenvolvido por 5VOLTCORE,
onde um braço mecânico é capaz de manipular facas (KIRN, 2007).
14

2.1.1 Componentes visuais

O Pd utiliza vários componentes, dos quais descrevemos na sequência os mais rele-


vantes para a realização deste trabalho. Esses componentes têm entradas que recebem
dados chamados inlets e saídas chamadas outlets, tornando a prática da programação na-
tural e instintiva, pois a rota de dados é mostrada por meio de linhas onde os dados entram
e saem.
A Figura 2.1 ilustra um exemplo de programa simples em Pd. Na parte de cima dos
componentes ficam os inlets, enquanto na parte de baixo estão os outlets. Podem-se notar
os inlets e outlets através das linhas que os ligam.

Figura 2.1: Componentes do Pd

Os componentes mais comuns são:

• Object: principal componente do Pd. Executa funções sempre que algum inlet
recebe uma informação, este gera um callback e executa sua função específica. Os
resultados calculados pelo objeto são enviados através de outlets para os compo-
nentes seguintes. Em alguns casos, esses resultados são enviados diretamente para
um dispositivo de saída.

• Bang: componente do Pd que dispara "ações". Ele executa as funções dos objetos
enviado um sinal para as mesmas;

• Message: Envia uma string que é interpretada pelo objeto como uma entrada. Este
componente é executado através do usuário através do mouse ou um sinal emitido
pelo Bang;

• Number: Análogo à Message, mas para Números;


15

• Toggle: Envia sinal 0 ou 1, funcionado como um interruptor de liga/desliga;

Entre outros objetos gráficos como barra de rolagem vertical e horizontal, gráficos,
vetores, etc.

2.1.2 Externals

Os objetos do Pd foram escritos em outras linguagens como C, C++, Python, entre


outras. Esses objetos são chamados externals. O external usa funções já contidas no
Pd. Para sua integração ao ambiente é necessário apenas que esteja no diretório, este é
carregado na sua inicialização.

2.1.3 Recursos do Pd

É possível no Pd abstrair parte do programa com a finalidade de diminuir poluição


visual e organizar o código. Funciona análogo a colocar uma estrutura feita em Pd para
dentro de um objeto como mostra na Figura 2.2. Uma vez criado o objeto, uma nova
janela de ambiente é aberta, onde poderá adicionar objetos chamados inlets e outlets.
Esses objetos são responsáveis pela comunicação com o resto do programa.

Figura 2.2: O código da direita sendo encapsulado no objeto "pd MusicStruct"


16

Outro recurso interessante no Pd, também usado no encapsulamento, é enviar e rece-


ber informações via mensagens, usando send e receive. Este recurso possibilita estruturas
diferentes comunicarem entre si. Esta forma de comunicação é possível também via rede,
usando dispositivos externos de entrada.
A Figura 2.3 mostra a programação em Pd utilizando recursos de send e receive, eli-
minando a necessidade de criar vários caminhos de dados entre os objetos. No exemplo,
uma freqüência de som é tocada e após 100ms é interrompida, repetindo esse procedi-
mento a cada 1500ms.

Figura 2.3: Componentes do Pd

2.1.4 GEM

O GEM (Graphics Environment for Multimedia) é uma biblioteca gráfica para o Pd ba-
seado em OpenGL, originalmente criado para plataformas win32 por Mark Danks, Gün-
ter Geiger portou o GEM para Linux e James Tittle para OS-X. Atualmente está sendo
gerenciado por Iohannes zmölnig (ZMÖLNIG, 2011). O GEM utiliza OpenGL entre ou-
tros recursos e praticamente todos os comandos de OpenGL já estão implementados para
GEM. Além do GEM existe outra biblioteca gráfica muito parecida chamada PDP (Pure
Data Package). PDP também foi implementado com OpenGL e muito utilizada no Pd
bem como o GEM.
17

2.2 Fractais

2.2.1 Números Complexos

Para entender os fractais utilizados neste trabalho, é apresentada uma introdução sobre
números complexos.
Um número complexo é formado por duas partes, uma real e outra imaginária. A parte

imaginária permite tirar a raiz quadrada de um número negativo, por definição: −1 = i,
ou seja, i2 = −1.
Um número complexo, normalmente referenciado pela letra Z, é a soma de um número
real com, um número real multiplicado por um número imaginário (WEGNER; TYLER,
1995).
Ou seja:
Z = a + bi, onde "a"e "b" são números reais.
Podemos criar 2 eixos para mapear os números complexos, um eixo para a parte real e
outro para a parte imaginária.
O objetivo de estudar números complexos é determinar se um determinado ponto
pertence a um conjunto de Mandelbrot mostrado na Figura 2.4.

Figura 2.4: Fractal de Mandelbrot

2.2.2 Mandelbrot

Para criar o fractal de Mandelbrot, é preciso verificar para cada pixel se ele pertence
ou não ao conjunto. Essa verificação se dá através de uma fórmula, onde os pixels são
testados se eles ultrapassam um raio pré-definido. Normalmente o pixel que pertence ao
conjunto não se distancia muito da posição inicial, formando uma órbita. Para o conjunto
18

de Mandelbrot, o menor raio usado é 2, pois é o menor raio para que o conjunto inteiro
seja calculado (WEGNER; TYLER, 1995). A seqüência de Mandelbrot é definida pela
fórmula:
Zn+1 = Zn2 + c
Onde c é um número complexo que recebe o valor do pixel analisado.
Para verificar se o pixel escapa da órbita, usamos a fórmula da distância do ponto à origem.

d = a2 + b 2
Assumindo "a" como a parte real, e "b" como a parte imaginária .

2.2.3 Fractal de Julia

O conjunto de Julia foi nomeado devido aos estudos do matemático Francês Gaston
Julia onde ficou famoso por volta de 1920 devido ao seu artigo "Mémoire sur l’itération
des fonctions rationnelles", publicado no jornal de matemática em 1918 (COMMUNI-
CATIONS, 2011). Considerando a fórmula de iteração do conjunto de Mandelbrot, usa-se
um número complexo "c" onde varia a cada Zpixel . Gaston Julia modificou a fórmula de
Mandelbrot e manteve "c" constante. Este processo resultou em fractais diferentes para
cada ponto utilizado. O conjunto de Maldelbrot serve então como um catálogo para os
fractais de Julia. Cada ponto pertencente ao fractal de Maldelbrot serve como índice a ser
usado no fractal de Julia. Com isso:
Zn+1 = Zn2 + k
Onde k é um número complexo mantém-se constante para todos os pixels.
A Figura 2.5 mostra o fractal de Mandelbrot e os respectivos fractais de Julia de
acordo com o índice usado na criação do fractal.

2.3 Shading Language

Shader são instruções de máquina que rodam na GPU. Inicialmente a programação era
feita em ASSEMBLY, tornando a programação difícil. Com isso, foram surgindo lingua-
gens de alto nível para a programação em GPU. Como por exemplo HLSL da Microsoft e
GLSL da OpenGL (PASTOR, 2011).
A arquitetura do OpenGL Shading Language é constituída por vertex processor, res-
ponsável por instruções como transformações de vértices e normais, geração e transfor-
mação de coordenadas de texturas e iluminação. Outro processador pertencente é o frag-
19

Figura 2.5: Fractal de Julia

ment processor, responsável pela definição da cor e da coordenada "Z" dos fragmentos
pixels. Atualmente esses processadores estão sendo substituídos por Stream Processor,
cujo processador desempenha ambas as funções. Cada um destes processadores opera em
paralelo aos demais SIMD (Single Instruction Multiple Data) (POZZER, 2009).
Um programa que usa a linguagem shader, utiliza um código GLSL que é compilado
e anexado ao programa principal. É possível ter apenas vários shaders de vértices e de
fragmentos, porém apenas um de cada ativo.
Programas que rodam em GPU são bem mais rápidos dos que rodam em CPU. Isto
porque a arquitetura de uma GPU é baseada em pipeline (um pipeline de um processador
Pentium 4 tem aproximadamente 10 estágios, enquanto o de uma GPU tem algo em torno
de 1000) (PASTOR, 2011).
3 TRABALHOS RELACIONADOS

3.1 Programas sobre Fractais

3.1.1 Fractint

Fractint, foi o primeiro programa que gera fractais a ficar conhecido. Criado em 1988,
escrito em DOS e recebendo o nome por usar números inteiros, devido aos computadores
da época não trabalharem com ponto flutuante (JONES, 2004). O programa conta com
mais de mil fórmulas, onde o usuário pode gerar os fractais e dar vários zooms por uma
seleção da área desejada.
Com a popularização do Fractint, foram aparecendo outros programas para criação
de fractais, como Ultra Fractal, Xaos fractal, Terry W. Gintz’s programs, Mind-Boggling
Fractals, entre outros (JONES, 2004).

3.1.2 Xaos

O Xaos é um programa para geração de fractais conhecido principalmente pelo zoom


iterativo e contínuo, diferente de outros programas onde é necessário selecionar a área
para zoom. O objetivo principal do Xaos é manter o zoom contínuo, onde existe um re-
curso chamado dynamic resolution, que detecta se a CPU está começando a ficar sobrecar-
regada e então automaticamente diminui a resolução do fractal, assim o zoom mantém-se
contínuo (LANGSTON, 2006).
Além dessas características o Xaos possui também vários recursos, coloração, filtros,
efeitos e várias fórmulas de fractais. É possível ver os fractais de Júlia através do fractal
de Mandelbrot como mostra na Figura 3.1. Nesta figura o índice para o fractal de Júlia
está apontado pelo ponteiro do mouse.
21

Figura 3.1: Imagem do fractal de Mandelbrol e um fractal de Julia

3.1.3 Emndl

O Emndl é um programa que possibilita a criação vídeos a partir de várias imagens do


conjunto de Mandelbrot. Utilizando uma função de aproximação, é possível dar infinitos
zooms com a finalidade de criação de um vídeo através de múltiplas imagens. O programa
é escrito em C, C++ e Bash (HEILAND, 2011).
A Figura 3.2 mostra o zoom no conjunto de Mandelbrot centralizado no ponto com-
plexo Z = -0.5988529658460445113700557999169873572638106766467118517477 +
-0.6627873418981974683919856287279365042423603984338094007074 i.

Figura 3.2: Imagem de um zoom tirado pelo programa Emndl


22

3.1.4 Música Fractal

Outro programa desenvolvido por (HEILAND, 2011), é o Z− > Z 2 + C, escrito em


Pure Data como mostra na Figura 3.3. Este programa utiliza a função de Mandelbrot e
seus parâmetros de zoom para criar uma música fractal. O programa necessita um external
chamado "vcf" utilizado para manipular as informações dos parâmetros do fractal.
Os externals em Pd são normalmente criados com a finalidade de auxiliar a progra-
mação no ambiente.

Figura 3.3: Tela principal do programa escrito em Pd para geração de música fractal
4 METODOLOGIA

A metodologia utilizada é específica às fórmulas iterativas de fractais. O fractal usado


é o de Julia, devido a particulariedade que, de acordo com os parâmetros utilizados, gera
um fractal diferente. Para garantir a idéia de movimentação, é necessário que parâmetros
próximos gerem fractais não muito diferentes.
A Figura 4.1 mostra uma seqüência fractais de Julia utilizando incremento de -0.1 nos
parâmetros. Quanto menor o incremento, maior será a semelhança nas imagens, portanto
maior será o detalhe de movimentação.

4.1 Gerando os fractais

4.1.1 Criando externals para Pd

Primeiramente foi implementado um programa que gera o fractal de Maldelbrot em


C++ utilizando OpenGL. Este programa foi desenvolvido a partir da fórmula envolvendo
números complexos vista na seção 2.2. A partir desta etapa foi feita uma modificação no
código para criar o fractal de Julia, recebendo como parâmetros um float para a parte real
e outro para a parte imaginária do plano complexo.
Após o desenvolvimento em C++, houve necessidade de adaptar o código para Pd.
Para isso foi necessário aprender como é criado um external em Pd, onde o tutorial de
(ZMÖLNIG, 2001) foi muito útil apesar de não existir referência no uso de recursos
gráficos para GEM, para que tornasse possível a visualização do fractal. O external de-
senvolvido é dividido em três partes.
A primeira parte consiste nas declarações de variáveis e inicialização. O tipo de ex-
ternal deve ser do tipo "GemShape", classe do Pd responsável para componentes que
serão exibidos em tela. A seguir é criado os inlets no método construtor, assim como a
atribuição das variáveis iniciais. Como mostra no código da Figura 4.2.
24

Figura 4.1: Sequência de fractais de Julia utilizando o primeiro objeto criado na imple-
mentação

A segunda parte do external é a renderização, responsável por desenhar o fractal na


tela do GEM e percorrer todos os pixels definindo a cor de cada um. Essa função é
chamada a todo o instante (definido externamente pelo objeto gemhead) e deverá receber
como parâmetro um ponteiro de estados do GEM. Como mostra no código da Figura 4.3
A terceira parte do external é configurar as funções de callback dos inlets. Toda a
vez que algum inlet recebe um parâmetro, ele executa uma função. No caso do exter-
nal criado, as funções de callback servem para mudar as variáveis internas do código.
A primeira função é responsável por configurar cada inlet com sua respectiva função de
callback, como mostra no código da Figura 4.4. Para testar o objeto foi criado um pro-
grama em Pd onde se utiliza uma barra de slide vertical e outra horizontal para simular o
plano complexo. Cada barra varia em um intervalo [-1,1] e envia a informação através de
mensagens como mostra na Figura 4.5.
25

/ / .H
c l a s s GEM_EXTERN f r a c t a l : p u b l i c GemShape
{
CPPEXTERN_HEADER( f r a c t a l , GemShape )
...

/ / . CPP
/ / definindo quantos i n l e t s o external vai t e r
CPPEXTERN_NEW_WITH_THREE_ARGS( f r a c t a l ,
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 1 , u s a d o p e l o GEM
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 2 , r e c e b e k i m a g i n á r i o
t _ f l o a t a r g , A_DEFFLOAT ) ; / / i n l e t 3 , r e c e b e k r e a l
/ / método c o n s t r u t o r
f r a c t a l : : f r a c t a l ( t _ f l o a t a r g r , t _ f l o a t a r g Ki , t _ f l o a t a r g Kr )
: arg1 ( r ) , Kimag ( Ki ) , K r e a l ( Kr )
{
L _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd ,
&s _ f l o a t , gensym ( " i n L " ) ) ;
R _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd ,
&s _ f l o a t , gensym ( " inR " ) ) ;
}

Figura 4.2: Código de Definições do External

v o i d f r a c t a l : : r e n d e r ( GemState ∗ s t a t e )
{
/ / desenha f r a c t a l
}

Figura 4.3: Código de Renderização

4.2 Utilizando música para gerar o fractal

Após a implementação do external, foi utilizada uma estrutura de leitura da música.


Essa estrutura é composta por alguns objetos principais e alguns objetos complementares
como a message "start", que dá início à música. O objeto do Pd chamado "oggread" é
responsável pela leitura de uma música com extensão ogg, esse manda a stream da música
para o objeto "sigmud", responsável por enviar uma nota MIDI. Foi então utilizado o
objeto "mtof", responsável por transformar a nota MIDI em frequência. Outro objeto
importante é o "vu", uma barra vertical que recebe o sinal de frequência e obtêm-se a
amplitude alcançada pela nota. Esses dados, a frequência e a amplitude, são usados como
parâmetros para a criação do fractal de Júlia.
26

/ / c o n f i g u r a r os métodos dos i n l e t s
void f r a c t a l : : o b j _ s e t u p C a l l b a c k ( t _ c l a s s ∗ c l a s s P t r )
{
class_addmethod ( c l a s s P t r , r e i n t e r p r e t _ c a s t <t_method >
(& f r a c t a l : : ChangeARG2Callback ) , gensym ( " i n L " ) , A_FLOAT , A_NULL ) ;

class_addmethod ( c l a s s P t r , r e i n t e r p r e t _ c a s t <t_method >


(& f r a c t a l : : ChangeARG1Callback ) , gensym ( " inR " ) , A_FLOAT , A_NULL ) ;
}
/ / f u n ç õ e s de c a l l b a c k
v o i d f r a c t a l : : ChangeARG1Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG1 ( v a l o r ) ;
}

v o i d f r a c t a l : : ChangeARG2Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG2 ( v a l o r ) ;
}
/ / funções executadas pela callback , a t u a l i z a o v a l o r das v a r i á v e i s
v o i d f r a c t a l : : ChangeARG1 ( f l o a t v a l o r )
{
Kimag = s i z e ;
setModified ( ) ;
}
v o i d f r a c t a l : : ChangeARG2 ( f l o a t v a l o r )
{
Kreal = s i z e ;
setModified ( ) ;
}

Figura 4.4: Configuração das funções de callback

4.2.1 Problemas Encontrados

A janela padrão do GEM possui um tamanho de 500 x 500 pixels. Como cada pixel é
testado aproximadamente 140 vezes para verificar se escapa de sua órbita, foi detectado
um problema na concorrência da renderização do fractal e a música. Este resultou em uma
interrupção constante na execução da música. O problema está basicamente relacionado
à grande quantidade de cálculos necessários para renderizar cada pixel. Foram estudadas
diversas possibilidades para resolver o problema, entre elas:

• Threads - Foi realizado estudo de como implementar threads em um external, porém


quando implementado, não foram obtidas melhoras significativas.

• Dynamic Patching - A idéia principal do dynamic patching é criar um programa


externo ao Pd que fosse responsável pelos cálculos, e então passar os resultados
ao external. Não chegou a ser implementado, pois os cálculos para a CPU iriam
27

Figura 4.5: Programa em Pd para criação de fractais de Julia

continuar os mesmos.

• Fragment shader - Usar a GPU para os cálculos do fractal, pois fragment shader
utiliza o pipeline da placa de vídeo para os cálculos dos pixels, pois cada pixel é
calculado em paralelo e transformado em uma textura, deixando a CPU rodando a
música e outros cálculos.

4.3 Implementação com Fragment Shader

4.3.1 Estrutura Utilizada

Para resolver o problema de concorrência, foi utilizado o recurso de fragment shader,


onde utiliza recursos da GPU para os cálculos do fractal. A Figura 4.6 mostra o diagrama
lógico que foi utilizado. A primeira parte do diagrama é responsável pela execução da
música e seleção da frequência e amplitude. Os parâmetros são repassados para um ex-
ternal de sincronização. Este external calcula qual será o raio e o ponto complexo a ser
repassado à estrutura shader. Esta estrutura é responsável em ler e em executar um ar-
quivo externo de fragmentos chamado "fractal.frag" e então criar a textura do fractal que
será mostrada pelo GEM.
Devido o fragment shader ser totalmente paralelizável, é necessário que a definição
28

Figura 4.6: Diagrama onde mostra a necessidade do objeto de sincronização

da cor de cada pixel seja independente dos demais, ou seja, cada pixel a ser calculado
executa o código escrito em GLSL do arquivo "fractal.frag" paralelamente.
A função criada detecta a coordenada do pixel corrente, chamando a função "isInside",
onde verifica o tempo de escape do pixel guardando a informação na variável "inside".
Caso a variável tenha um valor -1, o pixel é definido apenas com base no ponto complexo,
pois ele pertence ao conjunto de Júlia. Entretanto se a variável não for -1, a cor do pixel
é definida com base no tempo de escape, conforme Figura 4.7, onde mostra a função
principal do código em GLSL.
A função descrita na Figura 4.8 mostra a função utilizada para testar a órbita de escape
do pixel corrente. O pixel é testado por um número pré-definido de iterações através da
variável "MaxIterations", retornando "n" onde representa o tempo de escape do pixel. As
variáveis "radius", "cim" e "creal", são definidas externamente pelas variáveis "uniform
float".
29

v o i d main ( )
{
vec2 p o s i t i o n = gl_FragCoord ;
int inside= isInside ( position . x , position . y );
i f ( i n s i d e ==−1)
{
g l _ F r a g C o l o r = v e c 4 ( cim ∗ 2 / 3 , c r e a l ∗ 2 / 3 , ( cim+ c r e a l ) , 1 . 0 ) ;
}
else
{
gl_FragColor
= v e c 4 ( ( f l o a t ) ( cim+ c r e a l ) ∗ i n s i d e ∗ 2 / M a x I t e r a t i o n s + 0 . 1 ,
( f l o a t ) i n s i d e ∗2/ MaxIterations +0.2 ,
( f l o a t ) i n s i d e ∗2/ MaxIterations +0.4 ,1);
}
}

Figura 4.7: Função principal do Fragment Shader

4.3.2 Objeto de Sincronização

Foi criado um external em Pd para sincronizar a música com o fractal. Esse objeto
guarda o estado atual e utiliza para criar um novo estado, que é definido como um fractal
de Júlia criado a partir de um ponto complexo e um raio. A música quando é executada,
envia como parâmetros para o objeto, a amplitude e a frequência da nota musical. Com
esses parâmetros, o objeto é capaz de calcular o próximo fractal a ser criado, assim como
o seu tamanho. Este procedimento, quando bem configurado, sincronizará a música e o
fractal.

4.3.3 Movimentação

Para dar efeito de movimentação do fractal foram utilizadas duas técnicas, a primeira
é mudar o raio de acordo com a diferença de amplitude, este passo aproximará ou afastará
o fractal. Foi então criada uma função para gerar o raio:
Existem algumas observações sobre essa função:

• O objeto recebe como parâmetro a estrutura que contêm informações do objeto,


como os inlets e outlets, assim como as variáveis guardadas para referências futuras;

• a função verifica se amplitude atual for maior que a anterior e se essa mudança é
significativa. Então o raio será aumentado;

• Se não houver amplitude maior que a anterior, o raio diminui;


30

u n i f o r m f l o a t cim , c r e a l , r a d i u s ;
int MaxIterations = 140;
int isInside ( int x , int y)
{
f l o a t MinRe , MaxRe , MinIm , MaxIm ,
Re_factor , Im_factor ,
Z_re , Z_im , c_im , c _ r e ,
Z_re2 , Z_im2 ;
i n t HEIGHT = 5 0 0 ;
i n t WIDTH = 5 0 0 ;
int n ;
MinRe = ( f l o a t )− r a d i u s ;
MaxRe = ( f l o a t ) r a d i u s ;
MinIm = ( f l o a t )− r a d i u s ;
MaxIm = ( f l o a t ) r a d i u s ;
R e _ f a c t o r = ( MaxRe−MinRe ) / ( WIDTH− 1 ) ;
I m _ f a c t o r = ( MaxIm−MinIm ) / ( HEIGHT− 1 ) ;

c_im = MaxIm − y ∗ I m _ f a c t o r ;
c _ r e = MinRe + x ∗ R e _ f a c t o r ;
Z_re = c _ r e ;
Z_im = c_im ;
f o r ( n = 0 ; n< M a x I t e r a t i o n s ; ++n )
{
Z_re2 = Z_re ∗ Z_re ;
Z_im2 = Z_im∗Z_im ;
i f ( Z _ r e 2 + Z_im2 > 4 )
{
return n ;
}
Z_im = 2∗ Z _ r e ∗Z_im + cim ;
Z _ r e = Z _ r e 2 − Z_im2 + c r e a l ;
}
r e t u r n −1;
}

Figura 4.8: Função onde verifica o tempo de escape do pixel

• No final da função atribui-se um valor ao raio. Este valor sofre um ajuste, para não
deixar o raio zerar no caso da amplitude ser nula;

Outra técnica utilizada na movimentação é baseada na função de iteração utilizada na


criação do fractal. Há uma semelhança visual no fractal de Julia com pontos complexos
"k" próximo, como explicado anteriormente. A partir desta ideia, foi criada uma função
para alterar o ponto complexo usado na criação do fractal.
Primeiramente foi criada uma função que gera uma direção aleatória para o ponto e
este se desloca no plano complexo. O deslocamento se dá com uma velocidade que é
calculada com base na diferença de frequência, quanto maior a diferença, maior será a
velocidade. Outro detalhe desta função é quando atinge um limite, quando isso acon-
31

void g e r a r _ r a i o ( t _ m f r a c ∗x )
{
/ / s e v i e r uma a m p l i t u d e m a i o r que a a t u a l , e s e e s s a a m p l i t u d e .
/ / f o r s i g n i f i c a t i v a e n t ã o o r a i o aumenta r á p i d o
i f ( x−>Amp − x−>AmpAnt >TOLERANCIA)
{
/ / r a i o aumenta rápido , c a i devagar , p a r a dar maior e f e i t o p a r a
/ / amplitudes a l t a s ;
x−>AmpAnt +=INCREMENTO ;
}
x−>AmpAnt −= DECREMENTO;
/ / O a j u s t e do r a i o s e r v e p a r a a j u s t a r o tamanho do f r a c t a l
/ / sem a a p l i c a ç ã o da a m p l i t u d e
x−> r a d i u s = x−>AmpAnt / DIV + AJUSTE_DO_RAIO ;
o u t l e t _ f l o a t ( x−>R a d i u s _ o u t , x−> r a d i u s ) ;
}

Figura 4.9: Função para gerar o raio

tece, o sentido do vetor inverte e aumenta o deslocamento. Os limites são estabelecidos


para mostrar fractais mais interessantes, o que não ocorre quando o módulo de algum
parâmetro é muito alto.
Entretanto surgiram alguns problemas com esta abordagem, um dos problemas é que
algumas vezes o vetor direção fica nulo, pois foi gerado um valor para o eixo real e outro
para o eixo imaginário, variando entre [-1,1]. Para resolver este problema foi analisada a
possibilidade de criar um laço while para gerar os valores enquanto a direção não fosse
(0,0). Neste caso haveria o problema de espera ocupada, onde a música em um determi-
nado tempo não executa. Outro problema encontrado foi quando o ponto complexo atinge
uma borda, então o sentido é invertido, mas essa solução é valida por pouco tempo, pois
logo o sentido tende a atingir a borda novamente.
Tendo em vista esses problemas, surgiu a idéia de trabalhar com coordenadas polares.
A partir de um radiano gerado aleatoriamente é possível definir a direção de deslocamento
do ponto. Para simplificar a solução, pois existem apenas oito direções possíveis, foi
criado um vetor que guarda tais posições. A escolha da posição é gerada aleatoriamente
usando o índice do vetor. A Figura 4.10 mostra a lógica das direções usadas pelo vetor.

4.3.4 Programação em Pd

Com a finalidade de solucionar o problema das bordas, quando o ponto chega em um


dos limites, então, por um determinado tempo gera-se direções opostas à borda. Essa
abordagem gera uma animação mais contínua do fractal, resultando na seguinte função:
32

Figura 4.10: Vetor Direção

A primeira parte da função calcula a velocidade que irá assumir, levando em conside-
ração a diferença de frequência. A primeira verificação é em relação a variável "count".
Esta variável guarda o "tempo" que o ponto tem limitações na direção. Durante este
tempo, o vetor direção irá ser gerado aleatoriamente entre as direções que são opostas
a borda que foi atingida. Quando o contador é zerado, todas as direções ficam disponí-
veis novamente. No final da função é feita a verificação se alguma borda foi atingida.
Esta borda esta definida pela constante "LIMITE", onde por padrão foi definida em 0.9, o
tempo de retorno é definido pela variável "RETORNA", que por padrão é 10;
A Figura 4.12 mostra a sincronização da música com o fractal utilizando as soluções
vistas no presente trabalho. Foi obtido uma animação dinâmica quando implementado
essa nova abordagem.
33

void g e r a r _ d e s l o c a m e n t o ( t _ m f r a c ∗x )
{
float d;
int r ;
d=x−>F r e q − x−>F r e q A n t ; / / lim 1
d=d / DIV_FREQ ; // _______
d=d ∗ d ; // |0 1 2|
x−>s p e e d =d ; / / lim 4 | 7 P 3 | lim 2
s r a n d ( t i m e (NULL ) ) ; // |6 5 4|
i f ( x−>c o u n t ) // −−−−−−−
{ // lim 3
s w i t c h ( x−>l i m ) {
c a s e 1 : / / g e r a 4 , 5 ou 6
r = ( i n t ) r a n d ()%3 + 4 ;
break ;
c a s e 2 : / / g e r a 6 , 7 ou 0
r =( i n t ) rand ()%3+6;
i f ( r ==8) r = 0 ;
break ;
c a s e 3 : / / g e r a 0 , 1 ou 2
r =( i n t ) rand ()%3;
break ;
c a s e 4 : / / g e r a 2 , 3 ou 4
r = ( i n t ) r a n d ()%3 + 2 ;
break ;
}
} e l s e r =( i n t ) rand ()%8;
x−> d e s l x = x−> d i r e c a o [ r ] [ 0 ] ;
x−> d e s l y = x−> d i r e c a o [ r ] [ 1 ] ;
i f ( x−>c_im >LIMITE ) {x−>l i m = 1 ; x−>c o u n t = RETORNA; }
i f ( x−> c _ r e a l >LIMITE ) {x−>l i m = 2 ; x−>c o u n t = RETORNA; }
i f ( x−>c_im<−LIMITE ) {x−>l i m = 3 ; x−>c o u n t = RETORNA; }
i f ( x−> c _ r e a l <−LIMITE ) { x−>l i m = 4 ; x−>c o u n t = RETORNA; }
x−>c o u n t −−;
}

Figura 4.11: Função para gerar o deslocamento

4.4 Utilizando outros fractais

Para utilização de fractais que possuem fórmulas fixas, a animação deve ser voltada à
transformações e aplicação de efeitos na textura do fractal. A partir da textura criada pelo
shader é possível aplicar efeitos e filtros à essa textura antes de mostrar na tela. Esses
efeitos devem ser sincronizados pela música.
34

Figura 4.12: Fractal sendo animado através da música


5 CONCLUSÕES

O Pure Data é um ambiente de desenvolvimento com um grande potencial, sempre


tentando se atualizar com as novas tecnologias com a ajuda da comunidade, entretanto não
é muito conhecido. Muitos artistas musicais e visuais utilizam o ambiente devido à grande
variedade de recursos de seus interesses e a facilidade de programação no ambiente.
Nesse trabalho foi criado um objeto para Pure Data que anima um fractal a partir
de uma música. No decorrer do trabalho foram encontradas várias dificuldades devido,
primeiramente, a falta de referências sobre o desenvolvimento de objetos gráficos no Pure
Dara. Na questão de desempenho, foi visto que algumas vezes a solução não está na
técnica de programação, mas sim na arquitetura utilizada e em recursos de hardware.
Utilizar a GPU como solução no problema de concorrência mostrou-se muito efici-
ente. Esta solução foi adotada a fim de manter a característica de tempo real na aplicação.
O trabalho seguirá em desenvolvimento e tem como proposta de trabalhos futuros:

• Implementar um modelo dinâmico para a função de iteração do fractal

• Realizar melhorias na sincronização da música com o fractal

• Realizar melhorias na coloração do fractais, utilizando multi camadas de cores


como apresentado em (DRAVES, 2003)

• Publicação do trabalho e do tutorial

• Utilizar Quatérnios para gerar o fractal

A figura 5.1 mostra um exemplo do fractal de Julia gerada através de quatérnios.


36

Figura 5.1: Fractal de Julia gerado por Quatérnios


37

REFERÊNCIAS

ARMFIELD, A. Pure Data: an introduction. Sound On Sound : Est. 1985,


[S.l.], 2006. Disponível em http://www.soundonsound.com/sos/aug06/
articles/puredata_0806.htm. Acesso em: Abril de 2011.

CLEMENTS, J. csounds. Disponível em http://www.csounds.com/. Acesso em:


Julho de 2011.

COMMUNICATIONS, S. Gaston Julia. Disponível em http://www.nndb.com/


people/055/000108728/. Acesso em: Maio de 2011.

CYCLING74. Max MSP. Disponível em http://cycling74.com. Acesso em: Ju-


lho de 2011.

DIAZ, G. Fractals and Music. Disponível em http://emusician.com/mag/


emusic_fractals_music/. Acesso em: Junho de 2011.

DRAVES, S. The Fractal Flame Algorithm. SpotWorks, [S.l.], 2003. Disponível em


http://www.scribd.com/doc/47870748/Fractal-Flame-Algorithm.
Acesso em: Junho de 2011.

HEILAND, C. emndl. Disponível em http://claudiusmaximus.goto10.org/


cm/2011-04-23_emndl-0.1_released.html. Acesso em: Junho de 2011.

JONES, D. Fractal Programs. Disponível em https://www.fractalus.com/


fractal-art-faq/faq06.html. Acesso em: Junho de 2011.

KIRN, P. Robotic Knives Patched in Pd, Circuit-Bent Graphics Cards.


Disponível em http://createdigitalmusic.com/2007/08/
38

robotic-knives-patched-in-pd-circuit-bent-graphics-cards/.
Acesso em: Junho de 2011.

LANGSTON, J. Xaos. Disponível em http://xaos.sourceforge.net/. Acesso


em: Junho de 2011.

MCCARTNEY, J. pyata, programando o pure data com python. Disponível em


http://jeraman.info/tag/dynamic-patching/. Acesso em: Julho de
2011.

MCCARTNEY, J. SuperCollider. Disponível em http://supercollider.


sourceforge.net/. Acesso em: Julho de 2011.

PASTOR, T. D. Introducao aos Shaders. Disponível em http:


//www.pontov.com.br/site/index.php/xna/70-shaders/
250-introducao-a-shaders. Acesso em: Junho de 2011.

POZZER, C. T. OpenGL Shading Language. Disponível em http://www-usr.


inf.ufsm.br/~pozzer/disciplinas/cga_15_opengl_shading.pdf.
Acesso em: Junho de 2011.

ROST, J. J. OpenGL Shading Language. [S.l.]: Addison-Wesley Professional, 2009.

WEGNER, T. Fractint. Disponível em http://www.fractint.org/. Acesso em:


Julho de 2011.

WEGNER, T.; TYLER, B. Criando Fractais. [S.l.]: Axcel Books do Brasil Editora,
1995.

ZMÖLNIG, J. m. HOW TO write an External for puredata. Disponível em http:


//iem.at/pd/externals-HOWTO/. Acesso em: Março de 2011.

ZMÖLNIG, J. m. Pure Data. Disponível em http://gem.iem.at/. Acesso em:


Maio de 2011.
APÊNDICE A CÓDIGOS FONTE

A.1 Implementação em C++ e Pd

A.1.1 Códigos em C++

Listing A.1: Código de Implementação


# include " f r a c t a l . h"
# include " Base / GemState . h "
# include <GL / g l u t . h>
# include < s t d i o . h>
# include <math . h>

# d e f i n e WIDTH 500
# d e f i n e HEIGHT 500
# d e f i n e M a x I t e r a t i o n s 30

CPPEXTERN_NEW_WITH_THREE_ARGS
( fractal ,
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 1 , u s a d o p e l o GEM
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 2 , r e c e b e k i m a g i n á r i o
t _ f l o a t a r g , A_DEFFLOAT ) ; / / i n l e t 3 , r e c e b e k r e a l

fractal :: f r a c t a l ( t _ f l o a t a r g r , t _ f l o a t a r g Ki , t _ f l o a t a r g Kr )
: arg1 ( r ) , Kimag ( Ki ) , K r e a l ( Kr )
{
L _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd , &s _ f l o a t , gensym ( " i n L " ) ) ;
R _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd , &s _ f l o a t , gensym ( " inR " ) ) ;
}

fractal :: ~ fractal ()
{ }

v o i d f r a c t a l : : r e n d e r ( GemState ∗ s t a t e )
{
/ / a j u s t e da c â m e r a p a r a a v i s u a l i z a ç ã o do f r a c t a l
g l C l e a r ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
g l M a t r i x M o d e ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
g l u O r t h o 2 D ( 0 , WIDTH, 0 , HEIGHT ) ;
g l M a t r i x M o d e (GL_MODELVIEW ) ;
glLoadIdentity ( ) ;

/ / i n i c i a l i z a ç ã o das v a r i á v e i s
MinRe = −2; MaxRe = 2 . 0 ; MinIm = −2;
MaxIm = MinIm + ( MaxRe−MinRe )∗HEIGHT / WIDTH ;
R e _ f a c t o r = ( MaxRe−MinRe ) / ( WIDTH−1);
I m _ f a c t o r = ( MaxIm−MinIm ) / ( HEIGHT−1);
/ / l a ç o s que p e r c o r r e t o d o s o s p i x e l s
f o r ( y = 0 ; y<HEIGHT ; y ++)
{
c_im = MaxIm − y∗ I m _ f a c t o r ;
f o r ( x = 0 ; x<WIDTH ; x ++)
{
c _ r e = MinRe + x∗ R e _ f a c t o r ;
Z_re = c _ r e ;
Z_im = c_im ;
i s I n s i d e = true ;
/ / p a r a c a d a p i x e l v e r i f i c a s e nao e s c a p a do r a i o 2
f o r ( n = 0 ; n< M a x I t e r a t i o n s ; ++n )
{
/ / d= r a i z ( a ^2 + b ^ 2 )
/ / e l e v a ambos o s t e r m o s ao q u a d r a d o p a r a a c e l e r a r o s c á l c u l o s
/ / d ^2= a ^2 + b ^2
/ / v e r i f i c a s e a d ^2 > r ^2
Z _ r e 2 = Z _ r e∗Z _ r e ;
Z_im2 = Z_im∗Z_im ;
i f ( Z _ r e 2 + Z_im2 > 4 )
{
/ / s e e s c a p o u do r a i o e s c o l h e a c o r do p i x e l de a c o r d o com o n
40

isInside = false ;
glColor3f (( float ) n ∗2/ M a x I t e r a t i o n s ∗ K r e a l + 0 . 2 ,
( float ) n ∗2/ M a x I t e r a t i o n s ∗ K r e a l + 0 . 2 ,
( float ) ( n ∗2/ M a x I t e r a t i o n s )∗ Kimag + 0 . 3 ) ;
break ;
}
/ / s e nao e s c a p o u do r a i o c a l c u l a o p r ó x i m o Z
Z_im = 2∗ Z _ r e∗Z_im + ( d o u b l e ) ( K r e a l ) ;
Z _ r e = Z _ r e 2 − Z_im2 + ( d o u b l e ) ( Kimag ) ;
}
i f ( ! i s I n s i d e ){
/ / p i n t a o p i x e l c a s o t e n h a s a í d o de ó r b i t a
g l B e g i n ( GL_POINTS ) ;
glVertex2f (x , y );
glEnd ( ) ;
}
}
}
}

/ / f u n ç õ e s de c a l l b a c k
v o i d f r a c t a l : : ChangeARG2Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG2 ( v a l o r ) ;
}

v o i d f r a c t a l : : ChangeARG1Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG1 ( v a l o r ) ;
}

/ / funções executadas pela callback , a t u a l i z a o v a l o r das v a r i á v e i s


v o i d f r a c t a l : : ChangeARG2 ( f l o a t v a l o r )
{
Kreal = s i z e ;
setModified ( ) ;
}

v o i d f r a c t a l : : ChangeARG1 ( f l o a t v a l o r )
{
Kimag = s i z e ;
setModified ( ) ;
}

/ / c o n f i g u r a r os métodos dos i n l e t s
void f r a c t a l : : o b j _ s e t u p C a l l b a c k ( t _ c l a s s ∗ c l a s s P t r )
{
c l a s s _ a d d m e t h o d ( c l a s s P t r , r e i n t e r p r e t _ c a s t < t _ m e t h o d >(& f r a c t a l : : ChangeARG2Callback ) ,
gensym ( " i n L " ) , A_FLOAT , A_NULL ) ;
c l a s s _ a d d m e t h o d ( c l a s s P t r , r e i n t e r p r e t _ c a s t < t _ m e t h o d >(& f r a c t a l : : ChangeARG1Callback ) ,
gensym ( " inR " ) , A_FLOAT , A_NULL ) ;
}

Listing A.2: Header


/∗
MUSIC2FRACTAL
by C l e b e r F o l e t t o P e d r o z o

c l e b e r p e d r o z o @ g m a i l . com

T h i s i s a i m p l e m e n t a t i o n t e s t , i t s an e x t e r n a l f o r p u r e d a t a w i t c h r e c e i v e 2 f l o a t s and f o r e a c h p i x e l
i s made m a t h s t o d e t e c t i f t h e p i x e l i s i n s i d e o f f r a c t a l .
∗/

# i f n d e f INCLUDE_fractal_H_
# d e f i n e INCLUDE_fractal_H_

# i n c l u d e " Base / GemShape . h "


# i n c l u d e < s t r i n g . h>

c l a s s GEM_EXTERN f r a c t a l : p u b l i c GemShape
{
CPPEXTERN_HEADER( f r a c t a l , GemShape )
public :
f r a c t a l ( t _ f l o a t a r g a r g 1 , t _ f l o a t a r g Kimag , t _ f l o a t a r g K r e a l ) ;
virtual ~ fractal ( ) ;
private :
// variáveis
t_inlet ∗L _ i n l e t ,∗ R _ i n l e t ;
f l o a t a r g 1 , Kimag , K r e a l ;
d o u b l e MinRe , MaxRe ,
MinIm , MaxIm ,
Re_factor , Im_factor ,
c_im , c _ r e ,
Z_re , Z_re2 ,
Z_im , Z_im2 ;
int x , y , n ;
bool i s I n s i d e ;
/ / funções :
/ / f u n ç ã o que d e s e n h a o f r a c t a l em t e l a
v i r t u a l void r e n d e r ( GemState ∗ s t a t e ) ;
/ / f u n ç õ e s de c a l l b a c k
s t a t i c v o i d ChangeARG2Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r ) ;
s t a t i c v o i d ChangeARG1Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r ) ;
41

/ / f u n ç õ e s chamadas p e l a c a l l b a c k
v o i d ChangeARG2 ( f l o a t v a l o r ) ;
v o i d ChangeARG1 ( f l o a t v a l o r ) ;

};

# endif

A.1.2 Código em Pd

Figura A.1: Programa em Pd para criação de fractais de Julia

A.2 Implementação em Shader

A.2.1 Programação do fragment shader

Listing A.3: Arquivo de fragmento


u n i f o r m f l o a t cim , c r e a l , r a d i u s ;
int MaxIterations = 140;
int isInside ( int x , int y)
{
f l o a t MinRe , MaxRe , MinIm , MaxIm ,
Re_factor , Im_factor ,
Z_re , Z_im , c_im , c _ r e ,
Z_re2 , Z_im2 ;
i n t HEIGHT = 5 0 0 ;
i n t WIDTH = 5 0 0 ;
42

int n ;
MinRe = ( f l o a t )− r a d i u s ;
MaxRe = ( float ) radius ;
MinIm = ( f l o a t )− r a d i u s ;
MaxIm = ( float ) radius ;
Re_factor = ( MaxRe−MinRe ) / ( WIDTH−1);
Im_factor = ( MaxIm−MinIm ) / ( HEIGHT−1);

c_im = MaxIm − y∗ I m _ f a c t o r ;
c _ r e = MinRe + x∗ R e _ f a c t o r ;
Z_re = c _ r e ;
Z_im = c_im ;
f o r ( n = 0 ; n< M a x I t e r a t i o n s ; ++n )
{
Z _ r e 2 = Z _ r e∗Z _ r e ;
Z_im2 = Z_im∗Z_im ;
i f ( Z _ r e 2 + Z_im2 > 4 )
{
return n ;
}
Z_im = 2∗ Z _ r e∗Z_im + cim ;
Z _ r e = Z _ r e 2 − Z_im2 + c r e a l ;
}
r e t u r n −1;
}
v o i d main ( )
{
vec2 p o s i t i o n = gl_FragCoord ;
int inside= isInside ( position . x , position . y );
i f ( i n s i d e ==−1)
{
g l _ F r a g C o l o r = v e c 4 ( cim ∗ 2 / 3 , c r e a l ∗ 2 / 3 , ( cim+ c r e a l ) , 1 . 0 ) ;
}
else
{
gl_FragColor
= v e c 4 ( ( f l o a t ) ( cim+ c r e a l )∗ i n s i d e ∗2/ M a x I t e r a t i o n s + 0 . 1 ,
( f l o a t ) i n s i d e ∗2/ M a x I t e r a t i o n s + 0 . 2 ,
( f l o a t ) i n s i d e ∗2/ M a x I t e r a t i o n s +0.4 ,1);
}
}

A.2.2 Programação do external de sincronização

Listing A.4: External mfrac


# i n c l u d e " m_pd . h "
# i n c l u d e < t i m e . h>
# i n c l u d e < s t d l i b . h>
# i n c l u d e < s y s / t i m e . h>
# d e f i n e RETORNA 10
# d e f i n e AJUSTE_DO_RAIO 1 . 8
# d e f i n e LIMITE 0 . 9
# d e f i n e DIV_FREQ 500
# d e f i n e INCREMENTO 7
# d e f i n e DECREMNTO 4
# d e f i n e TOLERANCIA 2
# d e f i n e DIV 15
s t a t i c t _ c l a s s ∗mfrac_class ;

typedef s t r u c t _mfrac {
t _ o b j e c t x_obj ;
t _ i n t count , lim ;
t _ f l o a t r a d i u s , Amp, Freq , s p e e d , d e s l x , d e s l y ;
t _ f l o a t mod , AmpAnt , FreqAnt , c_im , c _ r e a l , c_imAnt , c _ r e a l A n t ;
t _ o u t l e t ∗c _ o u t , ∗ R a d i u s _ o u t , ∗ c 2 _ o u t ;
int direcao [8][2];
/ / c_out é a saída r e l a t i v o à constante imaginária C,
/ / onde c _ o u t r e p r e s e n t a a p a r t e r e a l e c 2 _ o u t a p a r t e i m a g i n á r i a =>
/ / c= a+ b i ( a= c _ o u t , b= c 2 _ o u t )
} t_mfrac ;

v o i d g e r a r _ d e s l o c a m e n t o ( t _ m f r a c ∗x )
{
float d;
int r ;
d=x−>F r e q − x−>F r e q A n t ; / / lim 1
d=d / DIV_FREQ ; // _______
d=d∗d ; // |0 1 2|
x−>s p e e d =d ; / / lim 4 | 7 P 3 | lim 2
s r a n d ( t i m e (NULL ) ) ; // |6 5 4|
i f ( x−>c o u n t ) // −−−−−−−
{ // lim 3
s w i t c h ( x−>l i m ) {
c a s e 1 : / / g e r a 4 , 5 ou 6
r = ( i n t ) r a n d ()%3 + 4 ;
break ;
c a s e 2 : / / g e r a 6 , 7 ou 0
r =( i n t ) rand ()%3+6;
i f ( r ==8) r = 0 ;
break ;
c a s e 3 : / / g e r a 0 , 1 ou 2
r =( i n t ) rand ()%3;
43

break ;
c a s e 4 : / / g e r a 2 , 3 ou 4
r = ( i n t ) r a n d ()%3 + 2 ;
break ;
}
} e l s e r =( i n t ) rand ()%8;
x−>d e s l x = x−>d i r e c a o [ r ] [ 0 ] ;
x−>d e s l y = x−>d i r e c a o [ r ] [ 1 ] ;
i f ( x−>c_im >LIMITE ) {x−>l i m = 1 ; x−>c o u n t = RETORNA; }
i f ( x−>c _ r e a l >LIMITE ) {x−>l i m = 2 ; x−>c o u n t = RETORNA; }
i f ( x−>c_im<−LIMITE ) {x−>l i m = 3 ; x−>c o u n t = RETORNA; }
i f ( x−>c _ r e a l <−LIMITE ) { x−>l i m = 4 ; x−>c o u n t = RETORNA; }
x−>c o u n t −−;
}
v o i d g e r a r _ r a i o ( t _ m f r a c ∗x )
{
/ / s e v i e r uma a m p l i t u d e m a i o r que a a t u a l , e s e e s s a a m p l i t u d e f o r s i g n i f i c a t i v a e n t a o o r a i o a u m e n t a r a p i d o
i f ( x−>Amp − x−>AmpAnt >TOLERANCIA)
{
/ / r a i o aumenta rapido , c a i devagar , p a r a dar maior e f e i t o p a r a a m p l i t u d e s a l t a s ;
x−>AmpAnt +=INCREMENTO ;
}
x−>AmpAnt −= DECREMENTO;
/ / O a j u s t e do r a i o s e r v e p a r a a j u s t a r o tamanho do f r a c t a l
/ / sem a a p l i c a ç ã o da a m p l i t u d e
x−>r a d i u s = x−>AmpAnt / DIV + AJUSTE_DO_RAIO ;
o u t l e t _ f l o a t ( x−>R a d i u s _ o u t , x−>r a d i u s ) ;
}

v o i d m f r a c _ b a n g ( t _ m f r a c ∗x )
{
/ / gera o vetor deslocamento
gerar_deslocamento (x ) ;
/ / a p l i c a o deslocamento
x−>c_im = ( f l o a t ) ( x−>d e s l y ∗ x−>s p e e d + x−>c_im ) ; / / c_im ;
x−>c _ r e a l = ( f l o a t ) ( x−>d e s l x ∗ x−>s p e e d + x−>c _ r e a l ) ;
/ / g e r a o r a i o que s e r á p a s s a d o ao f r a c t a l
gerar_raio (x );
/ / a l g u m a s v e z e s quando a f r e q u ê n c i a e s t á m u i t o a l t a
/ / e começamos n o v a m e n t e a m ú s i c a a f r e q u ê n c i a c a i r a p i d a m e n t e
/ / a u m e n t a n d o m u i t o o s v a l o r e s do p o n t o complexo
/ / e n t a o s e e l a f o r m a i o r que o LIMITE ( d e f a u l t 1 . 3 ) e n t a o v o l t a a s e r 0
i f ( x−>c _ r e a l >LIMITE | | x−>c _ r e a l < −LIMITE ) x−>c _ r e a l = 0 ;
o u t l e t _ f l o a t ( x−>c _ o u t , x−>c _ r e a l ) ;
i f ( x−>c_im >LIMITE | | x−>c_im < −LIMITE ) x−>c_im= 0 ;
o u t l e t _ f l o a t ( x−>c 2 _ o u t , x−>c_im ) ;

v o i d m f r a c _ n e w f r e q ( t _ m f r a c ∗x , t _ f l o a t a r g f 1 )
{
x−>F r e q A n t =x−>F r e q ;
x−>F r e q = f 1 ;
}

v o i d m f r a c _ n e w A m p l i t u d e ( t _ m f r a c ∗x , t _ f l o a t a r g f 1 )
{
x−>AmpAnt=x−>Amp ;
x−>Amp= f 1 ;
}

v o i d ∗mfrac_new ( t _ s y m b o l ∗s , i n t a r g c , t _ a t o m ∗ a r g v )
{
t _ m f r a c ∗x = ( t _ m f r a c ∗) pd_new ( m f r a c _ c l a s s ) ;
/∗
1 2 3
8 P 4
7 6 5
∗/
x−>d i r e c a o [ 0 ] [ 0 ] = − 1 ; x−>d i r e c a o [ 0 ] [ 1 ] = 1 ;
x−>d i r e c a o [ 1 ] [ 0 ] = 0 ; x−>d i r e c a o [ 1 ] [ 1 ] = 1 ;
x−>d i r e c a o [ 2 ] [ 0 ] = 1 ; x−>d i r e c a o [ 2 ] [ 1 ] = 1 ;
x−>d i r e c a o [ 3 ] [ 0 ] = 1 ; x−>d i r e c a o [ 3 ] [ 1 ] = 0 ;
x−>d i r e c a o [ 4 ] [ 0 ] = 1 ; x−>d i r e c a o [ 4 ] [ 1 ] = − 1 ;
x−>d i r e c a o [ 5 ] [ 0 ] = 0 ; x−>d i r e c a o [ 5 ] [ 1 ] = − 1 ;
x−>d i r e c a o [ 6 ] [ 0 ] = − 1 ; x−>d i r e c a o [ 6 ] [ 1 ] = − 1 ;
x−>d i r e c a o [ 7 ] [ 0 ] = − 1 ; x−>d i r e c a o [ 7 ] [ 1 ] = 0 ;
x−>Amp= 0 ;
x−>AmpAnt = 0 ;
x−>c o u n t = 0 ;
x−>F r e q = 1 0 ;
x−>F r e q A n t = 1 0 0 ;
x−>l i m = 0 ;
x−>d e s l x = 0 ;
x−>d e s l y = 0 ;
x−>s p e e d = 0 . 0 2 1 2 4 ;
x−>c _ r e a l = 0 ;
x−>r a d i u s = 0 . 5 ;
f l o a t i n l e t _ n e w (&x−>x _ o b j , &x−>F r e q ) ;
f l o a t i n l e t _ n e w (&x−>x _ o b j , &x−>Amp ) ;
x−>R a d i u s _ o u t = o u t l e t _ n e w (&x−>x _ o b j , &s _ f l o a t ) ;
x−>c _ o u t = o u t l e t _ n e w (&x−>x _ o b j , &s _ f l o a t ) ;
x−>c 2 _ o u t = o u t l e t _ n e w (&x−>x _ o b j , &s _ f l o a t ) ;
r e t u r n ( v o i d ∗) x ;
}

void mfrac_setup ( void ) {


m f r a c _ c l a s s = c l a s s _ n e w ( gensym ( " m f r a c " ) ,
( t_newmethod ) mfrac_new ,
44

0 , sizeof ( t_mfrac ) ,
CLASS_DEFAULT ,
A_GIMME, 0 ) ;
class_addbang ( mfrac_class , mfrac_bang ) ;
class_addmethod ( mfrac_class ,
( t _ m e t h o d ) m f r a c _ n e w f r e q , gensym ( " f r e q " ) ,
A_DEFFLOAT , 0 ) ;

class_addmethod ( mfrac_class ,
( t _ m e t h o d ) m f r a c _ n e w A m p l i t u d e , gensym ( "Amp" ) ,
A_DEFFLOAT , 0 ) ;
/ / c l a s s _ s e t h e l p s y m b o l ( m f r a c _ c l a s s , gensym ( " h e l p−m f r a c " ) ) ;
}

A.2.3 Programação em Pd

Figura A.2: Estrutura Principal

Figura A.3: Estrutura da música


45

Figura A.4: Estrutura do shader

Você também pode gostar