Brain Dump

Segunda-feira, 22 de Junho de 2009

As batalhas do magenta

Convencer as pessoas de que o magenta existe foi uma batalha, mas certamente não a única batalha pela qual a cor passou. O magenta é uma cor mais sofrida que o flicts; na verdade a própria origem do magenta foi em uma batalha!

Originalmente, a cor #FF00FF era chamada de fúcsia, em homenagem a uma singela florzinha que tem essa cor. Mas em 1859 houve uma sangrenta batalha entre franceses e austríacos, tão intensa que pintou o chão de sangue. Essa batalha aconteceu na cidade italiana de Magenta, e desde então aquele tom da cor de sangue ficou conhecido como magenta.

A batalha mais recente do magenta é contra outra injustiça cometida pelo povo que não conhece física. Dessa vez a abobrinha veio de um designer coreano, que bolou uma caneta-scanner especial para desenhistas. Se você quiser pintar uma maçã com a aparência similar a uma maçã real, basta usar a ponta-scanner da caneta para capturar o tom RGB exato da fruta, e na outra ponta a caneta mistura as proporções exatas de tintas (vermelhas, verdes e azuis) que reproduzem aquele tom. A idéia da caneta até é legal, mas do jeito que foi bolada, não funciona.


O problema da caneta, é claro, são as tintas. Para entender por que elas são um problema, precisamos relembrar a definição de cor do Kandel: "Cor é uma experiência subjetiva relacionada à composição espectral da luz que atinge o olho". Ou seja, segundo essa definição, a única coisa que pode ter cor é luz. Como tinta não é luz, logo tinta não pode ter cor.

A maneira correta de caracterizar uma tinta é através da sua refletância, ou seja, a relação entre luz absorvida e refletida para um dado comprimento de onda. A cor da tinta não depende apenas de suas características intrínsecas, mas também da luz que incide sobre ela.

Você pode fazer um experimento simples para verificar isso. Primeiro pegue dois pedaços de pano, branco e vermelho, e um lightsaber bicolor, azul e vermelho (se você não tem um lightsaber bicolor, eis uma boa desculpa pra comprar um!). Veja agora como a cor do tecido depende da luz incidente:

Luz ambiente (branca)

Luz vermelha

Luz azul

Agora dá pra ver claramente: o tecido "branco" na verdade reflete toda a luz que chega, então ele só é branco quando a luz é branca. Se a luz for vermelha, o tecido fica vermelho, se a luz for azul, o tecido fica azul.

Já o tecido "vermelho", na verdade, absorve todos os comprimentos de onda, menos o vermelho. Tanto faz se a luz é branca ou vermelha, o resultado é o mesmo: só o vermelho é refletido. Já quando a luz é azul, sem componente vermelho nenhum, o resultado é que ele fica com aparência praticamente preta, pois não tem nada pra refletir. O diagrama abaixo mostra o que aconteceu:


Agora fica claro porque a escolha de cores do designer coreano é falha. As tintas que ele escolheu (vermelho, verde e azul) não podem ser misturadas! Vejamos: uma tinta vermelha, na verdade, absorve o verde e azul, refletindo só o vermelho. Uma tinta verde, na verdade, absorve o vermelho e o azul, refletindo só o verde. Se você misturar o vermelho com o verde, a tinta resultante vai absorver o vermelho, o azul e o verde, ou seja, não vai refletir nada. Uma mistura de tintas vermelhas e verdes, em proporções iguais, dá uma tinta preta.

Quem já trocou cartuchos de impressora jato de tinta sabe qual a solução para esse problema. Basta escolher outras cores: amarelo, ciano... e magenta! Essas sim são tintas que podem ser misturadas. Confira: uma tinta magenta, na verdade, absorve o verde. Uma tinta ciano, na verdade, absorve o vermelho. Se você misturar magenta com ciano, o resultado absorve o verde e o vermelho, ou seja, só sobra azul. Tinta magenta com tinta ciano dá tinta azul.


