kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Mehrstimmigkeit / Polyphony

(EN google-translate)

(PL google-translate)

Die arithmetischen Operationen bewirken eine dauerhafte Transformation. Sie lassen sich ungefähr bestimmten musikalischen Praktiken zuordnen:

  • +n Die gleichen Töne erscheinen, aber um n Ticks früher
  • -n Die gleichen Töne erscheinen, aber um n Ticks später
  • *2 (Beispiel) Oktavierung um eine Oktave nach oben, aber es entstehen zusätzliche Töne
  • /2 (Beispiel) Oktavierung um eine Oktave nach unten, aber es entstehen zusätzliche Töne und durch Abschneiden der Nachkommastellen entstehen auch Tonrepetitionen
  • %n Modulo begrenzt den Zahlenbereich. Sich wiederholende Phrasen entstehen.

The arithmetic operations bring about a permanent transformation. They can be approximately assigned to certain musical practices:

  • +n The same tones appear but n ticks earlier.
  • -n The same tones appear, but n ticks later.
  • *2 (example) Octave up by one octave, but additional tones appear
  • /2 (example) Octave down by one octave, but additional tones appear and by cutting off the decimal places, tone repetitions also appear
  • %n Modulo limits the range of numbers. Repetitive phrases arise.

Übung #2 / Exercise #2

Nachfolgender Sketch zeigt, wie unter Verwendung der Library ComposingForEveryone Mehrstimmigkeit erzeugt werden kann. Erweitern Sie den Sketch auch unter Verwendung des vorangehenden Sketches BASIC_Sound_Of_N_simplified so, dass mit AOG ein mehrstimmiges Stück erzeugt wird. Hinweis: Verwenden Sie für jede Stimme immer den gleichen Tick t, aber jeweils andere arithmetische Operationen. Werfen Sie auch einen Blick auf den Sketch CFE bei den Beispielen zu ComposingForEveryone.

The following sketch shows how to create polyphony using the ComposingForEveryone library. Extend the sketch also using the previous sketch BASIC_Sound_Of_N_simplified so that a polyphonic piece is created with AOG. Note: Always use the same tick t for each voice, but different arithmetic operations for each. Also take a look at the CFE sketch in the ComposingForEveryone examples.

Polyphony.zip -- Download of the following sketch.
import processchains.*;
import processchains.wavfiles.WavLoader;
import processchains.Pulse;
import processchains.Utilities;

int BPM = 216;

Seq seq;
    
public void setup()
{
    //fullScreen();  // better for usage with an Android device
    size(640,480);   // better for testing it on a PC.
    seq = new Seq(this); 
    orientation(LANDSCAPE);            
    
    frameRate(5);   
}

int COUNTER=0;

public void draw()
{
    background(230,230,230);
    int voice = COUNTER%4;
    int frequency = 110*(COUNTER%13 +1);
    seq.play(voice, frequency, 40.0);
    
    COUNTER++;
}

Code 0-1: Main tab of the Sketch "Polyphony".

import processchains.*;
import processchains.wavfiles.WavLoader;

import processing.core.*;

public class Seq
{
    
    WavInstrument[] inst;
    
    Instruments2Channel inst2chan;
    ChannelMapper channelmapper;
    Channel2Buffer channel2buffer;
    Soundcard soundcard;
    public double[][] volume = 
    {
       {0.04,0.02},
       {0.03,0.06},
       {0.11,0.17},
       {0.05,0.04}
    };   
    
    public double[][] volume_copy = 
    {
       {0.04,0.02},
       {0.03,0.06},
       {0.11,0.17},
       {0.05,0.04}
    };   
    
    public Seq(PApplet pap)
    {
        int number_of_channels = 2;
        int sample_rate = 44100;
        int buffer_size = 512;
        
        int max_poly = 100;
        int instrument_specification_index = 1; //piano 2  [0..20]
        
        inst = new WavInstrument[4];  //EXPERIMENT 3: TRY OUT VARIOUS SOUND COMBINATIONS
        inst[0]   = new WavInstrument(pap,number_of_channels,sample_rate,0,1,max_poly,12,4000,2000,0.0); //viol_p_ton
        inst[1]   = new WavInstrument(pap,number_of_channels,sample_rate,0,1,max_poly,33); //vibraphone_ton
        inst[2]   = new WavInstrument(pap,number_of_channels,sample_rate,0,1,max_poly,7); //bass1_ton 
        inst[3]   = new WavInstrument(pap,number_of_channels,sample_rate,0,1,max_poly,30,100,41,-10.0);//clar3_long_ton
        inst[3].setMidimin(55);
        inst[3].setMidimax(79);
           
        for(int i=0;i<inst.length;i++)
            inst[i].setSource(volume[i]);
                
        inst2chan = new Instruments2Channel(sample_rate,buffer_size,number_of_channels);
        inst2chan.setSource(inst);
        
        channelmapper = new ChannelMapper(new int[] {0, 1});    
        channelmapper.setSource(inst2chan.getSink());
        inst2chan.registerSuccessor(channelmapper);
        
        channel2buffer = new Channel2Buffer(sample_rate,buffer_size,number_of_channels); 
        channel2buffer.setSource(channelmapper.getSink());
        channelmapper.registerSuccessor(channel2buffer);

        soundcard = new Soundcard(sample_rate,buffer_size,number_of_channels);
        soundcard.setSource(channel2buffer.getSink());
        channel2buffer.registerSuccessor(soundcard);
    }
    
