gogins / cloud-5

Complete browser-based computer music studio for algorithmic composition and live coding
Other
9 stars 1 forks source link

"Cancycle" for Csound, CsoundAC, and Strudel at Brooklyn College on 10/20/2023. #46

Closed gogins closed 1 year ago

gogins commented 1 year ago
gogins commented 1 year ago

Bio

I was born in 1950 in Salt Lake City, and grew up with trips to mountains, deserts, and unlocked university labs. My father was an inventor, my mother an artist. I have pursued poetry, photography, music performance, and composition. I have lived in Salt Lake City, Los Angeles, Seattle, and New York. I have a B.A. in comparative religion from the University of Washington, 1984, where I also studied computer music with John Rahn. Computer music became my major interest. It also enabled me to make a living as a programmer. In the late 1980s, I benefited greatly from Brad Garton's openness to non-student participation in the woof user group and concerts at the Columbia-Princeton Electronic Music Center. Currently, I contribute code to Csound, am the author of an algorithmic composition system for Csound, host the International Csound Csound Users Group meetings online, and am on the steering committee for the New York City Electroacoustic Music Festival. I write articles and papers on computer music, and I create computer music. I have a special interest in mathematical methods of algorithmic composition. I am married to Heidi Rogers. We live in the Catskills and in Manhattan.

gogins commented 1 year ago

Program Notes

This is a piece of interactive visual music implemented using my all-HTML5 system for making and performing computer music, cloud-5.

cloud-5 runs exclusively in standard Web browsers from a local or remote Web server. The system includes WebAssembly builds of Csound and my algorithmic composition library CsoundAC, the live coding system Strudel with some patches and additions by me, and whatever other JavaScript or WebAssembly components are needed.

I composed this piece using an orchestra of fairly complex Csound instruments together with a Strudel patch that uses CsoundAC for generating chord progressions and modulations. I set up the Strudel patch to make it easy to shape the piece by live coding during performance. The basic idea is that there are three rather repetitive sections, and the performer is expected to introduce variations in these sections by moving the sliders (especially the circle map parameters and the run and offset parameters), and by removing and adding code during play.

The piece also includes a music visualizer written in OpenGL Shader Language.

gogins commented 1 year ago

Things I would like to do in this piece:

gogins commented 1 year ago

The new slider in Strudel is very cool. To get it to work with csoundn, n rather than note must be used.

What I most want is to use a slider with discrete steps as a switch to control what Patterns are playing.

gogins commented 1 year ago

The slider can perhaps be used to switch between, mix, or cut up other Patterns. This could be used to make a piece that is set up to make certain possibilities easier for live coding. Patterns that could be controlled in this way include:

Sigh... none of these work as required out of the box.

Of course it's possible to just comment out and in chains of Patterns.

gogins commented 1 year ago

This works:

chooseWith(slider(0.6365, .5, 1), ["bd", "hh", "sd"]).s().fast(4)

No, it doesn't work if the list consists of patterns.

gogins commented 1 year ago

I will look through this resource: Online Encyclopedia of Integer Sequences. I thought these sequences had interesting graphs. Many even provide a way to save the sequence as a MIDI file, which will play just fine in Pianoteq.

Unfortunately these sample a sequence to obtain an array; what I need is to simply recurrently generate the sequence.

gogins commented 1 year ago

So conceptually there are two dimensions, tracks or time lines, and the vertical dimension. I need to assemble tracks from sub-patterns with from 0 to some N of repetitions each. Then I need to have one note, or one rest, on either sub-patterns or on the track as a whole, to create differential canon. A transposition of the whole track also should be applied.

Multiple tracks are then simply stacked to create the vertical dimension.

This doesn't currently work because stack aligns the ends as well as the beginnings of its Patterns, and so can't do differential canons.

gogins commented 1 year ago

arrange works up to a point, but not when the repetitions of a Pattern are set to 0, and not with use of slider for the number of repetitions.

gogins commented 1 year ago

I may have to define a switch or repeat Pattern. Actually this would be cat with a condition:

catWhen(when, pattern)

If when is true, returns this.cat(pattern); if when is false, returns this.

gogins commented 1 year ago
gogins commented 1 year ago