Essas tríades de cores são chamadas de cores primárias. Vermelho, verde e azul são as cores primárias aditivas, aquelas que você usa com emissores de luz, como lâmpadas e LEDs. Ciano, magenta e amarelo são as cores primárias subtrativas, aquelas que você usa com tintas.

Por fim, isso nos leva a mais uma batalha do magenta. "Peraí, minha professora na escolinha disse que as cores primárias são vermelho, azul e amarelo"! Hum, foi mal, mas a sua professora te ensinou errado (deve ter sido a mesma professora que ensinava que se a órbita da Terra era elíptica, então o inverno é quando a Terra está mais longe do Sol). Ela não sabia diferenciar magenta de vermelho, nem ciano de azul.

Uma dúvida mais sutil é "Ah, mas eu misturava vermelho, azul e amarelo, e conseguia fazer todas as cores"! Sim, sim, essas cores formam uma base no espaço das cores subtrativas, o problema é que não é uma base ortogonal. Se você fizesse uma impressora com essas cores, um dos tubinhos de tinta iria acabar mais rápido. Por isso também que impressoras tem um quarto tubo com tinta preta: para escurecer um tom é mais barato adicionar preto que misturar tinta dos três outros tubos.

Conclusão da história toda: não subestime o magenta! Apesar de ser sistematicamente ignorada, é uma cor com muitas utilidades :)

Marcadores: , ,

Terça-feira, 3 de Março de 2009

O olhar do macaco

RicBit e um povo da Engenharia vão até o prédio da psicologia se encontrar com um biólogo europeu. Por trás dessa aglomeração interdisciplinar, uma tese sobre a origem da humanidade, baseada na análise do olhar dos macacos. E tudo isso culminando com a conclusão do dilema: afinal, magenta é ou não uma cor? Suspense, emoção e integrais os aguardam no resto desse post!


No post anterior eu expliquei o que era o magenta, então agora é hora de ver o que é uma cor. O Kandel diz que cor é "uma experiência subjetiva relacionada à composição espectral da luz que atinge o olho", mas isso é uma simplificação. Pra ter uma experiência cromática você não precisa de luz, e nem de olho.

Certamente você já ouviu que as pessoas que levam porrada ficam "vendo estrelas". Não é só uma expressão, isso acontece de verdade. O que ocorre é que os mesmos cones da retina que convertem luz em sinais elétricos também são sensíveis a pressão. Então, se você apertar o sensor (por exemplo, com uma paulada bem dada), você vai gerar o mesmo impulso elétrico que teria sido gerado se você estivesse olhando para uma fonte luminosa. Daí, a sensação é de ver estrelas, mesmo que você esteja sem nenhuma luz, no completo escuro.

Certo, então podemos usar os olhos mesmo sem luz. Mas nem os olhos são realmente necessários. Os sinais elétricos que vão dos cones até o córtex visual primário podem ser injetados diretamente com eletrodos: nesse caso você tem a experiência da cor sem precisar da retina. Ou então você pode injetar uma droga psicoativa como o LSD, que altera o equilíbrio químico do cérebro, causando uma experência cromática mais intensa que colocar uma camiseta branca e um monte de roupas coloridas dentro da máquina de lavar.

Mas esses são efeitos colaterais. Na maior parte do tempo, você vai mesmo enxergar cor como sendo uma conseqüência do espectro eletromagnético. Curiosamente, tudo que eu posso afirmar é que a cor é uma conseqüência: eu não posso dizer, por exemplo, que a cor é uma função do espectro, porque ela falha em satisfazer a definição de função: você pode ter duas cores para um mesmo espectro, e dois espectros para a mesma cor. O primeiro caso pode ser visto facilmente na imagem abaixo:

