Skip navigation

Category Archives: openframeworks

continuamos revisões e dúvidas durante a primeira parte da sessão. depois entramos no laboratório, onde estamos a desenvolver projectos individuais, colectivos e alguns exercícios a alojar na net.

no pure data focámos noções elementares de programação visual, o que é o som digital, como o sintetisamos e o processamos temporalmente, espacialmente ou espectralmente. ler ficheiros do disco, gerar frequências, ruídos, impulsos, granular inputs,  resintetisar frequências, filtrar microfones, analisar níveis de som, criar processos interactivos. (sessões 11, 12)

ainda analisámos comunicação via rede na própria máquina ou entre várias máquinas, entre o pure data, max e o processing, openframeworks. para tal usamos o protocolo osc através de udp para ser mais rápido, criamos objectos que escrevem e lêem para a rede nos vários ambientes de programação, e por fim criámos programas exemplo que enviam valores de uma aplicação para outra.

introduzimos depois o arduino, e criámos um digitalizador de sensores. fizemos um controlador à base de ldr’s e pot’s numa breadboard, conectamos os sensores ao arduino, e criámos programas que lêem e usam os valores recebidos, gerando sons, sintetisando imagens, controlando estados dinâmicos também com piezos. vimos como o arduino ide é tão semelhante ao processing e o código que usamos também é parecido com java/c. (sessões 13, 14)

ainda fomos usar o arduino como actuador, controlando motores 5v e ventoinhas através dos outputs analógicos conseguimos emitir voltagens variáveis até 5v que controlam directamente ou através de outros componentes motores e actuadores sobre o mundo físico, criando o esboço de uma escultura cinética com led’s, motores e ventoinhas.

por agora já temos umas luzes sobre conceber e implementar interfaces híbridos que recorrem a várias tecnologias, como interfaces à base de computação física usando sensores, arduino, actuadores, outros materiais; interfaces à base de câmara analisando e confrontando as imagens que chegam, destacando posições distintas do fundo, obtendo parâmetros de localização, fazer actuar esses parâmetros; interfaces à base de som, analisando intensidades de frequências e construir listas de valores que fazem oscilar outros algoritmos.

por fim analisamos vários projectos construídos em c++ com o ambiente de programação openframeworks. analisamos a estrutura e funcionamento do compilador, linker, geração de código executável, e expandimos alguns exemplos de processing em c++. primeiro analisamos a programação por objectos, recorrendo a classes que têm variáveis e funções membros, e construímos vários exemplos em c++ que usam partículas, reconhecimento de imagem, som, comunicação por rede, interacções com sons e rato e electrónicas. (sessões 15, 16)

o c++ é mais robusto, um degrau acima na complexidade de escrever código comparado com o processing, mas  com as bibliotecas do openframeworks, torna-se extremamente simples, tal como no processing. a grande diferença é que cada sketch de processing extende a classe base papplet, enquanto que no openframeworks cada aplicação testapp extende a aplicação ofsimpleapp, que engloba a mecânica inicial necessária de uma aplicação c++.

continuamos com a análise de projectos individuais e criação de um laboratório na sala que tenha alguns projectores e câmaras para situações video-interactivas, microfones e colunas, e mesas para construir circuitos entre arduinos e sensores. brevemente mais novidades. boa semana. vejam as plantas, sugiram alternativas,

fizemos revisões de todos os conteúdos das várias linguagens que aprendemos, frisando conceitos chave de programação como variáveis, ciclos for, testes if(){}else{}, classes e objectos, chegar as variáveis a modificar, construir algoritmos base no processing, pd, arduino, openframeworks.

primeiro as noções iniciais de programação exploradas em máquinas de desenhar, onde a posição do rato serve como foco para o lançamento de novos objectos de classes programadas por nós. o sistema de coordenadas cartesiano e o sistema de coordenadas polar. (sessão 2)

primeiras noções de interactividade usando os microfones ligados ao computador, samplando a energia rms sonora, ou um espectro fft que nos dá intensidade por banda de frequência. aplicar os parâmetros do áudio em variáveis que controlam gráficos. noções de classes mais avançadas com os exemplos dos triângulos de som. (sessão 3)

paralelamente, primeiras máquinas lógicas simples, onde a nossa interacção controla um ou mais elementos, e há outros elementos que reagem face à nossa posição, distância, status, etc. os sketches círculos_attack.

