ASCIIMath creating images

Friday, February 25, 2011

SIDshield code updated

I have updated the code for the SIDshield, now it's actually useable to play some music in a relatively easy way.  Here is the new library, and here is a simple player with a little melody.  The player code is basically ported from the SIDcog, including the stored melody - so that remains copyright "Ahle2"! (Who deserves lots of respect for writing SIDcog)

The biggest problem with my code is that I didn't spend much effort in getting the timing correct so it's a bit wonky.

NOTE the Arduino environment puts static tables in RAM, which is very limited especially on the Atmega168.  I would constantly get mysterious malfunctions, including the inability to upload new sketches - effecitvely "bricking" the Arduino.  This can be fixed by carefully removing and resetting the power using the jumper and timing the upload of a new sketch.  It took me quite a while to figure out the solution.

The solution is to ensure the music data is in program memory: using the PROGMEM keyword.  Its use is a bit involved, since one can't simply access it as arrays but has to explicitly copy it using special functions.  See the player app.

UPDATE: The files got moved to my homepage, I adjusted the links accordingly.

Tuesday, February 22, 2011

Arduino SIDshield initial schematic and code

This is the schematic for the Arduino SIDshield I've been working on, drawn using Eagle. This is NOT the circuit on the breadboard, since I don't have a couple of 74LS164's handy - instead, I used a pair of 74LS323's that are slightly more flexible.  They operate in a simple parallel out mode though.  Also, as mentioned in the previous post, the 1MHz clock is provided by a function generator buffered by a 74LS04.  Hence, regard this schematic as untested!

I still haven't gotten around adding the 5V-to-12V boost circuit.  I was planning on using the LT1109CZ-12 - a nice, small TO-92 packaged chip.  Unfortunately it's not easy to get, it seems.  My 6581 draws 27mA from the 12V supply, well within the limits promised bu Commodore (datasheet says 25mA typ, 40mA max).

Software

The library to drive the chip is a modification of the Spi library, reduced to the constructor and a single function.  I will add more functions later, for now all it does is take an address and data value and set the appropriate SID register.  This first version is on my website.  A simple sketch to test it:

#include <SID.h>

void setup()
{
  sid.setReg(24,15); // full volume
  sid.setReg(6,0xf0); // ADSR=0,0,15,0
  sid.setReg(1,0x1c); // set frequency to 440Hz
  sid.setReg(0,0xd6);
}

void loop()
{
  // .8s beep at 1s interval
  sid.setReg(4,17); // gate on
  delay(800);
  sid.setReg(4,16); // gate off
  delay(200);
}

Performance

The speed with which registers are written is pretty good.  I don't want to make it any shorter actually, since the chip select is not synchronized to the clock signal - so I have to make sure a few cycles happen during CS low.  The shift registers get loaded within 5us, and the CS signal is asserted for slightly less than that.  Overall the entire operation of setReg is about 15us.

More to come.
UPDATE: see here.

Thursday, February 17, 2011

Arduino SIDshield: it's ALIVE!!!!

My most recent little project is to make a good ol' Commodore SID chip (6581) be controlled by an Arduino.  The prototype is now functioning:
The breadboard with the Arduino, the SID chip, a couple of shift registers, and a clock buffer.
The complete setup requires a bit more hardware:
Ok, quite a bit of that stuff is redundant...
On the scope you can see the triangular wave I coaxed out of the chip, which was pulled from my first C64, bought back in 1984 or 1985 in Germany.

This weekend I will finalize the schematics, do a board layout and finish the library for the Arduino.  Note that the design is conceptually very similar to the MIDIbox SID module, but then there are only so many ways to attach a SID to a couple of shift registers.

The final version will use a crystal oscillator (replacing the function generator in the picture) for the 1MHz clock, and a DC-DC boost converter to generate the 12V for the SID (currently provided by the adjustable supply).

I will post the schematic, layout and code as soon as I'm done.

Saturday, February 12, 2011

Playing sounds from MATLAB on Unix

While I honestly don't know if it is still a problem with the latest versions of MATLAB, there has been a problem with the "sound()" function in MATLAB on Macs and Linux platforms with ALSA.  Here is a very simple script that works around the problem by simply creating a temporary wave file, then calling the appropriate command-line function to make the sound.  It's trivial to customize.

In contrast to the real "sound()" function, this one also doesn't block, and returns immediately.  Again, this is trivial to change (by removing the ampersand) but I like this behavior, especially useful when playing longer sound files.

function [ ] = usound( w, fs )
%USOUND Plays sound on ALSA-based linux machines or macs

if nargin < 2
    fs = 16000;
end

filename = ['/tmp/' getenv('USER') '_matplay.wav'];
wavwrite( w, fs, filename );
if ismac
    eval(['!afplay ' filename ' &']);
else
    eval(['!aplay ' filename ' &']);
end

Sunday, February 6, 2011

Voronoi Neighbors

For a current research project, I was considering the problem of finding the neighbors of some given quantization value, basically a method to figure out if two Voronoi regions share a border, where the quantizer is specified simply by the centroids. I wrote a quick and dirty script, but it doesn't work in all cases - the problem is actually quite difficult for vector quantizers.  However, I started without checking the literature, trying to come up with my own approach; now I know better! Below, my crack at the problem, followed by the better, faster and smarter method!

The initial approach
My approach is based on drawing a line between two centroids.  If I find a point on this line that does not get quantized to either of the centroids, I declare the two regions not neighbors.
In this figure, A and B are clearly neighbors, whereas C isn't.  Testing is done using a binary search: I sample the middle of the line, check if that point gets quantized to A or B - if to B, then pick the halfway point from the middle to A, keep going until either a non-A or B point is found or 10 iterations have been done.  Generally for most checks the algorithm stops at the first check (see A and C) only for the neighboring regions will all 10 iterations be computed.

Problem is, this doesn't work very well.  Let's remove D:

Clearly, C now is a neighbor of A, but the straight line is not where the boundary between A and C is located.  So much for that...

The proper way
I found the correct way of solving this problem by looking at how Voronoi diagrams are drawn by MATLAB: using Delaunay triangulation.  Then using MATLAB functions, the lists of neighbors for the centroids can be found by calling delaunay, then TriRep, then the edges method on the resulting structure.  Here is some sample code:


% create a quantizer
V = zeros(2,8);
V(:,1) = [ 0 0 ];
for n=2:8
   V(:,n) = [ sin(2*pi*(n-1)/8) cos(2*pi*(n-1)/8) ];
end
figure;
voronoi(V(1,:),V(2,:));
tri = delaunay(V(1,:),V(2,:));
tr = TriRep(tri,V(1,:)',V(2,:)');


The resulting edges array can now be examined and turned into a list of neighbors for each centroid.  This should scale to higher dimensions, but won't work for 1-D - but there, the neighboring quantizer region problem is trivial anyways.  (Note, I have the Signal Processing Toolbox, so I'm not sure all those functions are in default MATLAB.)

So while my initial quick bit of code didn't work, it did cause me to think about the problem a bit more deeply and I learned a bit about computational geometry.