Os dois MSX produzem a sensação de duas cores diferentes, mas na verdade são o mesmo espectro (pode conferir no Photoshop)! A explicaçao é que o cérebro tem uma etapa diferencial após a captura do espectro pelos cones, então um espectro isolado pode produzir duas percepções diferentes, dependendo do que está em volta.

O segundo caso é mais chatinho. Eu poderia mostrar aqui dois espectros diferentes, falar que eles geram a mesma cor, e pedir pra vocês acreditarem em mim; mas resolvi fazer melhor que isso: criei um editor de espectro online! Para usar, basta desenhar um espectro com o mouse em cima da caixa bege, logo abaixo vai aparecer qual a cor que o seu olho enxergaria se estivesse vendo esse espectro. Veja como existem um monte de maneiras diferentes de fazer o amarelo. Você consegue fazer o magenta?



Source do editor de espectros online

Eu escrevi o editor usando GWT, a abscissa é o comprimento de onda (de 430nm até 650nm), a ordenada é a intensidade luminosa (em escala log), e as funções de transferência eu peguei no site do Colour and Vision Research Lab da Universidade da Califórnia em San Diego. Se você estiver lendo esse post por RSS, pode ser que o seu leitor faça sanitização de javascript e o applet não apareça; nesse caso é só ver o post original no www.ricbit.com.

Ok, agora nós sabemos que uma cor pode ser gerada por vários espectros diferentes. Por que isso acontece? A resposta é que o nosso sistema visual joga fora a maior parte da informação que entra, e para explicar os detalhes temos que entender como funcionam os cones.

Um cone é uma coisinha bem burrinha. A saída dele é binária: manda impulso elétrico ou não manda impulso elétrico; e o disparo é totalmente aleatório. Mas apesar ser aleatório, não é ruído puro, porque a probabilidade de disparo pode ser controlada através da luz que entra no sensor. Algumas freqüências fazem ele disparar com mais facilidade, e se você aumentar a intensidade da luz ele também aumenta a probabilidade.

No fim do processo, o cérebro vai interpretar esse trem de pulsos e gerar um único valor, que é uma espécie de média ponderada da luz que atingiu o cone. De outra maneira, é como se o cérebro calculasse o produto interno da função de transferência do cone com o espectro da luz incidente (lembrando que produto interno de distribuições é definido como a integral do produto das distribuições; e, de fato, no source do meu editor de espectro tem um método que faz exatamente isso). Em resumo, um cone gera um valor escalar a partir da entrada.

Mas com um cone sozinho nós não conseguiríamos ver cores. Humanos normais possuem três deles, e na verdade é aí que entra a história do macaco. O tal biólogo europeu tinha notado que o olhar dos macacos americanos era diferente do olhar dos macacos africanos: os primeiros tinham só dois cones, enquanto que os segundos tinham três cones. Isso serve de evidência de que a espécie humana surgiu na África, e não na América (já que os macacos de lá tem o mesmo número de cones que a gente).

A quantidade de cones define quão rica é sua experiência cromática. Alguns humanos nascem com apenas dois cones: são os daltônicos, que enxergam menos cores que os humanos normais. Segundo a wikipedia, entre as mulheres existe um grau significativo de tetracromia também, o que faz algum sentido pra mim (isso explicaria aquelas mulheres chatas que falam: "você não limpou direito, olha uma mancha aqui", e você olha, olha e não vê mancha alguma; vai ver ela era tetracromática e a mancha era de uma cor que você não enxerga).

A resposta dos três cones de um humano normal é a abaixo, nós os chamamos S, M, L (baseado nos comprimentos de onda que eles cobrem, small, medium e large).

Vamos juntar tudo agora. Um cone retorna um valor escalar, e nós temos três deles. Se podemos formar uma tripla ordenada de escalares com a saída dos cones, então na verdade eles definem um espaço vetorial de dimensão três. Uma cor, então, é simplesmente um vetor desse espaço.