depois fomos analisar o tipo de dados pimage e a biblioteca video do processing, que é um tipo de dados que armazena imagens. começamos com os sketches que acedem à informação de cor de cada pixel — criando travelers que oscilam com base nessa cor –, depois ler e scrubbing de video, gravar video e aceder a câmaras. terminamos com acessos mais elaborados à array dos pixels de cada pimage, modificando-os ou lendo-os directamente. (sessão 4)

o próximo tópico foram as partículas e sistemas de partículas, onde elementos simples mantêm variáveis de posição, velocidade, aceleração. a aceleração será o vector que controla a magnitude da deslocação. é também o vector que define a totalidade das forças aplicadas nas partículas. os próximos passos são actualizar a velocidade com a aceleração, actualizar a posição com base na nova velocidade, desenhar o elemento na nova posição. (sessão 5)

introdução ao 3d com noções de coordenadas espaciais, onde está a câmara, onde estão os objectos no espaço, como criar algorimos que gerem formas que se movimentem em três dimensões. (sessão 6)

alguns exemplos mais elaborados de video, como slitscan, delays, texturas em 3d; início do tracking de vídeo: detecção de presença, movimento, background removal, detecção de posição de centróides de blobs, frame differencing, detecção de outras features como caras, mãos, … (sessão 7, 8)

arraylists como recipientes dinâmicos de dados, texto no processing, como ler linhas de texto, separar palavras e espalhá-las espacialmente para desenhar. o sistema esférico (semelhante ao polar, mas em 3d), como desenhar pontos no espaço em forma de esfera e modificá-los com base no som. (sessão 9)

máquinas de estado simples mais avançadas, onde criamos várias classes, obstáculos, bolas, tiros, e todos elas comunicam entre si. cada bola, mesmo as autónomas colidem com os obstáculos, a nossa bola envia tiros que colidem com bolas e obstáculos, e implementamos uma lógica simples quando as bolas em cena terminam, re-iniciamos um novo nível. (sessão 10)

depois vimos puredata, arduino, open frameworks, que ficará como resumo no próximo post.

o curso está na fase laboratorial, estamos activamente a desenvolver projectos individuais e uns projectos colectivos, tirar dúvidas mais específicas em torno de algumas coisas, estamos de antenas apontadas para uma apresentação de projectos de fim de curso que ocorrerá no início de julho.

hoje focamos alguns exemplos de comportamentos de partículas mais avançados com o openframeworks. analisamos partículas em vectores c++, depois extendemos a class das partículas para incorporar forças de atracção e repulsão em função de elementos ou as outras partículas vizinhas, e vamos desembocar em exemplos de enxames. finalizamos com exemplos 3d e interacção imagem/som.

 

vectores c++

 

o primeiro passo é introduzir e saber manipular vector <tipo_de_dados> myVector; um vector é parecido com uma arraylist de java, como analisamos no processing, uma estrutura de dados que pode ser povoada dinamicamente a qualquer altura do código. declaram-se variáveis como tipo vector de um tipo de dados padrão ou por nós definido (entre <>).

 

para inserir elementos, criamos o elemento do tipo que queremos, e chamamos para o vector com a função myVector.push_back( elemento a adicionar ); a qualquer altura podemos saber o número de elementos no vector com myVector.size();, e eliminar elementos com a myVector.erase(), ou limpar todo o vector com myVector.clear();

 

na aplicação sp16_parts_vector inicializamos e gerimos as partículas com estes loops simples:

.. declarar

vector <Part> particulas;

 

.. durante a setup

// inicializar

int numparticulas = 250;

for(int i=0;i<numparticulas;i++){

Part particula;

particula.init(ofRandom(0,ofGetWidth()),ofRandom(0,ofGetHeight()));

particulas.push_back(particula);

}


.. durante a draw

for(int i=0; i<particulas.size();i++){

if(particulas[i].active )

particulas[i].render();

}

sp16-parts-vector

 

 

partículas

 

além da integração simples de novas posições a partir de velocidades, já vimos alguns exemplos onde aplicamos forças às partículas. o motor de movimento será quase sempre idêntico. o loop do sistema de partículas físico será algo como:

1. colocar as forças das partículas a zeros (acc = 0)

2. calcular novas forças para cada partícula ( acc = x )

3. adicionar a força calculada à velocidade ( vel += acc )

4. adicionar a velocidade calculada à posição ( pos += vel )

 

as inovações e coisas mais interessantes começam a surgir quando usamos diferentes formas de calcular forças a actuar nas partículas. primeiro vimos alguns exemplos onde há uma força de atracção global para todas as partículas em direcção ao rato, mas depois cada partícula recebe também uma força de repulsão em relação à posição das vizinhas, o que dá um novo tipo de organicidade ao sistema.

