Τα βασικά

Τα δομικα στοιχεια σε περιληψη

  • client/server: η βασικη αρχιτεκτονικη
  • OSC: η low-level γλωσσα επικοινωνιας μεταξυ μηχανων
  • RT/NRT: πραγματικος και μη χρονος
  • sclang: η γλωσσα επικοινωνιας μεταξυ ανθρωπων και μηχανων
    • SynthDef
    • Patterns
    • UGens

Το client/server μοντέλο

Ενας απο τους λογους που ο Supercollider (SC) είναι ισως πιό δύσκολος απο μια τυπικη "εφαρμογή" επεξεργασίας ηχου είναι οτι ακολουθεί το μοντελο "client/server" (πελάτη/διακομιστή η επι λεξη μεταφραση) που σημαινει οτι εχει δυο σημαντικα κομματια: μια εφαρμογη που την τρεχει ο χρηστης (client / sclang) σε καποιον υπολογιστη για να παραγει οδηγιες για μουσικη συνθεση, και μια δευτερη εφαρμογη (scsynth), που τρεχει στον ιδιο η αλλον υπολογιστη καπου στο δικτυο, που δεχεται τις οδηγιες και παραγει τον ηλεκτρονικο ηχο.

arch

Εικόνα απο το Introduction to SuperCollider του Andrea Valle.

Αυτη η αρχιτεκτονικη παρεχει πολυ μεγαλυτερη ευελιξία στο τι μπορει κανεις να οργανωσει με τον SC. Πχ δυο χρηστες μπορουν να στελνουν ανεξαρτητα τις οδηγιες τους στον ιδιο σερβερ απο δυο διαφορετικους υπολογιστες.

Στην πραξη Τρέχουμε παντα δυο πράγματα, ενα πρόγραμμα οπου γράφουμε εντολές σε sclang (δες παρακάτω) και ένα που παράγει ήχο.

SClang, μια γλώσσα "συγκεκριμένου αντικειμένου" (DSL)

Για να στείλουμε εντολές στον SC πρεπει να τις γράψουμε σε μια συγκεκριμένη γλώσσα προγραμματισμού που έχει αναπτυχθεί ειδικά για αυτό το σκοπό. Μια γρήγορη επισκόπηση:

  • σε εμφάνιση και λογική θυμίζει τις λεγόμενες "curly braces" γλώσσες (C/C++, Java, Javascript κλπ)
  • ειναι μια γλωσσα που ερμηνευεται (interpreted) απο τον υπολογιστη, γραμμη γραμμη, αναλογη μετα τα λεγομενα REPL (Read–eval–print) περιβαλλοντα της Python, του Javascript η του Linux και σε αντιθεση με το περιβαλλον μεταγλωτισσης (compilation) που χαρακτηριζει τις C++, Rust, Java κλπ.
  • η sclang χτίζει και καλύπτει κατα βαση τα μηνύματα Open Sound Protocol OSC για να σταλουν στο scsynth

Η χρήση της sclang δεν είναι εντελώς απαραίτητη. Μπορουμε να στειλουμε εντολες με αλλες εφαρμογες (tidal, sardine) η και να γραψουμε κατι απο την αρχη. 'Ειναι όμως η πιό εκτενής γλώσσα για την πλήρη χρήση του SC και σε αυτές τις σελιδες θα εμβαθυνουμε σε αυτη.

Στην πραξη Μαθαίνουμε τις βασικές εντολες κοιτωντας παραδειγματα και με το χρονο εμβαθυνουμε περισσοτερο στην δομη της γλωσσας.

Πραγματικος χρονος (RT) και μη-πραγματικος χρονος (NRT)

Η χρήση του SC για την παραγωγη μουσικης μπορει να ταξινομηθει σε δυο πολυ διαφορετικες μεταξυ τους κατηγοριες:

  • διαδραστικη (interactive) χρηση "real time" οπου ο μουσικος-προγραμματιστης δημιουργει κωδικα-ηχο που σχεδον ταυτοχρονα ακουγεται καπου και μετα χανεται σαν δακρυα μεσα στην βροχη
  • εκτός συνδεσης, στο background, σε "non-real time" οπου οι ηχοι σωζονται κατευθειαν σε ηλεκτρονικο αρχειο

Ενας τριτος τροπος ειναι ουσιαστικα η μαγνητοσκοπιση μιας ζωντανης RT παραστασης. Εδω θα δουμε το ιδιο παραδειγμα γραμμενο για τους δυο πρωτους τροπους.