Ora, todo espaço vetorial admite uma base. Como o espaço tem dimensão três, você pode escolher três vetores quaisquer pra formar essa base, desde que sejam linearmente independentes. O mais comum é escolher o vermelho, o verde e o azul, porque essas são as cores que você percebe quando estimulamos os nossos cones de maneira independente. Isso dá origem ao sistema RGB que todo mundo conhece.

Você pode aplicar uma transformação linear qualquer nessa base pra gerar outras, como por exemplo, o YIQ usado em transmissão NTSC, ou o YJK usado nos chips de vídeo do MSX2+. Alguns sistemas de cores são não-lineares, como o YCbCr da compressão MPEG. Um sistema não-linear muito usado por artistas é o HSV, que deforma o cubo RGB em um cilindro, onde o raio é a saturação, a altura é o brilho, e o ângulo é o tom da cor.

O sistema HSV pode ser realizado fisicamente se você tiver disponível um laser de freqüência variável e uma lâmpada de cor branca. Se você mudar a freqüência do laser, muda o tom da cor; se mudar a intensidade da lâmpada, mantendo a intensidade do laser fixa, você muda a saturação; e se mudar a intensidade dos dois ao mesmo tempo, muda o brilho. Por exemplo, eu poderia gerar um tom de rosa com um laser vermelho e com branco não muito forte. Um screenshot do editor de espectro gerando esse rosa é assim:

E agora chegamos ao ponto crucial do problema: como você gera o magenta com esse método? A resposta é: você não gera! Não dá pra fazer o magenta assim, porque um único laser não consegue estimular o cone do vermelho e o cone do azul sem estimular junto o cone do verde.

Isso é evidência de que o magenta não é uma cor? Claro que não, é só uma evidência de que esse método específico de gerar cores não é capaz de percorrer todo o espaço vetorial, e algumas cores ficam de fora.

A moral da história é que pra trabalhar com cognição você precisa ter um time interdisciplinar. Se o seu time não tiver alguém de exatas pra interpretar a álgebra linear do seu problema, você corre o risco de escrever bobagens como "magenta não é uma cor".

No próximo post, a conclusão da série do magenta, com as batalhas que a coitada da cor passou!

Marcadores: , , , , , ,

Sexta-feira, 20 de Fevereiro de 2009

There Is No Magenta (mesmo?)

O último meme que circula na twitosfera é debater se Magenta, afinal de contas, é uma cor ou não. A origem da dúvida é um artigo intitulado "Magenta ain't a colour", que afirma que não, magenta não é uma cor, ou pelo menos não uma cor de verdade.

Mas e aí? Enfim, o magenta é ou não uma cor? Bem, depende de como você define, e tem duas definições nessa afirmação. A primeira é "o que é uma cor?", mas também tem uma segunda, mais sutil e igualmente não trivial: "o que é magenta?".

Pra podermos discutir o que é o tal do magenta, eu proponho um gedankenexperiment famoso. Suponha que você tenha nascido com problema no sistema visual, e tudo que as pessoas enxergam como verde você veja como laranja, e vice-versa. Seus pais nunca fizeram nenhum exame em você, então simplesmente apontavam pro Hulk e ensinavam: tá vendo, o Hulk é verde.

Esse experimento foi proposto pelo John Locke, e até hoje filósofos e estudiosos da cognição o usam pra discutir sobre o qualia. Independente disso, uma observação mais simples é que não importa em qual estado sensorial o menino esteja, ele vai chamar o Hulk de verde porque é assim que seus pais o ensinaram. O nome das cores não está ligado apenas às percepções sensoriais: cores são construtos culturais.

Por exemplo, se eu tivesse nascido no japão feudal, meus pais me ensinariam que a cor verde chama Aoi (青い), nome dado para a cor da maçã que não está madura. Mas essa cor Aoi também é a cor do céu e a cor da água. Então, pros japoneses antigos verde e azul eram a mesma cor?

