# Funktionen

Wenn du einmal damit angefangen hast größere Mengen Programm-Code zu schreiben, dann wirst du nach Wegen suchen, wie du die Dinge organisieren und strukturieren kannst, um sie sauberer und verständlicher zu machen. Funktionen sind ein sehr wirkungsvoller Weg das zu tun. Sie geben uns die Möglichkeit, einem Haufen Programm-Code einen Namen zu geben. Sehen wir uns das an.

## Funktionen definieren

    define :foo do
      play 50
      sleep 1
      play 55
      sleep 2
    end

Hier haben wir eine neue Funktion mit dem Namen `foo` definiert. Wir machen das mit unserem alten Freund, dem do/end-Block und dem Zauberwort `define`, gefolgt von dem Namen, den wir unserer Funktion geben möchten. Wir müssen die Funktion nicht unbedingt `foo` nennen, wir können sie auch irgendwie anders nennen; zum Beispiel `bar`, `baz` oder idealerweise einen für dich bedeutsamen Namen wie `haupt_sektion` oder `hintergrund_akkorde`.

Denke daran, bei der Definition einer Funktion ihrem Namen einen Doppelpunkt `:` voranzustellen.

## Funktionen aufrufen

Wenn wir unsere Funktion definiert haben, können wir sie über die Eingabe ihres Namens aufrufen:

    define :foo do
      play 50
      sleep 1
      play 55
      sleep 0.5
    end
    foo
    sleep 1
    2.times do
      foo
    end

Wir können `foo` sogar in Blocks mit Iterationen verwenden - oder überall da, wo wir sonst auch `play` oder `sample` schreiben würden. Das gibt uns eine sehr weit gehende Möglichkeit uns auszudrücken, und können sinnvolle Worte einsetzen, um sie in unseren Kompositionen zu verwenden.

## Funktionen bleiben in Erinnerung

Wenn du bisher auf `Ausführen` geklickt hast, ist Sonic Pi jedes Mal aufs Neue ohne irgendwelche Vorgaben gestartet. Es berücksichtigt dabei nichts, außer dem, was im jeweiligen Puffer steht. Du kannst dich nicht auf irgendwelchen Programm-Code beziehen, der in einem anderen Puffer oder in einem anderen Thread steht. Funktionen ändern das jedoch. Wenn du eine Funktion definierst, dann erinnert sich Sonic Pi daran. Probieren wir das aus. Lösche den gesamten Code in deinem Puffer und ersetze ihn durch:

    foo

Klicke auf `Ausführen` - und höre deine Funktion spielen. Wo wurde dieser Code gespeichert? Woher wusste Sonic Pi, was es zu spielen hat? Sonic Pi hat sich deine Funktion einfach gemerkt - sogar, nachdem du den Programm-Code aus dem Puffer gelöscht hast, wusste Sonic Pi noch, was du geschrieben hattest. Dies funktioniert nur mit Funktionen, die du mit `define` (und `defonce`) erzeugt hast.

## Funktionen parametrisieren

Es wird dich vielleicht interessieren, dass so wie du `rrand` einen Minimal- und Maximalwert übergeben kannst, du auch deinen Funktionen beibringen kannst Argumente zu akzeptieren. Sehen wir uns das an:

    define :my_player do |n|
      play n
    end
    my_player 80
    sleep 0.5
    my_player 90

Das ist nicht besonders aufregend, zeigt aber, worum es hier geht. Wir haben unsere eigene Version von `play` mit dem Namen `my_player` erschaffen. Diese ist parametrisiert - sie akzeptiert also Argumente.

Die Parameter müssen hinter dem `do` des `define`-do/end-Blocks stehen, umgeben von senkrechten Strichen (pipes) `|`und durch Kommas `,` getrennt. Du kannst beliebige Wörter als Parameternamen verwenden.

Die Magie passiert innerhalb des `define`-do/end-Blocks. Du kannst die Parameternamen so benutzen, als wären sie wirkliche Werte. In diesem Beispiel spiele ich den Ton `n`. Du kannst die Parameter als eine Art Versprechen ansehen, dass wenn der Programm-Code läuft, sie durch wirkliche Werte ersetzt werden. Du machst das, indem du der Funktion beim Aufruf einen Parameter mitgibst. Ich tue das hier mit `my_player 80`, um die Note 80 zu spielen. Innerhalb der Funktionsdefinition wird `n` nun durch 80 ersetzt, sodass `play n` sich in `play 80` verwandelt. Wenn ich die Funktion erneut mit `my_player 90` aufrufe, wird `n` durch 90 ersetzt, sodass sich jetzt `play n` in `play 90` verwandelt.

Sehen wir uns ein interessanteres Beispiel an:

    define :chord_player do |root, repeats|
      repeats.times do
        play chord(root, :minor), release: 0.3
        sleep 0.5
      end
    end
    chord_player :e3, 2
    sleep 0.5
    chord_player :a3, 3
    chord_player :g3, 4
    sleep 0.5
    chord_player :e3, 3

Hier habe ich `repeats` so benutzt, als ob es eine Zahl in der Zeile `repeats.times do` wäre. Zusätzlich habe ich `roots` so verwendet, als ob es ein Notenname in meinem Aufruf von `play` wäre.

Sieh dir an, wie wir hier etwas sehr Ausdrucksstarkes und leicht zu Lesendes schreiben konnten, indem wir vieles von unserer Programmlogik in Funktionen verschieben!