返回资讯中心
外部精选
软件工程
#开发者实时流

Daphne – Oramics Inspired DAW

A drawn-sound instrument after Daphne Oram's Oramics machine. You draw the

Hacker News 最新stuart782026/11/1 · 今天30 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

A drawn-sound instrument after Daphne Oram's Oramics machine. You draw the sound, on paper or on screen, and the machine plays what you drew.

Built for running workshops. Print the sheets, let people draw on them, play the results. It was written for Drawing Sound, a workshop on Oram and the machine she spent her working life building; that page carries the slides and the speaker notes from the first half.

Download v0.4.0 for macOS, Windows or Linux. The macOS build is signed and notarised, so it opens normally. Windows is unsigned and SmartScreen will warn once.

pnpm install pnpm dev # run the app pnpm template # generate sheets to print pnpm test

Packages

engine The voice. Plain TypeScript, no Web Audio, no DOM, no Node.

template Printable sheets, and the geometry everything shares.

vision Reading a photographed sheet back: registration and extraction.

midi Reading a MIDI file onto the strips.

app Drawing surfaces, audio client, projector view, PDF export.

shell Electron: windows, external display, save dialog.

Keeping the engine free of platform code is the decision everything else rests on. The same module runs in the AudioWorklet, in an offline bounce at whatever speed the CPU manages, and in a unit test. It can move to WASM or a JUCE plugin later without a rewrite. A test asserts that a 128-sample worklet render and an offline bounce agree to 1e-9, so a bounce always matches what you heard.

vision follows the same rule for the same reason. It takes pixels and returns numbers, with no DOM and no Node anywhere in it, so it runs against a canvas in the app, against a rendered sheet in a test, and in a watch folder later.

Ten synchronised 35 mm film strips ran over photocells. Four carried pitch as binary-coded whole Hertz, four carried amplitude (one per timbre), and one each carried vibrato, reverberation and transport. Four hand-painted glass slides sat in front of CRTs to supply the waveforms: a photomultiplier feedback loop dragged a scanning dot onto the painted contour, and the resulting voltage was the wave. Output was mono. Polyphony came from multitracking to tape.

Several of its constraints are modelled rather than approximated, because they are most of why it sounds the way it does. Each is a switch in the app, so you can hear 1969 and then leave it.

Oram's surviving slides carry four thick, irregular ribbons of paint stacked vertically, each spanning the full width, with clear glass above and below. None of that is a single-valued function of x.

Graham Wrench, who built the electronics, described how the machine read them: the spot sweeps left to right, and "if obscured by the opaque part of the drawn waveform, the photomultiplier would detect no light, and the beam would move higher until the photomultiplier could see it." Dark pushes the spot up, light pulls it down, and it balances on the top edge of the paint.

So scanner.ts runs that loop at audio rate over a 2-D opacity field, one bilinear lookup and a few flops per sample. The character comes out of the loop rather than being added afterwards:

Free-floating ribbons are only locally stable. A spot below one sees light and dies on the bottom rail, so the loop has a search mode, as real tracking servos do. It sweeps up to reacquire, but only when the column actually contains paint. An empty carrier sits dark instead of hunting.

Wrench again: "one strip would set the number of units of cycles per second; one set the number of tens of cycles; a third set the number of hundreds of cycles; the last would set the number of thousands." Those relays "switch in banks of resistors and make the time-base run at whatever frequency."

Resistors in parallel, so conductance sums, so frequency is proportional to the coded number. The painted code does not represent a pitch. It is the frequency in Hertz. Two things follow:

The tracks are weighted 1-2-4-2 reading up from the film's lower edge, not the 8-4-2-1 you would reach for today. They sum to 9, so every digit is reachable, and several have two paintings. 4 is either the single 4 track or both 2s, and the machine cannot tell them apart.

The relays latch, so pitch persists between neumes, which is why a painted strip is mostly blank. They are also mechanical and do not move together, so 199 Hz to 200 Hz flips eight tracks and the bank spells frequencies nobody painted for about ten milliseconds. Changes within one digit are clean. Decimal carries stumble.

Level was set by shining a torch bulb at a photoresistor. Filament thermal mass plus asymmetric cell recovery means no envelope has a sharp attack, and released notes hang on longer than the drawing says.

The Hertz strip is the machine as built, and it stays the default. It is also hard to draw a tune on: octaves fall unevenly up a linear scale, so middle C and the C above sit a hand's width apart at the bottom and nearly touch at the top.

Notes splits pitch into two bands, a note band of twelve rows over an octave band of eight rows. This is the shape of Oram's own later design, and of Tom Richards' Mini Oramics, rather than the 1969 machine. Switch with the Hertz and Notes buttons on the pitch lane, or ⇧⌘H.

Blank sheet prints the note sheet when the app is in Notes mode: light grey rows for the notes, with the sharps shaded, and eight octave rows below. The QR says which sheet it is, so importing a photo of one switches the app to Notes.

Space play or stop

⇧⌘H pitch in Hertz or Notes

⇧⌘L notes as dots or lines

⌘+ ⌘- ⌘0 zoom in, out, fit

⌘D next theme

⌘S ⌘O save, open

⌘N clear and start again