Incrivelmente, sim! Pra eles o verde e o azul eram apenas tons diferentes de Aoi, da mesma maneira que nós temos azul claro e azul escuro. Com o tempo eles criaram uma outra palavra, Midori (緑), pra falar especificamente do conjunto "Aoi que não é azul". E quando querem falar do azul propriamente dito, hoje em dia eles falam Burú (ブルー), copiado do inglês Blue.

Isso ocorre em todas as culturas. Pra gente, o azul é uma coisa só, mas um americano pode dizer que Blue é só o azul escuro, e aquilo que a gente chama de azul claro na verdade é Cyan.

Por isso, quando eu li o título do artigo, minha primeira dúvida foi: mas de qual magenta ela está falando? O que ela chama de magenta é o mesmo que eu chamo de púrpura? Ou é roxo? Violeta? É a cor da calça do Hulk?

Ler o artigo original não ajuda, pois lá ela afirma que magenta é a mesma coisa que pink, e aqui na minha cultura isso são coisas diferentes: magenta é a cor no meio do azul e do vermelho, rosa é o vermelho desaturado.

A moral da história é que se você quer afirmar alguma propriedade a respeito de uma cor, não chame a cor pelo nome pois depende de locale. Ao invés disso, é melhor usar uma descrição quantitativa.

No fim das contas, o que autora queria dizer mesmo é que #FF00FF não é uma cor de verdade, e isso eu vou mostrar no próximo post que é falso também :)


PS: Aparentemente eu não tinha cumprido a promessa de dois posts por mês, mas isso é porque eu tive que viajar para a Índia, e os posts acabaram indo para um blog novo só sobre a viagem. Se você quiser ler as bizarras aventuras do Ricbit na Índia, basta visitar o India Broadcast.

Marcadores: ,

Segunda-feira, 5 de Janeiro de 2009

O Teorema de Capullo

Quando eu era criança, tinham duas coisas que eu fazia bem: programar e desenhar. Em um certo ponto da vida eu decidi conscientemente deixar de lado o desenho pra focar na programação, mas não antes de tentar um emprego como desenhista :)

Isso foi quando eu tinha onze anos. Eu morava ao lado do estúdio do Ely Barbosa, que na década de 80 tinha vários personagens bizarros, incluindo um coelho que viajava numa escova de dentes voadora gigante. Na cara de pau eu fui lá e me ofereci pra desenhar os gibis deles. Incrivelmente, eles não falaram "se manda guri", mas fizeram de fato um teste pra ver se eu desenhava o suficiente. (Que eu acabei bombando. Tinha só onze anos poxa.)

Mas mesmo tendo optado pela programação, eu nunca deixei de lado esse lado artístico. Não por acaso, meus primeiros empregos foram todos com computação gráfica. E, embora há muito eu não desenhe, adoro comprar livros e revistas com técnicas de desenho, para o caso de algum dia dar vontade de desenhar de novo.

Uma das revistas que tenho aqui é a primeira edição da Wizard brasileira, onde publicaram na íntegra todo o curso de desenho do Greg Capullo (desenhista do Spawn), uma série muito boa chamada Curso de Impacto (no original Krash Course, tem digitalizado na web se você souber onde procurar). No capítulo sobre perspectiva, eu aprendi um truque muito bom com ele, que na falta de nome melhor eu chamo de Teorema de Capullo:

Se você tiver vários personagens de mesma altura em uma cena, mesmo que eles não estejam na mesma profundidade, sempre haverá uma parte do corpo deles que estará alinhada.


Sabendo usar a regra acima, fica super fácil desenhar cenas complexas com perspectiva correta. Pra ver experimentalmente como isso é verdade, eu fiz um programinha em pyOpenGL que desenha vários Ricbits em posições aleatórias, usando as regras acima:


Script em python que desenha a cena acima

Note como o teorema de Capullo é verdadeiro: apesar de estarem em distâncias diferentes, todos os Ricbits estão alinhados na altura da cintura. Naturalmente, a primeira coisa em que pensei quando vi o teorema foi: dá pra demonstrar? A resposta é: sim, dá, e é surpreendentemente simples!