This is the most impressive patch I've seen for Strudel: https://strudel.tidalcycles.org/?YtkX3prz4D7h. It dynamically composes an arrange from a whole set of patches.

I searched Strudel's Discord channel for "arrange" and found a lot of people feeling confused, so I'm not the only one.

gogins commented 1 year ago

I'm beginning to get the same feeling about Strudel that I used to have about Jeskola Buzz -- that it is a really cool way of arranging musical thought. But I find I can edit Strudel pieces much much faster than I ever could Buzz pieces.

gogins commented 1 year ago

Investigate:

gogins commented 1 year ago

Major outstanding objectives:

gogins commented 1 year ago

I can't seem to use stack with run. Not true; the problem is, one can't use stack to do differential canons.

gogins commented 1 year ago

What's the difference between off and offset?

/**
 * Superimposes the function result on top of the original pattern, delayed by the given time.
 * @name off
 * @memberof Pattern
 * @param {Pattern | number} time offset time
 * @param {function} func function to apply
 * @returns Pattern
 * @example
 * "c3 eb3 g3".off(1/8, x=>x.add(7)).note()
 */
gogins commented 1 year ago

In Cancycle-5, each note in a chord triggers acST and acSM, not justacSCV. What I need is for there to be only one trigger of acST and acSM at any given time, but acSCV will act as it now does.

Does Strudel's chord do this and, if so, how? In tonal/voicings.mjs, chord is a control, not a Pattern; voicing is a pattern that applies the chord to the note.

There are two ways I can think of to implement the desired behavior:

But this would kind of mix the metaphors and muddy the waters. Problem solved by tracking changes of input to Statefi;Patterns, see below.

gogins commented 1 year ago

Indeed, the CsoundAC objects can be attached to the Hap value as controls.

Hap.value.chord
Hap.value.scale

The problem remains however, as the operations on these objects are still going to be triggered by multiple Patterns.

But see scaleTranspose and related Patterns. The scale is a member of the Hap context.

Problem solved by using changes of inputs to StatefulPatterns, see below.

gogins commented 1 year ago

The solution is simple. Change the state when and only when the value of the Pattern input changes. The trigger may not even be necessary.

The only hackish element of this is the need to have a toggle for Patterns such as acCK that do not essentially involve an input value. In place of the trigger, we use a toggle.

This now seems to be working in the context of a real piece.

gogins commented 1 year ago

Musical objectives for this piece involve "long-scale composition:"

gogins commented 1 year ago

This kind of works for arranging, as it implements silencing sections in the arrangement, but the timing is only correct if each section is the same duration, and slider cannot be used to set the number of repetitions of a segment:

export function arrangeTrack(...sections) {
    sections = sections.filter(function(element) {
        return element[0] >= 1;
    });
    const total = sections.reduce((sum, [cycles]) => sum + cycles, 0);
    sections = sections.map(([cycles, section]) => [cycles, section.fast(cycles)]);
    return timeCat(...sections).slow(total);
};
gogins commented 1 year ago

Differential canons are possible in Strudel only with polymeter but that accepts lists whereas I want it to accept Patterns. And polymeter depends upon the _sequenceCount function.

I don't see how to a version of polymeter that works with Patterns and not lists.

gogins commented 1 year ago

Wrong, differential canons are possible with stack, but the number of cycles in each layer must differ:

stack(
  "<a5 b5 c6>".note().piano().gain(.5),
    "<a2 b2>".note().s("gm_blown_bottle"),
  "<db3 e3 gb3 ab3>".note().s("harp")).fast(6).pianoroll()
gogins commented 1 year ago

Better music visualizers:

gogins commented 1 year ago

Try to get shorter, more percussive sounds using "Emulations and Models" but with sample tables omitted or swapped for generated tables. Two more instruments should do it. Try:

gogins commented 1 year ago

Instruments needing controls in addition to levels:

gogins commented 1 year ago

To make this piece better in the limited time remaining, sections:

  1. Circle map, andante, chiming sounds, mezzo-forte.
  2. Circle map, largo, evolving pads, forte.
  3. run and offset, with jux, plucked string sounds, allegro, forte.
  4. Circle map, andante, mixture of chimes and pads, piano.

Parameters will be preselected, I will vary them during performance.

gogins commented 1 year ago

This is finished enough. I will try to practice and tweak some more before the concert tonight.