sp16-parts-frcs

 

outro exemplo é ter um campo de forças a actuar nas partículas, consoante a posição da partícula, vai receber um vector de direcção do campo de forças, que forçará padrões de movimento consoante as orientações dos campos de partículas.

 

sp16-vf1

 

enxames

 

os enxames vão ser um caso especial desenvolvido dos anteriores, onde cada partícula vai calcular três ou mais tipos de forças consoante a posição das partículas vizinhas. além da pos, vel, acc, vamos ter floats que pesam cada uma destas forças nas partículas. as forças nos enxames costumam ser: força de separação (pelo menos estar a distância x das outras partículas), força de coesão (força na direcção do centro de massa do enxame de distância y), força de alinhamento (força na direcção actual das restantes partículas a uma distância z).

 

o passo 2 que esboçamos anteriormente vai então desdobrar-se em pequenos sub-passos:

2.  calcular novas forças para cada partícula ( acc = x )

2.1 calcular vector de separação, coesão e alinhamento

2.2 pesar os vectores com os coeficientes das forças e somá-los para obter a acc

 

uma vez realizados estes passos temos as novas forças das partículas. os diferentes comportamentos autónomos que se podemo construir vão ter aqui o ponto-chave, que forças calcular para obter determinado tipo de comportamento em relação aos restantes elementos do enxame.

 

sp16-flocking

 

finalizamos com um exemplo que envolve som, bolas que interagem e colidem entre elas, quando tocam no chão despoletam a reprodução de um fragmento sonoro na posição temporal dependendo do x de cada bola, e de vol e duração dependendo das velocidades de impacto no chão.

 

sp16-2001

sp16-2001a

 

hoje introduzimos o openframeworks. primeiro configuramos os compiladores e as pastas do openframeworks, revemos as noções de programação com objectos em java no processing, e exemplificamos algumas aplicações feitas com o openframeworks.

configuração dos compiladores

as páginas de setup dos compiladores da equipa do openframeworks são claras e devem ser seguidas passo a passo com atenção. nos pc’s instalamos o codeblocks com mingw, e nos mac’s o xcode.

para ‘instalar’ o openframeworks, basta descarregar o ficheiro da nossa plataforma (006 xcode fat para mac e 006 codeblocks fat para windows), descomprimi-lo e mover a pasta para uma directoria de trabalho à nossa escolha. o que é importante é manter a estrutura de directorias das pastas dentro da versão of que descarregam:

of006/addons/
of006/apps/
of006/libs/
of006/other/

os nossos projectos para compilar consistem apenas do src folder. vamos ter de copiar um projecto dos exemplos do openframeworks.

primeiro temos de criar uma directoria de trabalho dentro da estrutura do openframeworks. criei a directoria apps/somdopensamento/. de seguida copiamos os ficheiros da sessão para dentro desta directoria. os ficheiros trazem uma pasta com o nome do projecto, e uma subpasta src que tem o source code. mas ainda faltam os projectos. este passo é importante, só assim os projectos estarão correctamente configurados para compilação. primeiro copiamos um projecto dos exemplos ou dos addons (se usarmos addons), das pastas nativas apps/examples, apps/addons. (em apps/examples/emptyexample, no xcode copia-se openFrameworks.xcodeproj e openFrameworks-Info.plist, no codeblocks copia-se apps/examples/emptyexample/openFrameworks.cbp). agora as nossas pastas dentro de apps/somdopensamento devem ter os projectos duplicados dos exemplos e uma subpasta ‘src’ que tem os ficheiros .h e .cpp onde está declarado o código c++ que tentamos compilar.

para a configuração dos project files nos compiladores, antes de a iniciarem, devem ter algo como

of006/apps/somdopensamento/sp15_circulo/src/main.cpp
of006/apps/somdopensamento/sp15_circulo/src/testApp.cpp
of006/apps/somdopensamento/sp15_circulo/src/testApp.h
of006/apps/somdopensamento/sp15_circulo/openFrameworks.xcodeproj
of006/apps/somdopensamento/sp15_circulo/openFrameworks-Info.plist

(para os pc’s é semelhante, copiamos o ficheiro de projecto codeblocks que está nos exemplos para este local)