Vamos assumir que o observador está a uma altura h do solo, e que o plano de projeção está na coordenada z=1 (sem perda de generalidade). Vamos projetar um ponto P qualquer nesse plano de projeção, cujas coordenadas são Px, Py, Pz, e a intersecção com o plano vai ser em Sx, Sy. O que nós queremos provar é que existe um Sy tal que, para qualquer Pz dado, sempre é possível escolher um Py, independente de Pz, que projeta nesse Sy. Virando a figura de lado ela fica assim:

(Thanks to Bani/Inkscape pelo diagrama)

Por semelhança de triângulos, nós tiramos que (Py-h)/Pz = Sy/1, logo Sy=(Py-h)/Pz. Agora é imediato, basta escolher Py=h que Sy sempre será zero, independente de Pz, QED.

A parte bacana de entender matematicamente o que acontece é que você pode extrapolar suas conclusões. Como a escolha de Py depende do h, isso significa que o ponto exato onde as figuras se encontram depende da altura do observador. Subindo o observador no script ficamos com uma figura como a abaixo, note como agora os Ricbits estão alinhados na altura do pescoço:


Um dia eu ainda volto a desenhar, mas enquanto isso programação e matemática são divertidas demais :)

PS: Minha resolução de ano novo é atualizar o blog pelo menos duas vezes por mês, então, se eu atrasar, me cobre!

Marcadores: , , , ,

Sábado, 25 de Outubro de 2008

Dez anos de MUST

É díficil achar alguém na faixa dos 30 anos que trabalhe com computadores e não conheça o MSX, um computador pessoal de 8 bits que fez um sucesso enorme por aqui. No seu auge, entre 85 e 91, estima-se que mais de 400 mil máquinas tenham sido vendidas no Brasil.

Mas embora esse período tenha sido o auge em número de usuários, não foi o ápice na parte técnica. Os mais avançados softwares brasileiros de MSX foram feitos no período de 1996 a 2004, e há dois motivos pra isso. O primeiro é que esse foi o início da internet comercial, então muitos dos manuais e datasheets que antes eram raros, passaram a ser difundidos livremente pelas listas de discussão. O segundo é que essa também foi a época em que começaram a se formar os primeiros engenheiros que cresceram com o MSX na infância, e toda essa criançada estava sedenta pra usar os novos conhecimentos na sua velha maquininha.

Eu mesmo fiz um monte de brincadeiras nessa época, talvez a mais conhecida tenha sido o meu emulador BrMSX. Mas agora, em 2008, um outro software que fiz completa dez anos, e nada mais apropriado que comemorar com um detalhado making of. Apresento a vocês o Music Station, ou como também era carinhosamente conhecido, o MUST:


Vamos voltar uma década no tempo: em 1998, a internet crescia, nasciam os primeiros grandes portais nacionais, e começava a surgir uma prática que hoje em dia é extremamente comum: o compartilhamento de músicas em mp3. Primeiro por FTP e IRC, depois pelo Napster e Audiogalaxy, em pouco tempo os arquivos mp3 estavam por toda a parte.

Naturalmente, quem ainda brincava com o MSX também queria entrar na onda. Mais de uma vez me perguntaram "Ricardo, você não pode fazer um programinha pra tocar mp3 no MSX?". Qualquer criatura com um mínimo de bom senso iria perguntar "pra quê?". Mas bom senso nunca foi o meu forte :)

Eu já sabia de antemão que mp3 no MSX não era viável, o coitado do Z80 não iria dar conta. Mas a essa altura eu já sabia evitar um erro muito comum em desenvolvedores, o de prestar atenção no que o usuário pede, ao invés de focar no usuário quer. Sure, eles estavam pedindo mp3, mas o que eles queriam mesmo era só tocar música no MSX. Se fosse um outro formato qualquer não faria diferença. Como eu tinha acabado de cursar Processamento Digital de Sinais na Poli (com o saudoso prof. Max Gerken), achei que poderia encarar a construção de uma solução customizada pro MSX.