⇧⌘A export audio

The 30-second guarantee

The printed time field is exactly 300 mm at 10 mm/s, so a sheet is 30.000 s by construction. 1 cm is 1 second and 1 mm is 100 ms. That is one tenth of the machine's 100 mm/s film speed. At her speed a Legal sheet would last 3.5 seconds.

Nothing downstream measures millimetres off paper. Four corner fiducials define a reference rectangle, the extractor solves a homography onto their known coordinates, and print scale, scan DPI, skew and lens distortion all drop out. Each sheet carries a QR describing itself, so importing is scan-and-drop and the app takes its speed from the sheet.

Draw in the app, hit Export PDF, and you get the same sheet people draw on with your lines printed onto it. One page: every lane as a band, the four timbres in a strip underneath. Print it, let someone mark it up by hand, scan it back. That works because the app and the printed template share one geometry module.

Import scan takes a photograph or a flatbed scan of a printed sheet and turns the marks on it into lanes. Three steps, each of which can fail honestly rather than guessing.

Register. The four corner squares are found, and a homography solved onto their known page coordinates. Print scale, scan DPI, page skew, the angle the phone was held at and most lens distortion all drop out together. Measured against rendered sheets put through a simulated camera, the worst position error anywhere on the page is about a tenth of a millimetre. Three corners are not enough and the importer says so instead of fitting a plausible wrong map.

Describe. The QR is rectified using that map and decoded, so the sheet says which piece it belongs to and how long its field is meant to last.

Extract. Each band and panel is sampled where the template says it is. The threshold is calibrated from the corner squares, which are the one thing on the page guaranteed to be solid black: everything printed is then a known fraction of it, so the same setting works for a flatbed scan, a phone under a window and a photocopy of a photocopy.

The sheet declares its own printed furniture so the extractor can ignore it. A mark is discarded only when it fits entirely inside the strip a printed rule occupies, never merely because it sits at the same height, because the centre rail on the transport lane is exactly where people draw and the pitch band's rules are the octaves. A stroke laid along a printed rail is the one case this cannot separate, and it reads as the rail.

Each band is registered on its own box rather than on the page alone. The homography maps the four corner squares exactly, and over 300 mm a printer that lays the content a hair small or a hair off centre still leaves a millimetre or two unaccounted for at each end: the first second of a band lands on the gutter and the last lands inside the frame. So a band looks for its own left and right sides, which are the only full-height lines it has, and time is measured along the printed band. The registered picture is cut to the same box, so the paper sits under the reading rather than beside it.

What the printing hides is put back, where the printing explains it. The rail labels sit inside each band and a line drawn behind one goes unread, which used to leave an amplitude silent for the first half second of a piece that was drawn across the whole sheet. A hole is filled only when every missing column is one where the line would have been inside printed ink, and only for a short stretch: the widest thing the sheet prints inside a band is 9 mm, and a longer blank belongs to the paper.

A scanned timbre is laid again at the weight a brush lays. A pen line is about a twentieth of the panel high where enamel is a seventh, and the scanning spot is wider than the pen line: the servo gets a weak, broken edge to ride and the voice comes out several times quieter than the same shape drawn on screen. The traced line is redrawn underneath itself at brush weight with pen skips bridged, which leaves the top edge, the part the spot rides, exactly where it was drawn.

A lane holds one value per column. That is what the machine reads, and it is not what anybody drew. A workshop sheet comes back covered in scribbles, words and faces, and reducing that to a height per column throws away almost all of it. So an imported sheet keeps its registered photograph and every band shows the paper, with our reading of it drawn over the top in orange. Reading in the header turns the overlay off, leaving the sheet as it was drawn.

The timbre panels are not read as contours at all. Oram's slides were painted glass and the flying spot answers to the whole field, so a panel is sampled as a 2-D opacity field and handed to the engine as painted glass. A scribble stays a scribble, a drawn face stays a face, and the scanner does with them what the machine did. Read as a single edge and filled underneath, every one of them came back as the same solid black silhouette.

The threshold sits below what the dashed rules print at, because a workshop runs on pencil and pencil is nowhere near solid black. Held above the rules it read a firm biro and missed half of what people actually drew.

Import MIDI lays a .mid file onto the strips. The parser is hand-rolled, so format 0 and 1, running status and tempo changes anywhere in any track are all handled, and the package has no DOM and no Node in it like the others.

The interesting part is not the parsing. The machine has one pitch strip and four amplitude strips, and the four amplitudes are the four timbres of a single voice rather than four voices. A chord cannot be represented at all. Neither can two parts at different pitches.

So a file is reduced to one line. The highest sounding note wins, which is what a listener hears as the tune, and the importer reports how many notes it dropped rather than hiding the loss. The rest goes where it can:

A file longer than thirty seconds is fitted rather than cut: the note times are mapped onto the sheet and the transport speed is set so the piece still plays at its own tempo. Notes above 1000 Hz have no place on the strip and are counted, not clipped silently.

In Notes mode a MIDI note lands as a note row and an octave row instead, which is what it already is. Only notes outside octaves 1 to 8 are refused.

Export ▸ Audio renders one pass of the sheet to a WAV file: the same engine that plays live

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →