EP/AssA WS13

Aus Progwiki
< EP
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

Ausbesserungsbeispiel (AssA)

Das Ausbesserungsbeispiel ersetzt die Punkte des Gruppenbeispiels. Teilnehmen darf jeder, der bis dato negativ (weniger als 10 Punkte auf das Gruppenbeispiel) ist und alle Beispiele zumindest als Versuch abgegeben hat.

Das Lernziel dieses Ausbesserungsbeispiels ist es, den Umgang mit Binärdateien, Textdateien sowie dynamischem Speicher zu beherrschen. Dafür soll ein Programm entwickelt werden, das die Noten von einem Lied aus einer Textdatei ausliest und eine WAVE Datei generiert, welche man später mit einem Audio-Player abspielen kann.

Änderung vom 1. Februar 2014: Alle Fehlermeldungen sollen einheitlich mit einem "\n" abgeschlossen werden. Der entsprechende Zeilenumbruch wurde bei den drei File-IO Fehlermeldungen ergänzt.

Programmaufruf

Ein beispielhafter Programmaufruf sieht wie folgt aus:

./assa -bpm 120 -o out.wav input1.txt input2.txt

Das Programm erwartet mindestens eine Eingabedatei, es können allerdings (so wie in diesem Beispiel) auch zwei oder mehrere Dateien angegeben werden, wenn das Lied mehrere Tonspuren enthält.

Mit "-bpm <beats_per_minute>" kann optional das Tempo, mit dem das Lied abgespielt werden soll, angegeben werden. Der BPM-Wert beschreibt dabei die Anzahl der Viertelnoten pro Minute. Wird kein Wert angegeben, so ist der Wert 120 zu verwenden.

Optional kann auch noch der Name der Ausgabedatei mit "-o <output_filename>" spezifiziert werden. Wird kein Name angegeben, so ist die Datei "out.wav" zu erstellen.

Die optionalen Parameter (sofern vorhanden) können in beliebiger Reihenfolge angegeben werden. Es kann aber davon ausgegangen werden, dass die Eingabedateien immer am Ende der Argumentenliste stehen.

Eingabeformat

Die Noten für das Musikstück werden als Textdatei angegeben. Dabei enthält jede Zeile eine eigene Note, welche in folgendem Format angegeben wird:

<duration> <note name> <octave>

<duration> ist dabei entweder der String "1/1", "1/2", "1/4", "1/8" oder "1/16". Mögliche Werte von <note name> können aus der untenstehenden Tabelle entnommen werden und <octave> ist eine Ganzzahl zwischen -5 und 5 (jeweils inklusive).

Name Offset
C 0
C#, Db 1
D 2
D#, Eb 3
E 4
F 5
F#, Gb 6
G 7
G#, Ab 8
A 9
A#, Bb 10
B 11

Es empfiehlt sich die Noten für die weitere Verarbeitung als MIDI Note abzuspeichern. Die MIDI Note d ist dabei definiert als d = (5 + octave) * 12 + offset, wobei das offset aus der Tabelle zu entnehmen ist.

Statt "<note name> <octave>" kann auch der String "-" angegeben werden um eine Pause zu speichern. Die Zeile hat dann folgende Syntax:

<duration> -

Ausgabeformat

Es soll eine WAVE Datei erstellt werden, welche eine elektronische Darbietung des Liedes aus der Eingabedatei enthält und folgende Eigenschaften hat: PCM, mono, 44.1 kHz Abtastrate, 16 Bits per Sample. Das genaue Format dieser Datei ist dabei aus der Spezifikation zu entnehmen.

Generierung der Musik

Hier empfiehlt es sich einen Oszillator (representiert durch einen Winkel Φ) zu verwenden. Bei jedem Sample wird dieser Winkel in Abhängigkeit von der Frequenz f des aktuellen Tons und der Abtastrate entsprechend um 2 * pi * f / sample_rate erhöht und anschließend wird sin(Φ) in die Datei geschrieben. sin(Φ) muss dafür auf einen Wert zwischen SHRT_MIN und SHRT_MAX (Wertebereich des Datentyps short, siehe "limits.h") skaliert werden.

Bei einer Pause verändert sich der Wert des Winkels nicht. Bei mehreren Tonspuren werden mehrere Oszillatoren benötigt und es ist das arithmetische Mittel der sin(Φ_i) in die Datei zu schreiben.

Mit Hilfe der folgenden nützlichen Formel kann die Frequenz f von einer MIDI Note d berechnet werden:

Midi freq.png

Die Anzahl der Samples pro ganzer Note kann mit (sample_rate * 60 * 4) / bpm berechnet werden.

Des weiteren sollten auch noch entsprechende Obertöne (also Töne die mit der doppelten, dreifachen, vierfachen, etc. Frequenz) abgespielt werden hinzugefügt werden. Dies kann erreicht werden in dem man für jede Tonspur ein Array von Oszillatoren verwendet und diese entsprechend aufaddiert. Der erste Oberton soll allerdings nur mehr 1/2 so laut sein wie der eigentliche Ton (also 0.5 * sin(Φ)), der zweite Oberton nur 1/4 so laut, der dritte 1/8, usw. Es reicht die ersten 12 Obertöne zu simulieren.

Beispiel

Programmaufruf:

./assg -bpm 166 -o mountain.wav mountain1.txt mountain2.txt

Eingabedateien:

Ausgabedatei:

Rückgabewerte und Fehlermeldungen

  • Erfolgsfall
    • keine Ausgabe
    • Rückgabewert 0
  • "Usage: ./assa [-bpm <beats_per_min>] [-o <output_file>] <input_files>\n"
    • Werte in <> sowie [] sollen nicht ersetzt werden!
    • Wenn das Programm nicht ordnungsgemäß gestartet wurde.
    • Rückgabewert 1
  • "Error: can not read input file.\n"
    • Wenn die Eingabedatei nicht geöffnet werden konnte oder wenn während dem Lesen ein Fehler auftritt.
    • In diesem Fall soll keine WAVE Datei erstellt werden.
    • Rückgabewert 2
  • "Error: invalid input file.\n"
    • Wenn die Eingabedatei nicht der vorgegebenen Syntax entspricht.
    • In diesem Fall soll keine WAVE Datei erstellt werden.
    • Rückgabewert 3
  • "Error: can not write output file.\n"
    • Wenn die Ausgabedatei nicht zum Schreiben geöffnet werden konnte oder wenn während des Schreibvorgangs ein Fehler auftritt.
    • Rückgabewert 4
  • "Error: out of memory.\n"
    • Wenn kein dynamischer Speicher angefordert werden konnte.
    • Rückgabewert 5

Spezifikation

  • keine weiteren Ausgaben
  • alle Ausgaben müssen auf stdout erfolgen
  • erlaubte Bibliotheken: alle C Standard Bibliotheken
  • Dateinamen laut Abgabenliste
  • Archiv beinhaltet keine Verzeichnisse oder andere Dateien

Abgabe

Bis zum So. 09.02.2014 19:00:00

  • Quellcode (assa.c)

in einem .tar.gz oder .zip Archiv (assa.tar.gz oder assa.zip).



Verantwortlicher Tutor: Christoph Hack

Meine Werkzeuge