abre-se o projecto no xcode ou codeblocks, e na área de browser do projecto, primeiro removemos todos os ficheiros que lá estão, depois introduzimos os ficheiros .h e .cpp que fazem parte do nosso projecto (no mac arrastam-se os ficheiros para a subpasta src no browser do projecto do xcode, no pc seleciona-se o projecto com o botão do lado direito e selecciona-se add files..). após este passo final, devemos ter o projecto configurado e pronto para o próximo passo, que corresponde à compilação do código fonte, corrigir eventuais erros devolvidos pelo compilador, e ligações às várias bibliotecas de código (linker) que se usam (opengl, opencv, rtaudio, freetype, etc, etc). para compilarmos há-de haver uma opção para build and run.

após a compilação deve surgir dentro da pasta do nosso projecto um ficheiro binário executável na nossa plataforma que corre o código exemplo simples da criação de um círculo que segue o rato.

oop (object oriented programming)

semelhante ao primeiro exemplo do processing, fomos passar as variáveis necessárias à criação de um circulo dentro de uma class, com variáveis e funções. em c++ a definição de classes é muito semelhante ao processing, apenas temos de em conta dois passos importantes.

o primeiro é a inclusão do header apenas uma vez, através das directivas #ifndef CIRCULO_H, #define CIRCULO_H e #endif. a outra noção é terminar a declaração da class no header com um ‘;’ após as chavetas ‘}’ que terminam a declaração da classe.

este é o header da class circulo, e a seguir o ficheiro cpp da mesma class.

15-classh

15-classcpp

no testApp.h, o local onde começamos a programar a nossa função, em vez de termos variáveis float posx, posy, rad como no primeiro exemplo, temos agora um objecto circulo do tipo Circulo que definimos nos ficheiros circulo.h e circulo.cpp anteriores.

15-browser-circulo-class

a função update da testApp no ficheiro testApp.cpp chama a go_mouse(); e a draw simplesmente desenha o circulo no ecran

void testApp::draw(){

ofBackground(58,95,83);

circulo.draw();

}

devemos ver isto.

15-circulo

um segundo exemplo cria uma array de objectos Circulo e todos eles chamam a draw e fazem o update das coordenadas em relação ao rato.

15-circulos

o terceiro exemplo mostra como ter um apontador para objectos de um tipo que nós definimos, class Part, no testApp.h declaramos

Part *p; // um pointer para partículas

int num_p; // o número de partículas

e alocamos memória para o apontador na função

void init_n_parts(int num);

que é declarada no ficheiro testApp.cpp desta forma:

