HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Musical Fizzbuzz

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
musicalfizzbuzzstackoverflow

Problem

I wrote some code using ChucK : Strongly-timed, Concurrent, and On-the-fly
Music Programming Language and would like a review. I broke down the logic into a number of classes, all of which are shown below.

This is pretty new to me, and I would appreciate any and all constructive criticism. What the main script fizzbuzz_run.ck does, besides the regular FizzBuzz modulus operations, is play different chords depending on the FizzBuzz result, and throughout print the results and primary oscillator frequency.

Clarification

I want to clarify a few things that are specific to ChucK:

  • printing statements to console: >>;



  • The ChucK operator => is a bit like your usual assignment, except reverse order. For example 42 => int theMeaningOfLifeAndEverything; is how you would otherwise int theMeaningOfLifeAndEverything = 42;.



  • Time and duration are handled by the ChucK VM.



Code on Github

I uploaded a video to YouTube showing what it sounds like. (video not embedded, link opens YouTube)

OscPitch.ck

```
public class OscPitch {
this.freq => float freq;
getSemitoneRatio() => float SEMITONE;

// Change the pitch by N musical steps
// @param float steps : the number of steps to change the frequency, positive or negative
// @return float : the changed frequency
fun float change(float steps) {
if (Math.isnan(steps)) {
>>;
return freq;
} else {
// The semitone ratio has to be applied once for each step change
// hence the use of Math.pow which does everything
// in one operation, rather than having to use a loop
return freq * Math.pow(SEMITONE, steps) => freq;
}
}

// Get the ratio to apply to a frequency to go up or down one semitone
fun float getSemitoneRatio() {
// The ratio for a musical semitone is
// the 12th root of 2, or approximately 1.05946309436
// More info: https://en.wikipedia.org/wiki/Twelfth_ro

Solution

Really interesting thing you've created! I've never used ChucK, but I'll try to comment on some things. I also have some, but limited music theory knowledge. If language constraints is a reason for doing something I've mentioned below, please excuse my ignorance :)

Semitone ratio?

I wonder why you chose to create the getSemitoneRatio function. It's only used to initialize the SEMITONE variable. Why not just remove that function and put the body as the initializer expression instead?

Additionally, I wouldn't actually call it a ratio. It's a factor.

// The factor to apply to a frequency to go up or down one semitone
// More info: https://en.wikipedia.org/wiki/Twelfth_root_of_two
Math.pow(2.0, 1.0/12.0) => float SEMITONE_FACTOR;


Dry initialization

// initialize oscillators
0 => I.freq;
0 => III.freq;
0 => V.freq;
0 => VII.freq;
mute => I.gain;
mute => III.gain;
mute => V.gain;
mute => VII.gain;
I   => dac;
III => dac;
V   => dac;
VII => dac; 

// Sets all chord frequencies to 0, making them inaudible.
fun void noChord() {
    0 => I.freq;
    0 => III.freq;
    0 => V.freq;
    0 => VII.freq;
    "no chord" => currentChord;
}


Since you already have the noChord function you can easily remove part of this code duplication. Just call noChord instead of the first four lines after the comment. The side-effect of initializing currentChord as well is probably just good.

Dry initialization 2

Another approach to this is creating a factory function for SawOsc. Compare the following examples.

SawOsc I, III, V, VII;

0 => I.freq;
0 => III.freq;
0 => V.freq;
0 => VII.freq;
mute => I.gain;
mute => III.gain;
mute => V.gain;
mute => VII.gain;


createSawOsc(0, mute) => SawOsc I;
createSawOsc(0, mute) => SawOsc III;
createSawOsc(0, mute) => SawOsc V;
createSawOsc(0, mute) => SawOsc VII;


Gain?

In OscChord there are two variables representing different gain levels.

0.05 => float gain;
0.0 => float mute;


It's confusing that one is just named gain while the other one is called mute. Perhaps call them muteGain and playGain to show their relationship.

Code Snippets

// The factor to apply to a frequency to go up or down one semitone
// More info: https://en.wikipedia.org/wiki/Twelfth_root_of_two
Math.pow(2.0, 1.0/12.0) => float SEMITONE_FACTOR;
// initialize oscillators
0 => I.freq;
0 => III.freq;
0 => V.freq;
0 => VII.freq;
mute => I.gain;
mute => III.gain;
mute => V.gain;
mute => VII.gain;
I   => dac;
III => dac;
V   => dac;
VII => dac; 

// Sets all chord frequencies to 0, making them inaudible.
fun void noChord() {
    0 => I.freq;
    0 => III.freq;
    0 => V.freq;
    0 => VII.freq;
    "no chord" => currentChord;
}
SawOsc I, III, V, VII;

0 => I.freq;
0 => III.freq;
0 => V.freq;
0 => VII.freq;
mute => I.gain;
mute => III.gain;
mute => V.gain;
mute => VII.gain;
createSawOsc(0, mute) => SawOsc I;
createSawOsc(0, mute) => SawOsc III;
createSawOsc(0, mute) => SawOsc V;
createSawOsc(0, mute) => SawOsc VII;
0.05 => float gain;
0.0 => float mute;

Context

StackExchange Code Review Q#106791, answer score: 9

Revisions (0)

No revisions yet.