Μια ολοκληρωμενη αλληλουχια απο εντολες σε RT

Ο παρακατω κωδικας δειχνει την απλουστερη δυνατη αλληλουχια απο εντολες σε πραγματικο χρονο.

// ξεκινα ενα σερβερ που να ακουει σε μια συγκεκριμενο πορτα του υπολογιστη
s = Server("new_server", NetAddr("127.0.0.1", 56789));
s.boot;
// ορισε μια μηχανη συνθεσης (ενα απλο ημιτονο)
SynthDef("sine", { Out.ar(0, SinOsc.ar(440, 0, 0.2)) }).send(s);
// τρεξε την συνθεση (κανονικα θα ακουστει ενας καθαρος τονος)
s.sendMsg("s_new", "sine", n = s.nextNodeID, 0, 1);
// σταματα τον ηχο
s.sendMsg("/n_free", n);
// σταματα τον σερβερ και τελειωσαμε
s.quit;

Τιποτε δραματικο βεβαια, αλλα το παιδι μιλησε!

Το ιδιο σε NRT

(
// ξεκινα ενα σερβερ    
var server = Server(\nrt,
    options: ServerOptions.new
    .numOutputBusChannels_(2)
    .numInputBusChannels_(2)
);

// γραψε μια "παρτιτουρα" στο στυλ του OSC με τρια μηνυματα / εντολες:
// πρωτα οριζουμε το SynthDef
// μετα στο στελνουμε στο σερβερ, και στο τελος
// σταματαμε την παραγωγη ηχου    
a = Score([
    [0.0, ['/d_recv',
        SynthDef(\NRTmod, { |out, freq = 440|
            Out.ar(out, SinOsc.ar(440, 0, 0.2))
        }).asBytes
    ]],
    [0.0, (x = Synth.basicNew(\NRTmod, server, 1000)).newMsg(args: [freq: 400])],
    [5.0, x.freeMsg]
]);

// καταγραφουμε τον παραγμενο ηχο σε ενα αρχειο    
a.recordNRT(
    outputFilePath: "~/Music/nrt-example.wav".standardizePath,
    headerFormat: "wav",
    sampleFormat: "int16",
    options: server.options,
    duration: 1,
    action: { "done".postln }
);

server.remove;
)

Synths και UGens

UGens

Οι γεννητριες παραγουν σηματα. Αυτα ερχονται σε τρεις τυπους:

  • Σήματα ρυθμού ήχου (audio rate, ar): Αυτά εκτελούνται με υψηλη αναλυση, δηλαδη ενα ρυθμό που μπορεί να χρησιμοποιηθεί για την είσοδο ή την έξοδο ήχου στο υπολογιστή (η τρέχουσα προεπιλογή είναι 44100 Hz).
  • Σήματα ρυθμού ελέγχου (control rate, kr): Αυτά εκτελούνται σε ένα κλάσμα του ρυθμού ήχου ανάλογα με την εσωτερική προσωρινή μνήμη μέγεθος της μηχανής σύνθεσης. Χρησιμοποιούνται ως είσοδοι στα UGens και παρέχουν συνεχή έλεγχο στις παραμέτρους τους.
  • Σήματα αρχικού ρυθμού (initial rate. ir): Ένα σήμα ir έχει μια αμετάβλητη (σταθερή) τιμή που αρχικοποιείται όταν δημιουργείται το Synth

// Παιξε ενα καθαρο τονο, συχνοτητα 440 Hz, φαση 0, πλατος (ενταση) 0.1
{ SinOsc.ar(440, 0, 0.1) }.play;
// Διπλασια συχνοτητα 880 Hz, φαση 0, διπλη ενταση 0.2
{ SinOsc.ar(880, 0, 0.2) }.play;

// Ζωγραφισε καποιες κλασσικες γεννητριες
{ SinOsc.ar(110,0, 0.1) }.plot;
{ LFSaw.ar(500, 1, 0.1) }.plot;
{ LFSaw.ar(20, [0, 1, 2]) }.plot(0.1);
{ LFNoise0.kr(10000) }.plot(0.1);
{ LFNoise0.kr(0.3, 700, 900), 0, 0.05)}.plot;

// Χτισε κατι σχετικα ενδιαφερον με το συνδυασμο γεννητριων
{ SinOsc.ar(LFNoise0.kr(0.3, 700, 900), 0, Trig.kr(Dust.kr(10, 0.1)))}.play;