Hora de calibrar os objetivos: eu decidi fazer um player que tivesse a melhor qualidade possível pro MSX, que rodasse em qualquer modelo de MSX, incluindo os nacionais, e que conseguisse espremer pelo menos um minuto de música em uma MegaRAM de 256kb, o modelo mais comum. O primeiro passo, portanto, é ver se o MSX dá conta de tocar um sample com qualidade aceitável.

O MSX usa como gerador de som o chip AY-3-8910 (popularmente PSG), que é basicamente um gerador de ondas quadradas. Pra tocar um Lá central, você especifica a freqüência de 440Hz, acerta o volume apropriado, e se diverte com o barulhinho que ele produz. Se você for um mago do chiptune, dá pra fazer músicas bem legais com o PSG, mas definitivamente ele não foi feito pra reprodução de áudio digital. Para conseguir isso, nós temos entender como o chip funciona por dentro.

Internamente, o gerador de ondas quadradas é só um contador digital, que alterna o estado de um flip-flop depois do término de meio período. O chip tem três geradores que você pode ligar ou desligar de maneira independente através de um mixer. Quem tem experiência com chips TTL sabe que sinais desligados usualmente não são interpretados como nível lógico zero, mas sim como nível lógico um.

Pro nosso ouvido tanto faz, um sinal constante é silêncio sempre, independente dele estar em zero volts ou em cinco volts, mas o segredo da coisa é que o controle de volume é uma etapa analógica feita depois do mixer. Por isso, se você desligar o gerador através do mixer, e mudar bem rapidamente o controle de volume, você pode improvisar qualquer forma de onda que quiser! Como o PSG tem 16 volumes possíveis, isso significa que o MSX pode emular um PCM de 4 bits, mesmo sem ter sido projetado pra isso.

Quando o sinal está em nível lógico um, basta variar o volume!

Agora basta ligar esse PCM num timer de alta resolução e pronto. Quer dizer, exceto pelo fato do MSX não ter um timer de alta resolução. O melhor que ele tem é um timer que dispara no início do retraço vertical, a 60Hz, que é uma freqüência baixa demais pra gente. Nesse caso, o jeito é apelar pra gambiarra criatividade :)

Como o Z80 do MSX não tem cache, nem prefetching, nem nenhuma dessas firulas de processadores modernos, os opcodes sempre levam o mesmo tempo pra rodar. Assim, você pode criar um pseudo-timer simplesmente contando quantos ciclos de clock seu programa leva pra executar. Se nós precisássemos de uma rotina que lesse um byte da memória, mandasse pro PSG, e levasse exatamente 50 clocks pra rodar, uma possibilidade seria:

LD A,(HL) ; 8 clocks
LD A,(HL) ; 8 clocks
INC HL ; 7 clocks
OUT (0A1h),A ; 12 clocks
NOP ; 5 clocks
NOP ; 5 clocks
NOP ; 5 clocks

Pra fazer um timer assim, além de programar em assembly, você ainda precisa resolver um subset sum dos opcodes, o que é extremamente divertido (eu assumo que se você está lendo até aqui, deve achar essas coisas divertidas também :). Note como é importante fazer o padding correto, além de colocar 3 NOPs, eu também repliquei o carregemento da memória, só pra fazer a conta bater certinho nos 50 clocks.

Agora que temos um jeito de reproduzir o som, precisamos escolher a sampling rate. Pra conseguir o objetivo de 1 minuto em 256kb, o áudio certamente terá que ser comprimido. Então a sampling rate precisa ser baixa o suficiente pra poder suportar a descompressão em real time entre cada amostra, e alta o suficiente pra não perder muita qualidade de som. Eu escolhi 11kHz; como o clock do MSX é 3.57MHz, isso dá um total de 324 clocks por amostra. Não é muito, mas alguma compressão dá pra fazer.