    public boolean play(int voice, int frequency, float VELOCITY)
    {
        int midi = Utilities.freq2mid(frequency);
                    
        if(midi>=inst[voice].getMidimin() && midi<=inst[voice].getMidimax())
        {
            if(voice==3 )
               inst[voice].stop(200); //violine  / organ / clar EXPERIMENT 4: STOPPING OR NOT BEFORE NEXT TONE 
            //if(voice==0 )
            //   inst[voice].stop(200); //violine  / organ / clar EXPERIMENT 4: STOPPING OR NOT BEFORE NEXT TONE 
               
            inst[voice].play(midi,VELOCITY*(float)volume[voice][0],VELOCITY*(float)volume[voice][1]);
            
            return true;
        }    
        else
        {
            return false;
        }
    }
}

Code 0-2: Secondary tab of the Sketch "Polyphony", class Sequencer, again using other classes inside ComposingForEveryone.




Eine mögliche Lösung zu Übung 2 / a possible solution of exercise #2




import processchains.*;
import processchains.wavfiles.WavLoader;
import processchains.Pulse;
import processchains.Utilities;

int BPM = 216;

Seq seq;
    
public void setup()
{
    //fullScreen();  // better for usage with an Android device
    size(640,480);   // better for testing it on a PC.
    seq = new Seq(this); 
    orientation(LANDSCAPE);            
    
    frameRate(5);   
}

int t=9000;

public boolean selectiveDivisionAndPlay(int ff, int tt, int voice, float velocity)
{
  int fff = 1;
    while(tt>=2 && tt%2==0 && ff>=2 && ff%2==0) {tt/=2;ff/=2;fff*=2;}
    while(tt>=3 && tt%3==0 && ff>=3 && ff%3==0) {tt/=3;ff/=3;fff*=3;}
    while(tt>=5 && tt%5==0 && ff>=5 && ff%5==0) {tt/=5;ff/=5;fff*=5;}
    while(tt>=7 && tt%7==0 && ff>=7 && ff%7==0) {tt/=7;ff/=7;fff*=7;}
    
    //VARIANT FOR SELECTIVE MULTIPLICATION:
    //double f = (double)fff;
    //f*=0.25;

    //VARIANT FOR SELECTIVE DIVISION:
    double f = (double)ff;
    f*=0.07;
    
    println(f);
    return seq.play(voice,(int)(f+0.5),velocity);  
}

int ZUSATZFAKTOR=0;

public void draw()
{
    if(ZUSATZFAKTOR<24*33)
    {
        background(230,230,230);
    }
    else
    {
        background(230,0,0);
        return;
    }
    int BASE = 2*2*2*2*3*3*5*7;
    
    BASE = BASE * ((ZUSATZFAKTOR/24)%8+1);  //slowly change basenumber
    ZUSATZFAKTOR++;
    
    int x1 = t*9;
    int x2 = t*12;
    int x3 = t*3;
    int x4 = t*6;
    
    boolean played1 = selectiveDivisionAndPlay(BASE,x1,0,60.0);
    boolean played2 = selectiveDivisionAndPlay(BASE,x2,1,60.0);
    boolean played3 = selectiveDivisionAndPlay(BASE,x3,2,60.0);
    boolean played4 = selectiveDivisionAndPlay(BASE,x4,3,60.0);
 
    if(!played1)
    {
        x1*=2;
        played1 = selectiveDivisionAndPlay(BASE,x1,0,40.0);
    }
    if(!played2)
    {
        x2*=8;
        played2 = selectiveDivisionAndPlay(BASE,x2,0,40.0);
    }
    if(!played3)
    {
        x3*=4;
        played3 = selectiveDivisionAndPlay(BASE,x3,0,40.0);
    }
    if(!played4)
    {
        x4*=16;
        played4 = selectiveDivisionAndPlay(BASE,x4,0,40.0);
    }

    if(!played1 && x1%2==0)
    {
        x1/=2;
        played1 = selectiveDivisionAndPlay(BASE,x1,0,20.0);
    }
    if(!played2)
    {
        x2%=8;
        played2 = selectiveDivisionAndPlay(BASE,x2,0,20.0);
    }
    if(!played3 && x3%4==0)
    {
        x3/=4;
        played3 = selectiveDivisionAndPlay(BASE,x3,0,20.0);
    }
    if(!played4)
    {
        x4%=16;
        played4 = selectiveDivisionAndPlay(BASE,x4,0,20.0);
    }
    
    
    
    t = t + 1;
}

Code 0-3: Sourcecode for the main sketch of Polyphony2, which is a possible solution for exercise #2.

Polyphony2.zip -- Download of the project Polyphony2.
Sound of Polyphony2 on youtube.

Hinweise / Hints

  • During the course at Porto in September 2021 something went wrong with the code. So here comes now a corrected version.
  • Here also the basenumber is changing slowly, see lines 57,58 in the processing sketch.
  • For each of three operations the tone is played if possible.
  • If a tone was played due to a previous operation, the next ones are ignored, see "if(played1 ... )" and so on.
  • The operation division was changed a bit: Only if it is possible without rest it is applied. Thus repetitions are suppressed.
  • The code shows also a possibility to control volume or other articulation parameters: The volume depends on which of three successing operations are applied in one formula.
  • The violin is not stopped when a new tone should be played. Thus, it provides a kind of harmonic ground to the piece.
  • The lines 46 to 54 cause that the piece will terminate after a while.
  • By changing two lines it is possible to switch from selective division to selective multiplication, see lines 30 to 36.
  • Please be aware that also the second tab, this is class Sequencer remains the same as in Polyphony (changed 11th of Sep. 2021).