After drawing basic shapes on the oscilloscope (circles, lines, and rectangles), I decided to try something more adventurous: bitmaps. Since the soundcard outputs no more than 192,000 samples per second and the oscilloscope doesn't retain data for much longer than 1/60th of a second, I knew that only small images would work.
First, I needed to read images. The Python Imaging Library does an admirable job (and is free!). It works with most formats, and is capable of reading layered images (animation, for the layman). Most of my test images were GIF files, which posed a problem: GIF's are indexed. In an indexed image, each pixel has only a single value, rather than the usual three (red, green, and blue). The GIF includes a lookup table for translating that value into a color. Unfortunately, PIL doesn't include any way of running those numbers through the lookup table. Fortunately, it allows conversion to a normal RGB image.
Converting a GIF to an RGB worked perfectly. My script translated pixel values into positions on the oscilloscope screen, and dwelled on each pixel for a variable amount of time, based on lightness (the sum of the red, green, and blue compoments). The code supports a variable number of color levels: the cursor can dwell for anywhere between 1/192,000 and 10/192,000 of a second to change brightness of a pixel.
The only flaw in the image was heavy ringing. The soundcard expected to drive speakers (8Ω), not an oscilloscope (0.5-2MΩ). Without a noticiable load, the card creates overshoots the target voltage. That's ringing.
With static bitmaps done, I decided to try and display animations. The first problem I ran into was easily solved: when PIL converts an image to RGB, it also flattens the layers. I reworked the code to copy the current layer and convert it. I also needed to process the image into a wav file before displaying anything. The process of flattening, converting, and parsing took far too long.
The soundcard was also difficult. When asked to display the same amplitude signal for any period of time, the output amplitude decays. So, if I drew a line across the top of the screen, it'd drift to the middle. Animations whose centers moved (say, a drop of water falling) drifted even more. I don't know if I can fix the soundcard, and the drifting ruins any possiblility of complex animations.
Finally, I decided to try something useful with my knowledge. Using the functions I'd written prior, I assembled a clock. I even made the hour and minute hands move incrementally: at 10:30, the hour hand sits halfway between 10 and 11.
That's all for now. I'm back at Lafayette, so expect different sorts of projects.