void testApp::init_n_parts(int num){ //pedimos memória para o apontador com tamanho para array com num elementos p = new Part[num]; num_p = num; float w = ofGetWidth()/2.0f; float h = ofGetHeight()/2.0f; for(int i=0; i<num;i++){ float x = w+ofRandom(-100,100); float y = h+ofRandom(-100,100); p[i].init(x,y); } } 15-parts

o quarto exemplo é um port do starfield que vimos como exemplo inicial 3d em processing. aqui o mais importante é o uso de um apontador dentro da class Star que aponta para um valor dentro da testApp, que será igual para todas as estrelas. o apontador é inicializado na função testApp::setup() e a partir desse momento podemos escrever o mesmo valor global para cada estrela.

15-starfield

o quinto exemplo é um exemplo de computer vision, onde exploramos algumas técnicas de identificar blobs nas imagens e tentar usar os dados para representar objectos. já é um exemplo mais complexo, onde criamos um objecto class ComputerVision que vai iniciar a câmara e fazer um tracking de blobs usando o addon ofxOpenCv, que coloca à nossa disposição a biblioteca opencv da intel.

15-blosc

instalar, instalar, abrir os programas, correr exemplos teste, primeiras noções de programação.

a primeira aula foi em torno de uma abordagem aos programas que vamos usar ao longo do curso, bem como da análise da bibliografia que nos vai acompanhar, e finalmente uma primeira abordagem às linguagens de programação e principalmente, programação por objectos.

ainda falta instalar os compiladores nas máquinas para ter o openframeworks a funcionar (para os mac’s, instalar o x-code, para os pc’s, instalar o code::blocks), mas já conseguimos abrir o processing, pd e arduino, o que não foi nada mal para primeira sessão.

o tema principal desta primeira sessão foi a análise de um primeiro programa exemplo em processing, que já usa programação por objectos. vimos que cada variável tem um tipo, e que esse tipo pode ser ou um tipo básico de dados (boolean, int, float, char, string…), ou então um tipo/class/objecto por nós preparado, que consiste no diferente re-arranjo de várias variáveis de tipos básicos.

assim, quando na primeira linha do programa declaramos uma variável que se chama circulo do tipo Circulo, estamos já a pressupor que este tipo Circulo está por nós definido algures.

Circulo circulo;

na definição dos objectos vimos que os pontos principais correspondem à criação de variáveis membro que fazem parte desse mesmo objecto, bem como das funções próprias de cada classe. A função principal que é chamada aquando da criação do objecto é o chamado construtor, que instancia variáveis e lhes atribui valores.

o objecto Circulo está definido como:

class Circulo {

float posx, posy, rad;

Circulo(){
rad = random(10,30);
posx = random(rad,width-rad);
posy = random(rad,height-rad);
}

void draw(){

stroke(0);
fill(82,247,195);

ellipse(posx,posy,rad,rad);

}

void reset(){
posx = random(rad,width-rad);
posy = random(rad,height-rad);

}

}

o objecto Circulo tem 3 variáveis fraccionárias, posx, posy, e rad. o construtor do objecto quando é chamado atribui valores aleatórios a cada um destes campos e que têm a ver com a própria variável. o raio, rad, só tem valores de 10 a 30, as posições têm valores entre rad e largura e altura menos rad, para que sejam instanciados dentro da tela. além do construtor do objecto, temos mais duas funções, uma chamada draw e outra chamada reset, ambas do tipo void, porque não devolvem parâmetros nenhuns (por oposição à função random que devolve um parâmetro float quando é chamada)

o objecto circulo do tipo Circulo é criado na função setup(), através desta linha:

circulo = new Circulo(); // criar um novo circulo

depois desta linha ser executada, temos a certeza que a nossa variável circulo tem agora três campos, já com valores atribuídos, valores esses que são aleatórios, ie, calculados através do random(min,max). podemos aceder aos campos para os usar em funções fora da classe através do ‘.’, ex:

circulo.posx = 100; // colocar a variável posx do obj circulo com o valor 100
circulo.rad = (2*frameCount % 50); // atribuir ao raio duas vezes o número de frames que já passaram, entre 0 e 50

circulo.posy = circulo.posy + 1; // novo valor de y é igual ao valor antigo mais 1

ou então, dentro do próprio objecto, não precisamos do ponto para aceder aos valores da função. reparem que na função draw acedemos aos valores actuais posx, posy, e rad sem usarmos o ponto, pois estamos dentro do objecto.

além de aceder às variáveis fora do objecto, podemos aceder às funções:

circulo.draw(); // chamar a função draw do objecto circulo

circulo.reset(); // chamar a função reset do objecto circulo

e pronto, feito o objecto, podemos agora começar a brincar com ele/eles.(eles + à frente).

lembrem-se que no processing a função setup é corrida em primeiro lugar uma única vez, que serve para inicializar janela/som/variáveis/etc. depois é a função draw que faz um loop contínuo infinito até que optemos por terminar o programa com o esc.

esta função draw executa os seguintes passos:

1. background (58,95,83);
2. go_mouse();
3. circulo.draw();

1. apaga sempre a frame anterior e preenche a tela com aquela cor rgb
2. mexe nas coordenadas do círculo em função do pressionamento do botão
3. desenha o círculo com as coordenadas actuais

e faz estes 3 passos continuamente, em loop.

a função go_mouse é que mexe nas coordenadas do círculo, em função das coordenadas do rato e se carregamos no botão.

é definido principalmente com um bloco de código

if (condição v ou f) {
//este código é executado se a condição for V
} else {
//este código é executado se a condição for F
}

e a nossa condição é o mousePressed. se o rato for premido, o círculo tende a ir ter com a posição do rato, se for largado, o circulo afasta-se do rato. usamos um low pass filter para alterar as posições, é um filtro comum e simples que suaviza as transições de valores.

assim, o programa completo para adicionar à classe Circulo criada acima é o seguinte:

/// circulo , processing, som do pensamento

Circulo circulo; //declarar a variável do tipo Circulo

void setup(){
size(500,281); // criar uma janela
circulo = new Circulo(); // criar um novo circulo

//overwrite dos valores das variáveis mouse e mousePressed
mouseX = width/2;
mouseY = height/2;
mousePressed = true;
}

void draw(){

background (58,95,83);
go_mouse();
circulo.draw();

}

void go_mouse(){

if(mousePressed){
// um filtro low pass ao movimento com destino ao rato
float filter = 0.01;
circulo.posx = circulo.posx * (1.0-filter) + mouseX * filter;
circulo.posy = circulo.posy * (1.0-filter) + mouseY * filter;
} else {
//se o rato não premido, afastamo-nos
float filter = 0.01;
// calcular um vector com origem no rato até ao circulo
float dx = circulo.posx – mouseX;
float dy = circulo.posy – mouseY;
// as coordenadas de destino são a posição do círculo + o vector
circulo.posx = circulo.posx * (1.0-filter) + (circulo.posx +dx) * filter;
circulo.posy = circulo.posy * (1.0-filter) + (circulo.posy +dy) * filter;

}

}

outro ponto importante que observámos foi a localidade das variáveis. posso ter duas variáveis filter dentro desta função go_mouse() porque o seu alcance não se toca, estão em níveis distintos, podem ter valores diferentes, só existem dentro das chavetas em que são declaradas.

este programa instancia apenas um círculo, de seguida, vimos um programa que instancia N circulos, e a grande alteração foi inserir os ciclos for e alterar a variável circulo para uma array de variáveis circulos.

este é o segundo programa, mantendo a classe Circulo acima definida.

Circulo circulos[];
int NUM_CIRCULOS = 10;

void setup(){
size(500,281); // criar uma janela

circulos = new Circulo[NUM_CIRCULOS]; // criar espaço na memória para N variáveis do tipo Circulo
for(int i=0; i<NUM_CIRCULOS; i++) {
circulos[i] = new Circulo(); // instanciar cada uma das variáveis Circulo
}

//overwrite dos valores das variáveis mouse e mousePressed
mouseX = width/2;
mouseY = width/2;
mousePressed = true;
}

void draw(){

background (58,95,83);
go_mouse();
for(int i=0; i<NUM_CIRCULOS; i++) {
circulos[i].draw();
}

}

void go_mouse(){

for(int i = 0; i < NUM_CIRCULOS; i++) {

if(mousePressed){
// um filtro low pass ao movimento com destino ao rato
float filter = 0.01;
circulos[i].posx = circulos[i].posx * (1.0-filter) + mouseX * filter;
circulos[i].posy = circulos[i].posy * (1.0-filter) + mouseY * filter;
}
else {
//se o rato não premido, afastamo-nos
float filter = 0.01;
// calcular um vector com origem no rato até ao circulo
float dx = circulos[i].posx – mouseX;
float dy = circulos[i].posy – mouseY;
// as coordenadas de destino são a posição do círculo + o vector
circulos[i].posx = circulos[i].posx * (1.0-filter) + ( circulos[i].posx +dx) * filter;
circulos[i].posy = circulos[i].posy * (1.0-filter) + ( circulos[i].posy +dy) * filter;
}

}

}

as alterações não são muitas, e já podemos ver a riqueza de começar a programar com objectos: agora com o mesmo código que tinhamos usado para apenas um circulo, podemos ter o mesmo comportamento para N circulos.

algumas imagens dos programas com 1 circulo e N circulos

circulo_26

circulos31

no fim da aula o nuno disse-me que com mil circulos a coisa já ficava lenta. pois é. o comando para desenhar um círculo (ellipse no processing) é mais pesado que o comando para desenhar um quadrado. a outra coisa que lhe mostrei foi o mesmo código em c++ no openframeworks, e aí os mil círculos já andavam bem a 60 frames por segundo.

ainda antes de terminar a primeira aula, vimos a funcionar um programa mais avançado, que consistia em duas partes a comunicar por rede através do protocolo OSC (open sound control) no próprio computador. uma parte para analisar blobs no movimento da imagem, a outra parte sintetisa som a partir das coordenadas das blobs. a parte que analisa a imagem pelas blobs, construí há pouco tempo uma aplicação no openframeworks para ter a melhor performance possível na parte da análise de imagem. chama-se blosc e têm o código na pasta da aula, bem como binários para o osx prontos a executar aqui. a segunda parte é um patch em pure data, que recebe na própria máquina, na port 7737, os valores calculados pela aplicação e usa os valores para controlar 10 osciladores que funcionam de acordo com as blobs analisadas.

aqui ficam imagens em funcionamento dos dois programas, e serve já para uma introdução a síntese sonora, sendo que o som e a continuação da análise de tarefas simples de programação é o que nos vai ocupar nos próximos tempos.

blosc-34

blosc-pd-37

até para a semana! leiam se puderem os livros, começem a ler os capítulos introdutórios que têem estas noções sobre variáveis e objectos e ciclos, etc, e tragam dúvidas que encontrem pelo caminho. boas leituras.