Vamos calcular a compressão agora. Pra colocar 60 segundos a 11kHz em 256kb, nós precisamos de, no máximo, 256k*8/60/11k = 3.1 bits por amostra. Nosso sinal original tem 4 bits por amostra, então realmente a compressão é necessária. O Z80 não tem fôlego pra implementar transformadas, então não podemos usar nada de DCT, e nem mesmo Haar.

O jeito é modelar alguma coisa bem simples mesmo, tipo um código de tamanho variável como o código de Huffman. Esse tipo de código funciona tanto melhor quanto menos uniforme for o seu histograma. Pegando uma música típica como teste, chegamos em uma entropia de 2.6 bits; mas, por outro lado, a primeira diferença tem entropia ainda menor, apenas 2 bits!


Vamos codificar a diferença então. Com apenas 324 clocks não dá pra implementar todo o Huffman, mas tem uma maneira de simplificar, que é usando compressão com perdas. Como 99.3% das diferenças estão na faixa de -3 a 3, eu posso saturar nesses valores pra deixar o código mais simples. O código que utilizei foi o abaixo:

3 1111
2 1110
1 01
0 00
-1 10
-2 1101
-3 1100

No final a implementação desse código ficou menor do que eu esperava, apenas 169 clocks. Isso significava que eu tinha 198 clocks sobrando, com a cpu parada. Eu poderia ter aprimorado o codec com uma compressão mais eficiente, mas pensei que seria mais divertido, ao invés disso, usar esses clocks sobrando pra adicionar animações. Nesses clocks sobrando eu acabei colocando um osciloscópio com a forma de onda tocada, um banner animado na parte inferior, e no cantinho ainda sobrou cpu pra colocar um pingüim dançando!

Nesse ponto tudo que faltava era uma tela de abertura. Como no final o programa acabou ficando uma experiência multimídia, eu resolvi que ele seria uma homenagem à série Disc Station da Compile, que primava por seus excelentes demos. Eu chamei então o meu programinha de Music Station, e como os Disc Station originais sempre começavam com uma menina bonitinha, eu pedi ao meu irmão que desenhasse uma pingüinha no mesmo estilo. O desenho original que ele fez foi o abaixo:

Adaptar desenhos no MSX é tão complicado quanto adaptar código, a resolução é de apenas 256x192 e ainda tem o problema do color clash (cada bloco de 8x1 pixels pode ter no máximo duas cores). O pingüim tomando sol no canto da imagem teve que sumir, eu não tinha resolução pra isso. Já na pingüinha, eu tive que usar traços bem grossos no contorno, pra minimizar o clash, mas mesmo assim ainda sobraram algumas partes borradas. A solução foi usar sprites pra cobrir esse borramento.

Consegue achar as diferenças?

Por fim, bastou criar um logo, inspirado no logo original do Disc Station, e o MUST estava finalmente pronto! Pra quem quiser brincar com ele, abaixo tem uma versão em .dsk que pode ser carregada em emuladores, como o blueMSX ou o openMSX, e também o código fonte original.

Imagem de disco para rodar em emuladores
Código fonte original do Music Station, em assembly Z80

Na época, a comunidade MSX adorou o MUST. Como eu esperava, o pessoal começou a compartilhar músicas convertidas, do mesmo jeito que o povo do PC compartilhava mp3; e como eu publiquei a engine do MUST em GPL, um monte de gente reaproveitou o código, sendo que a engine foi usada até em joguinhos. Eu até animei a fazer uma versão com vídeo também, mas isso já é outra história, pra outra ocasião :)

Parabéns pelos dez anos, Music Station!

Agradecimentos à Ila, ao Acidx e ao Sturaro por ajudar na arqueologia digital :)

Marcadores: , , , , , ,