Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-release > by-pkgid > 5fcfcb7517038d1f44ab4e478e6e61fa > files > 2023

csound-doc-6.10.0-1.mga7.noarch.rpm

/**
S I L E N C I O

Copyright (C) 2014 by Michael Gogins

This software is licensed under the terms of the
GNU Lesser General Public License

Part of Silencio, an algorithmic music composition library for Csound.

DEVELOPMENT LOG

2015-07-15

Silencio.js was relatively easy, ChordSpace.js is going to be harder. The main
problems are that JavaScript does not permit operator overloading, and it does
not implement deep clones or deep value comparisons out of the box.

 I will omit the chord space group stuff because it will not always be
 possible to save the chord space group files, which are necessarily for
 efficient use with chords of more than 3 or 4 voices.

It is now clear that Lua (and especially LuaJIT) is a rather superior
language; and yet, JavaScript provides everything that I need.

TO DO

--  Implement various scales found in 20th and 21st century harmony
    along with 'splitting' and 'merging' operations.

--  Implement tendency masks.

--  Implement Xenakis sieves.

*/

(function() {
/**
A Score is a matrix in which the rows are Events.

An Event is a homogeneous vector with the following dimensions:

 1 Time in seconds from start of performance.
 2 Duration in seconds.
 3 MIDI status (only the most significant nybble, e.g. 144 for 'NOTE ON').
 4 MIDI channel (any real number >= 0, fractional part ties events).
 5 MIDI key number from 0 to 127, 60 is middle C (a real number).
 6 MIDI velocity from 0 to 127, 80 is mezzo-forte (a real number).
 7 x or depth, 0 is the origin.
 8 y or pan, 0 is the origin.
 9 z or heigth, 0 is the origin.
10 Phase, in radians.
11 Homogeneity, normally always 1.

NOTE: ECMASCRIPT 5 doesn't support inheritance from Array
in a clean and complete way, so we don't even try.
*/

function eq_epsilon(a, b) {
  var epsilon_factor = 100 * Number.EPSILON;
  if (Math.abs(a - b) > epsilon_factor) {
    return false;
  }
  return true;
}

function lt_epsilon(a, b) {
  if (eq_epsilon(a, b)) {
    return false;
  }
  if (a < b) {
    return true;
  }
  return false;
}

function le_epsilon(a, b) {
  if (eq_epsilon(a, b)) {
    return true;
  }
  if (a < b) {
    return true;
  }
  return false;
}

function gt_epsilon(a, b) {
  if (eq_epsilon(a, b)) {
    return false;
  }
  if (a > b) {
    return true;
  }
  return false;
}

function ge_epsilon(a, b) {
  if (eq_epsilon(a, b)) {
    return true;
  }
  if (a > b) {
    return true;
  }
  return false;
}

function Event() {
  this.data = [0,0,144,0,0,0,0,0,0,0,1];
  this.chord = null;
  Object.defineProperty(this,"time",{
    get: function() { return this.data[0]; },
    set: function(value) { this.data[0] = value; }
  });
  Object.defineProperty(this,"duration",{
    get: function() { return this.data[1]; },
    set: function(value) { this.data[1] = value; }
  });
  Object.defineProperty(this,"end",{
    get: function() {
      return this.data[0] + this.data[1];
    },
    set: function(end_) {
        var duration_ = end_ - this.data[0];
        if (duration_ > 0) {
            this.data[1] = duration_;
        } else {
            this.data[0] = this.data[0] + duration_;
            this.data[1] = -1 * duration_;
        }
    }
  });
  Object.defineProperty(this,"status",{
    get: function() { return this.data[2]; },
    set: function(value) { this.data[2] = value; }
  });
  Object.defineProperty(this,"channel",{
    get: function() { return this.data[3]; },
    set: function(value) { this.data[3] = value; }
  });
  Object.defineProperty(this,"key",{
    get: function() { return this.data[4]; },
    set: function(value) { this.data[4] = value; }
  });
  Object.defineProperty(this,"velocity",{
    get: function() { return this.data[5]; },
    set: function(value) { this.data[5] = value; }
  });
  Object.defineProperty(this,"depth",{
    get: function() { return this.data[6]; },
    set: function(value) { this.data[6] = value; }
  });
  Object.defineProperty(this,"pan",{
    get: function() { return this.data[7]; },
    set: function(value) { this.data[7] = value; }
  });
  Object.defineProperty(this,"heigth",{
    get: function() { return this.data[8]; },
    set: function(value) { this.data[8] = value; }
  });
  Object.defineProperty(this,"phase",{
    get: function() { return this.data[9]; },
    set: function(value) { this.data[9] = value; }
  });
  Object.defineProperty(this,"homogeneity",{
    get: function() { return this.data[10]; Event.TIME = 0;},
    set: function(value) { this.data[10] = value; }
  });
}
Event.TIME = 0;
Event.DURATION = 1;
Event.STATUS = 2;
Event.CHANNEL = 3;
Event.KEY = 4;
Event.VELOCITY = 5;
Event.X = 6;
Event.Y = 7;
Event.Z = 8;
Event.PHASE = 9;
Event.HOMOGENEITY = 10;
Event.COUNT = 11;

Event.prototype.toString = function() {
  var text = '';
  for (var i = 0; i < this.data.length; i++) {
    text = text.concat(' ', this.data[i].toFixed(6));
  }
  text = text.concat('\n');
  return text;
}

Event.prototype.toIStatement = function() {
  var text = 'i';
  text = text.concat(' ', this.data[3].toFixed(6));
  text = text.concat(' ', this.data[0].toFixed(6));
  text = text.concat(' ', this.data[1].toFixed(6));
  text = text.concat(' ', this.data[4].toFixed(6));
  text = text.concat(' ', this.data[5].toFixed(6));
  text = text.concat(' ', this.data[6].toFixed(6));
  text = text.concat(' ', this.data[7].toFixed(6));
  text = text.concat(' ', this.data[8].toFixed(6));
  text = text.concat(' ', this.data[9].toFixed(6));
  return text;
}

Event.prototype.temper = function(tonesPerOctave) {
  if (typeof tonesPerOctave === 'undefined') {
      tonesPerOctave = 12;
  }
  var octave = this.key / 12;
  var tone = Math.floor((octave * tonesPerOctave) + 0.5);
  octave = tone / tonesPerOctave;
  this.key = octave * 12;
}

Event.prototype.clone = function() {
  other = new Event();
  other.data = this.data.slice(0);
  return other;
}

function Score() {
  this.data  = [];
  this.minima = new Event();
  this.maxima = new Event();
  this.ranges = new Event();
}
Score.prototype.add = function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) {
  var event = new Event();
  for (var i = 0; i < event.data.length; i++) {
    if (typeof arguments[i] !== 'undefined') {
      event.data[i] = arguments[i];
     }
  }
  this.data.push(event);
}

Score.prototype.append = function(event) {
  this.data.push(event);
}

Score.prototype.clear = function () {
  while(this.data.length > 0) {
    this.data.pop();
  }
}

Score.prototype.getDuration = function () {
  this.sort();
  this.findScale(0);
  var duration = 0;
  for (var i = 0; i < this.data.length; i++) {
    var event = this.data[i];
    if (i == 0) {
      duration = event.end; //data[0] + event.data[1];
    } else {
      var currentDuration = event.end; //data[0] + event.data[1];
      if (currentDuration > duration) {
        duration = currentDuration;
      }
    }
  }
  return duration;
}

Score.prototype.log = function (what) {
  if (typeof what === 'undefined') {
    what = '';
  } else {
    what = what + ': ';
  }
  for (var i = 0; i < this.data.length; i++) {
    var event = this.data[i];
    csound.message(what + event.toString());
  }
}

Score.prototype.setDuration = function (duration) {
  this.sort();
  var start = this.data[0].time;
  for (var i = 0; i < this.data.length; i++) {
    var event = this.data[i];
    event.data[0] = event.data[0] - start;
  }
  var currentDuration = this.data[0].end;
  for (var i = 0; i < this.data.length; i++) {
    var event = this.data[i];
    if (event.end > currentDuration) {
      currentDuration = event.end;
    }
  }
  var factor = Math.abs(duration / currentDuration);
  for (var i = 0; i < this.data.length; i++) {
    var event = this.data[i];
    event.data[0] = event.data[0] * factor;
    event.data[1] = event.data[1] * factor;
  }
}

Score.prototype.sendToCsound = function(csound, extra) {
    if (typeof extra === 'undefined') {
        jscore = '';
    } else {
        extra = 5.0;
        this.sort();
        var duration = this.getDuration() + extra;
        jscore = 'f 0 ' + duration + ' 0\n';
    }
    for (var i = 0; i < this.data.length; i++) {
        var event = this.data[i];
        var pfields = [];
        pfields.push(event.data[3]);
        pfields.push(event.data[0]);
        pfields.push(event.data[1]);
        pfields.push(event.data[4]);
        pfields.push(event.data[5]);
        pfields.push(event.data[6]);
        pfields.push(event.data[7]);
        pfields.push(event.data[8]);
        pfields.push(event.data[9]);
    }
    csound.scoreEvent('i', pfields);
  //for (var i = 0; i < this.data.length; i++) {
  //  jscore += this.data[i].toIStatement() + '\n';
  //}
  // Still too slow!...
  //csound.inputMessage(jscore);
}

Score.prototype.findScales = function() {
  for (var i = 0; i < this.minima.data.length; i++) {
    this.findScale(i);
  }
}

Score.prototype.findScale = function(dimension) {
  var min = Number.NaN;
  var max = Number.NaN;
  for (var i = 0; i < this.data.length; i++) {
    var value = this.data[i].data[dimension];
    if (i === 0) {
      min = value;
      max = value;
    } else {
      if (value < min) {
        min = value;
      }
      if (value > max) {
        max = value;
      }
    }
  }
  this.minima.data[dimension] = min;
  this.maxima.data[dimension] = max;
  this.ranges.data[dimension] = max - min;
}

Score.prototype.setScale = function(dimension, minimum, range) {
  this.findScale(dimension);
  var toOrigin = this.minima.data[dimension];
  var currentRange = this.ranges.data[dimension];
  if (currentRange === 0) {
    currentRange = 1;
  }
  var rescale = range / currentRange;
  if (typeof range === 'undefined') {
    rescale = 1;
  }
  var translate = minimum;
  for (var i = 0; i < this.data.length; i++) {
    var value = this.data[i].data[dimension];
    value -= toOrigin;
    value *= rescale;
    value += translate;
    this.data[i].data[dimension] = value;
  }
}

Score.prototype.temper = function(tonesPerOctave) {
  for (var i = 0; i < this.data.length; i++) {
    this.data[i].temper(tonesPerOctave);
  }
}

Score.prototype.sort = function() {
  this.data.sort(eventComparator);
}

Score.prototype.tieOverlaps = function(tieExact) {
  csound.message("Before tieing: " + this.data.length + "\n");
  if (typeof tieExact === 'undefined') {
      tieExact = false;
  }
  this.sort();
  for (var laterI = this.data.length - 1; laterI >= 0; laterI--) {
    var laterEvent = this.data[laterI];
    if (laterEvent.status === 144) {
        for (var earlierI = laterI - 1; earlierI >= 0; earlierI--) {
          var earlierEvent = this.data[earlierI];
        if (earlierEvent.status === 144) {
          var overlaps = false;
          if (tieExact) {
            overlaps = ge_epsilon(earlierEvent.end, laterEvent.time);
          } else {
            overlaps = gt_epsilon(earlierEvent.end, laterEvent.time);
          }
          if (overlaps === true) {
            if ((Math.floor(earlierEvent.channel) === Math.floor(laterEvent.channel)) &&
                (Math.round(earlierEvent.key) === Math.round(laterEvent.key)))
          {
              //console.log('Tieing: ' + earlierI + ' ' + earlierEvent.toString());
              //console.log('    to: ' + laterI + ' ' + laterEvent.toString());
              earlierEvent.end = laterEvent.end;
              laterEvent.duration = 0;
              laterEvent.velocity = 0;
              //console.log('Result: ' + earlierI + ' ' +  earlierEvent.toString() + '\n');
              break;
          }
        }
      }
    }
  }
  }
  // Get rid of notes that will not sound (again).
  for (var laterI = this.data.length - 1; laterI >= 0; laterI--) {
    var laterEvent = this.data[laterI];
    if (laterEvent.status === 144) {
      if ((laterEvent.duration <= 0) || (laterEvent.velocity <= 0)) {
        this.data.splice(laterI, 1);
      }
    }
  }
  csound.message("After tieing: " + this.data.length + "\n");
}

Score.prototype.draw = function(canvas, W, H) {
  this.findScales();
  csound.message("minima:  " + this.minima + "\n");
  csound.message("ranges:  " + this.ranges + "\n");
  var xsize = this.getDuration();
  var ysize = this.ranges.key;
  var xscale = Math.abs(W / xsize);
  var yscale = Math.abs(H / ysize);
  var xmove = - this.minima.time;
  var ymove = - this.minima.key;
  var context = canvas.getContext("2d");
  context.scale(xscale, yscale);
  context.translate(xmove, ymove);
  csound.message("score:  " + xsize + ", " + ysize + "\n");
  csound.message("canvas: " + W + ", " + H + "\n");
  csound.message("scale:  " + xscale + ", " + yscale + "\n");
  csound.message("move:   " + xmove + ", " + ymove + "\n");
  var channelRange = this.ranges.channel;
  if (channelRange == 0) {
    channelRange = 1;
  }
  var velocityRange = this.ranges.velocity;
  if (velocityRange == 0) {
    velocityRange = 1;
  }
  for (var i = 0; i < this.data.length; i++) {
    var x1 = this.data[i].time;
    var x2 = this.data[i].end;
    var y = this.data[i].key;
    var hue = this.data[i].channel - this.minima.channel;
    hue = hue / channelRange;
    var value = this.data[i].velocity - this.minima.velocity;
    value = value / velocityRange;
    value = .5 + value / 2;
    var hsv = "hsv("+hue+","+1+","+value+")";
    context.strokeStyle = tinycolor(hsv).toHexString();
    //csound.message("color: " + context.strokeStyle + "\n");
    //context.strokeStyle = 'red';
    context.beginPath();
    context.moveTo(x1, y);
    context.lineTo(x2, y);
    context.stroke();
    //csound.message("note " + i + ": " + x1 + ", " + x2 + ", " + y + "\n");
  }
}

Score.prototype.toString = function() {
    var result = '';
    for (var i = 0; i < this.data.length; i++) {
        var event = this.data[i];
        result = result.concat(event.toString());
    };
    return result;
};

Score.prototype.size = function() {
    return this.data.length;
};

Score.prototype.get = function(index) {
    return this.data[index];
};

// Returns the sub-score containing events
// starting at or later than the begin time,
// and up to but not including the end time.
// The events in the slice are references.
Score.prototype.slice = function(begin, end_) {
    this.sort();
    var s = new Silencio.Score();
    for (var index = 0; index < this.size(); index++) {
        var event = this.data [index];
        var time_ = event.time;
        if (time_ >= begin && time_ < end_) {
            s.append(event.clone ());
        };
    };
    return s;
};

function eventComparator(a, b) {
  for (var i = 0; i < a.data.length; i++) {
    var avalue = a.data[i];
    var bvalue = b.data[i];
    var difference = avalue - bvalue;
    if (difference !== 0) {
      return difference
    }
  }
  return 0;
}

function Turtle(len, theta) {
  this.len = len;
  this.theta = theta;
  this.reset();
  return this;
}
Turtle.prototype.reset = function() {
  this.angle = Math.PI/2;
  this.p = {'x': 0, 'y': 0};
  this.stack = [];
  this.instrument = 'red';
  this.tempo = 1;
  this.event = new Silencio.Event();
 };
Turtle.prototype.next = function() {
  return {
    'x': this.p.x+this.len*this.tempo*Math.cos(this.angle),
    'y': this.p.y-this.len*Math.sin(this.angle)
  };
};
Turtle.prototype.go = function(context) {
  var nextP = this.next();
  context.strokeStyle = tinycolor(this.instrument).toString();
  context.beginPath();
  context.moveTo(this.p.x, this.p.y);
  context.lineTo(nextP.x, nextP.y);
  context.stroke();
  this.p = nextP;
};
Turtle.prototype.move = function() {
  this.p = this.next();
};
Turtle.prototype.turnLeft = function() {
  this.angle += this.theta;
};
Turtle.prototype.turnRight = function() {
  this.angle -= this.theta;
};
Turtle.prototype.upInstrument = function() {
  this.instrument = tinycolor(this.instrument).spin(10);
};
Turtle.prototype.downInstrument = function() {
  this.instrument = tinycolor(this.instrument).spin(-10);
};
Turtle.prototype.upVelocity = function() {
  this.instrument = tinycolor(this.instrument).darken(-1);
};
Turtle.prototype.downVelocity = function() {
  this.instrument = tinycolor(this.instrument).darken(1);
};
Turtle.prototype.upTempo = function() {
  this.tempo = this.tempo / 1.25;
};
Turtle.prototype.downTempo = function() {
  this.tempo = this.tempo * 1.25;
};
Turtle.prototype.push = function() {
  this.stack.push({'p': this.p, 'angle': this.angle, 'instrument': this.instrument, 'tempo': this.tempo, 'event': this.event.clone()});
};
Turtle.prototype.pop = function() {
  var s = this.stack.pop();
  this.p = s.p;
  this.angle = s.angle;
  this.instrument = s.instrument;
  this.tempo = s.tempo;
  this.event = s.event;
};
function LSys() {
  this.axiom = '';
  this.rules = {};
  this.prior = '';
  this.score = new Silencio.Score();
  return this;
}
LSys.prototype.addRule = function(c, replacement) {
  this.rules[c] = replacement;
}
LSys.prototype.generate = function(n) {
  this.sentence = this.axiom;
  for (var g = 0; g < n; g++) {
    var next = [];
    for (var i=0; this.sentence.length > i; i++) {
      var c = this.sentence[i];
      var r = this.rules[c];
      if (r) {
        next.push(r);
      } else {
        next.push(c);
      }
    }
    this.sentence = next.join("");
  }
};
LSys.prototype.draw = function(t, context, W, H) {
  context.fillStyle = 'black';
  context.fillRect(0, 0, W, H);
  // Draw for size.
  t.reset();
  var size = [t.p.x, t.p.y, t.p.x, t.p.y];
  for (var i=0; this.sentence.length > i; i++) {
    var c = this.sentence[i];
    this.interpret(c, t, context, size);
  }
  // Draw to show.
  var xsize = size[2] - size[0];
  var ysize = size[3] - size[1];
  var xscale = Math.abs(W / xsize);
  var yscale = Math.abs(H / ysize);
  var xmove = - size[0];
  var ymove = - size[1];
  context.scale(xscale, yscale);
  context.translate(xmove, ymove);
  t.reset();
  for (var i=0; this.sentence.length > i; i++) {
    var c = this.sentence[i];
    this.interpret(c, t, context);
  }
};
LSys.prototype.findSize = function(t, size) {
  if (t.p.x < size[0]) {
    size[0] = t.p.x;
  }
  if (t.p.y < size[1]) {
    size[1] = t.p.y;
  }
  if (t.p.x > size[2]) {
    size[2] = t.p.x;
  }
  if (t.p.y > size[3]) {
    size[3] = t.p.y;
  }
};
Turtle.prototype.startNote = function() {
  var hsv = tinycolor(this.instrument).toHsv();
  this.event = new Silencio.Event();
  this.event.channel = hsv.h;
  this.event.time = this.p.x;
  this.event.key = - this.p.y;
  this.event.velocity = hsv.v;
  this.event.pan = Math.random();
}
Turtle.prototype.endNote = function(score) {
  this.event.end = this.p.x;
  if (this.event.duration > 0) {
    var event = this.event.clone();
    score.data.push(event);
  }
}
LSys.prototype.interpret = function(c, t, context, size) {
  //csound.message('c:' + c + '\n');
  if (c === 'F') {
    if (typeof size === 'undefined') {
      t.startNote();
      t.go(context);
    } else {
      t.move();
    }
  }
  else if (c === 'f') t.move();
  else if (c === '+') t.turnRight();
  else if (c === '-') t.turnLeft();
  else if (c === '[') t.push();
  else if (c === ']') t.pop();
  else if (c === 'I') t.upInstrument();
  else if (c === 'i') t.downInstrument();
  else if (c === 'V') t.upVelocity();
  else if (c === 'v') t.downVelocity();
  else if (c === 'T') t.upTempo();
  else if (c === 't') t.downTempo();
  if (typeof size === 'undefined') {
    if (c === 'F') {
      t.endNote(this.score);
    }
    this.prior = c;
  } else {
      this.findSize(t, size);
  }

};

/**
Generates scores by recursively applying a set of generating
functions to a single initial musical event.
This event can be considered to represent a cursor within a score.
The generating functions may move this cursor around
within the score, as if moving a pen, and may at any time write the
current state of the cursor into the score, or write other events
based, or not based, upon the cursor into the score.

The generating functions may be lambdas. Generated notes must not
be the same object as the cursor, but may be clones of the cusor,
or entirely new objects.

cursor          A Silencio.Event object that represents a position in a
                musical score. This could be a note, a grain of sound, or
                a control event.

depth           The current depth of recursion. This must begin > 1.
                For each recursion, the depth is decremented. Recursion
                ends when the depth reaches 0.

Returns the next position of the cursor, and optionally, a table of
generated events.

generator = function(cursor, depth);
{cursor, events} = generator(cursor, depth);

The algorithm is similar to the deterministic algorithm for computing the
attractor of a recurrent iterated function systems. Instead of using
affine transformation matrixes as the RIFS algorithm does, the current
algorithm uses generating functions; but if each generating function
applies a single affine transformation to the cursor, the current
algorithm will in fact compute a RIFS.

generators      A list of generating functions with the above signature.
                Unlike RIFS, the functions need not be contractive.

transitions     An N x N transition matrix for the N generating functions.
                If entry [i][j] is 1, then if the current generator is the
                ith, then the jth generator will be applied to the current
                cursor after the ith; if the entry is 0, the jth generator
                will not be applied to the current cursor after the ith.
                In addition, each generator in the matrix must be reached
                at some point during recursion.

depth           The current depth of recursion. This must begin > 1.
                For each recursion, the depth is decremented. Recursion
                ends when the depth reaches 0.

index           Indicates the current generating function, i.e. the
                index-th row of the transition matrix.

cursor          A Silencio.Event object that represents a position in a
                musical score. This could be a note, a grain of sound, or
                a control event.

score           A Silencio.Score object that collects generated events.
*/

function RecurrentResult(c) {
  this.cursor = c;
  this.events = [];
  return this;
}

function Recurrent(generators, transitions, depth, index, cursor, score)
{
    depth = depth - 1;
    //print(string.format('Recurrent(depth: %d  index: %d  cursor: %s)', depth, index, cursor:__tostring()))
    if (depth == 0) {
        return;
    }
    var transitionsForThisIndex = transitions[index];
    for (var j = 0; j < transitionsForThisIndex.length; j++) {
        if (transitionsForThisIndex[j] == 1) {
            var result = generators[j](cursor.clone(), depth);
            for (var i = 0; i < result.events.length; i++) {
                score.append(result.events[i].clone());
            }
            Recurrent(generators, transitions, depth, j, result.cursor.clone(), score);
        }
    }
}

console.log('browser:  ' + navigator.appName)
console.log('platform: ' + navigator.platform)
var Silencio = {
  eq_epsilon: eq_epsilon,
  gt_epsilon: gt_epsilon,
  lt_epsilon: lt_epsilon,
  ge_epsilon: ge_epsilon,
  le_epsilon: le_epsilon,
  Event: Event,
  Score: Score,
  Turtle: Turtle,
  LSys: LSys,
  RecurrentResult: RecurrentResult,
  Recurrent: Recurrent
};
// Node: Export function
if (typeof module !== "undefined" && module.exports) {
    module.exports = Silencio;
}
// AMD/requirejs: Define the module
else if (typeof define === 'function' && define.amd) {
    define(function () {return Silencio;});
}
// Browser: Expose to window
else {
    window.Silencio = Silencio;
}

})();