Οδηγός Μελέτης - Εισαγωγή στον Προγραμματισμό

Α9.17 · Επεξεργασία Ήχου (soundwave)

Εργασία 1 (2025-26), Άσκηση 1 · Δυσκολία ★★★ · programming · Κεφάλαια: 9, 12, 5

Ο ήχος είναι ένα αναλογικό σήμα, μια συνάρτηση \(f(t)\) της έντασης ως προς τον χρόνο, που για να αποθηκευθεί σε υπολογιστή ψηφιοποιείται καταγράφοντας την τιμή του σε διακριτές ισαπέχουσες χρονικές στιγμές (π.χ. 44.100 δείγματα ανά δευτερόλεπτο σε ένα μουσικό CD). Αντικείμενο αυτής της εργασίας είναι η δημιουργία ενός συστήματος επεξεργασίας ήχου για αρχεία τύπου wav.

Η μορφή των αρχείων wav

Τα αρχεία wav είναι δυαδικά—δηλαδή τα περιεχόμενά τους δεν είναι άμεσα αναγνώσιμα ως κείμενο αλλά αντιθέτως περιέχουν μια σειρά από bytes διατεταγμένα σε ένα αρχείο στον δίσκο με συγκεκριμένες ερμηνείες. Τα αρχεία wav που θα κληθούμε να διαχειριστούμε στα πλαίσια της εργασίας έχουν την ακόλουθη δομή:

FileHeader | SampleData | OtherData

Δηλαδή αποτελούνται από μια κεφαλίδα (FileHeader) που περιέχει πληροφορίες για το συγκεκριμένο αρχείο ήχου wav, ακολουθούμενο από τα ίδια τα δείγματα του ήχου (SampleData) και στην συνέχεια ακολουθούν προαιρετικά άλλα δεδομένα (OtherData). Τα αρχεία κεφαλίδας wav, περιέχουν τα ακόλουθα πεδία με την σειρά:

Μετά την κεφαλίδα του αρχείου, ακολουθούν τα ψηφιοποιημένα δεδομένα του ήχου με χρονική σειρά (SampleData). Στην περίπτωση στερεοφωνικού ήχου με δύο κανάλια, για κάθε χρονική στιγμή, υπάρχει ένα ζευγάρι δεδομένων, με το πρώτο στοιχείο να αντιστοιχεί στο αριστερό κανάλι και το δεύτερο στοιχείο στο δεξιό κανάλι. Μετά το τέλος των δεδομένων ήχου, ενδεχομένως να υπάρχουν και άλλα τμήματα (OtherData) που προβλέπονται για την κατηγορία WAVE, με τα οποία όμως δεν θα ασχοληθούμε στην εργασία.

Ας δούμε τώρα τα περιεχόμενα ενός πραγματικού αρχείου wav. Μπορούμε να δούμε τα δυαδικά περιεχόμενα οποιουδήποτε αρχείου χρησιμοποιώντας την εντολή od ως εξής (η εκφώνηση δείχνει και ένα σχήμα με τα ίδια bytes μέσω xxd -g1, όπου σημειώνονται τα πεδία):

$ od -tx1 good.wav
0000000 52 49 46 46 85 00 00 00 57 41 56 45 66 6d 74 20
0000020 10 00 00 00 01 00 01 00 44 ac 00 00 88 58 01 00
0000040 02 00 10 00 64 61 74 61 58 00 00 00 00 00 d4 07
0000060 a1 0f 5e 17 04 1f 8a 26 ea 2d 1c 35 18 3c d7 42
0000100 54 49 86 4f 69 55 f6 5a 27 60 f8 64 63 69 64 6d
0000120 f7 70 18 74 c5 76 fa 78 b6 7a f6 7b b9 7c ff 7c
0000140 c8 7c 12 7c e0 7a 33 79 0b 77 6c 74 58 71 d1 6d
0000160 dd 69 7e 65 b8 60 92 5b 0f 56 36 50 0c 4a 97 43
0000200 df 3c ea 35 45 78 74 72 61 44 61 74 61
0000215

Σημείωση. Πέρα από την εντολή od, υπάρχουν και άλλες εντολές όπως οι: (1) xxd, (2) hexdump, (3) hexedit που προσφέρουν αντίστοιχες δυνατότητες σε Unix-like συστήματα (Linux, MacOS, WSL κοκ). Για να συγκρίνετε δύο δυαδικά αρχεία, μπορείτε να χρησιμοποιήσετε την εντολή cmp ή την εντολή vbindiff. Για περιβάλλοντα Windows, υπάρχουν ελεύθερα διαθέσιμα προγράμματα που λειτουργούν παρόμοια (π.χ. https://mh-nexus.de/en/hxd/).

Φτάσαμε λοιπόν στο ζητούμενο αυτής της άσκησης: να υλοποιήσουμε ένα πρόγραμμα επεξεργασίας αρχείων wav με δυνατότητες αλλαγής και παραγωγής ήχου—όλα σε γλώσσα C!

Τεχνικές Προδιαγραφές

Η Υποεντολή info (40% της βαθμολογίας)

Όταν το πρόγραμμά σας κληθεί με την υποεντολή info ως πρώτο όρισμα, δηλαδή ως ./soundwave info θα πρέπει να ελέγχει αν τα δεδομένα που διαβάστηκαν ακολουθούν το πρότυπο wav που περιγράφηκε παραπάνω και να εκτυπώνει τις σχετικές πληροφορίες του ήχου (χωρίς τα δεδομένα αυτά καθεαυτά). Παραδείγματα εκτέλεσης ακολουθούν:

$ ./soundwave info < good.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
size of data chunk: 88
$ ./soundwave info < 1MB.wav
size of file: 1073210
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 8000
bytes/sec: 32000
block alignment: 4
bits/sample: 16
size of data chunk: 1072948
$ ./soundwave info < 2MB.wav
size of file: 2146158
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 16000
bytes/sec: 64000
block alignment: 4
bits/sample: 16
size of data chunk: 2145896
$ ./soundwave info < 5MB.wav
size of file: 5226758
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 44100
bytes/sec: 176400
block alignment: 4
bits/sample: 16
size of data chunk: 5226496
$ ./soundwave info < 10MB.wav
size of file: 10406730
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 44100
bytes/sec: 176400
block alignment: 4
bits/sample: 16
size of data chunk: 10406468

Όλα τα αρχεία που φαίνονται στα παραδείγματα της εκφώνησης της εργασίας μπορείτε να τα κατεβάσετε από το https://github.com/progintro/wav.

Οι εκτυπώσεις του προγράμματός σας θα γίνονται κανονικά στην πρότυπη έξοδο, εκτός αν παρουσιαστεί κάποιο σφάλμα (δείτε παρακάτω) οπότε και θα πρέπει να τυπώσετε στο πρότυπο ρεύμα εξόδου σφάλματος (stderr / standard error). Για να τυπώσετε στο stderr, μπορείτε να χρησιμοποιήσετε την συνάρτηση fprintf με πρώτο όρισμα το stderr εξής:

fprintf(stderr, <ίδια ακριβώς ορίσματα με αυτά της printf>);

Το πρόγραμμά σας πρέπει να είναι σε θέση να καταλαβαίνει λάθη που υπάρχουν στα δεδομένα ήχου που διαβάστηκαν και να σταματά στο πρώτο λάθος που βρίσκει εκτυπώνοντας το κατάλληλο διαγνωστικό μήνυμα στο stderr. Παραδείγματα εκτέλεσης σε προβληματικά δεδομένα εισόδου είναι τα ακόλουθα:

$ ./soundwave info < bad_riff.wav
Error! "RIFF" not found
$ echo $?
1
$ ./soundwave info < bad_riff.wav 2> error.txt
$ cat error.txt
Error! "RIFF" not found
$ ./soundwave info < bad_wave.wav
size of file: 133
Error! "WAVE" not found
$ ./soundwave info < bad_fmt.wav
size of file: 133
Error! "fmt " not found
$ ./soundwave info < bad_sfc.wav
size of file: 133
size of format chunk: 18
Error! size of format chunk should be 16
$ ./soundwave info < bad_wtf.wav
size of file: 133
size of format chunk: 16
WAVE type format: 2
Error! WAVE type format should be 1
$ ./soundwave info < bad_ms.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 3
Error! mono/stereo should be 1 or 2
$ ./soundwave info < bad_bys.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88202
block alignment: 2
Error! bytes/second should be sample rate x block alignment
$ ./soundwave info < bad_bis.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 32
Error! bits/sample should be 8 or 16
$ ./soundwave info < bad_ba.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
Error! block alignment should be bits per sample / 8 x mono/stereo
$ ./soundwave info < bad_data.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
Error! "data" not found
$ ./soundwave info < bad_insfd.wav
size of file: 133
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
size of data chunk: 88
Error! insufficient data
$ ./soundwave info < bad_sf.wav
size of file: 128
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
size of data chunk: 88
Error! bad file size (found data past the expected end of file)

Στο τελευταίο παράδειγμα εκτέλεσης, παρατηρούμε ότι το bad_sf.wav αρχείο ισχυρίζεται ότι έχει μέγεθος 128 bytes (σύνολο 136 με τα αρχικά 8 bytes της κεφαλίδας), όμως αν ελέγξουμε τα συνολικά bytes του αρχείου:

$ wc -c ./bad_sf.wav
141 ./bad_sf.wav

παρατηρούμε ότι έχει και άλλα bytes στο τέλος τα οποία δεν συμπεριλαμβάνονται στο SizeOfFile και επομένως δεν περνάει τον έλεγχο ορθότητας (validation). Αντίστοιχα, μπορείτε να φτιάξετε και εσείς τα δικά σας παραδείγματα με λανθασμένα wav προκειμένου να ελέγξετε ότι το πρόγραμμά σας τα αναγνωρίζει επιτυχώς.

Η υποεντολή rate (40% της βαθμολογίας)

Τώρα που το πρόγραμμά μας μπορεί να αναγνωρίζει αρχεία wav, ήρθε η ώρα να προσθέσουμε την πρώτη sound-editing υποεντολή μας, την υποεντολή rate, της οποίας η σύνταξη είναι ./soundwave rate fp_rate, όπου fp_rate είναι ένας αριθμός κινητής υποδιαστολής (double) που αντιστοιχεί στην επιτάχυνση που επιθυμούμε στον ρυθμό αναπαραγωγής. Η υποεντολή rate, εκτός από τον έλεγχο ορθότητας των δεδομένων εισόδου θέλουμε να μεταφέρει στην έξοδο, με τη βοήθεια της συνάρτησης putchar, τα δεδομένα του ήχου, έχοντας αλλάξει την ταχύτητα αναπαραγωγής του, χωρίς να αλλοιώσει τα δείγματα που αποτελούν τον ψηφιοποιημένο ήχο.

Αν το υλοποιήσουμε σωστά, καλώντας το πρόγραμμά μας ως ./soundwave rate 0.5 < input.wav > output.wav περιμένουμε το output.wav αρχείο να αναπαράγεται με υποδιπλάσιο ρυθμό, δηλαδή στον διπλάσιο χρόνο από τον αρχικό. Σκεφτείτε ποιες παράμετροι των δεδομένων εισόδου θα πρέπει να αλλάξουν και πώς, ώστε να επιτευχθεί το ζητούμενο. Σε κάθε περίπτωση, η έξοδος του προγράμματος πρέπει να είναι μία νόμιμη ακολουθία από δεδομένα wav. Ακόμα και αν υπάρχουν στην είσοδο επιπλέον bytes μετά το τμήμα των δεδομένων του (OtherData), θα πρέπει και αυτά να μεταφερθούν στην έξοδο, προφανώς αυτούσια. Παραδείγματα εκτέλεσης ακολουθούν:

$ ./soundwave info < LaughEvil.wav
size of file: 329266
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
size of data chunk: 329230
$ ./soundwave rate 0.5 < LaughEvil.wav > LaughEvil2.wav
$ ./soundwave info < LaughEvil2.wav
size of file: 329266
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 22050
bytes/sec: 44100
block alignment: 2
bits/sample: 16
size of data chunk: 329230
$ ./soundwave rate 0.5 < ThePinkPantherTheme.wav > ThePinkPantherTheme2.wav
$ ./soundwave rate 0.5 < la.wav > la2.wav
$ ./soundwave rate 0.5 < 8bitstereo.wav > 8bitstereo2.wav

Στα παραπάνω παραδείγματα, η έξοδος του προγράμματος ανακατευθύνεται σε ένα νέο αρχείο ήχου. Για να τα ακούσετε, κάνετε διπλό κλικ στο αρχείο ή χρησιμοποιήστε μια εντολή όπως η play (Linux) ή η afplay (MacOS). Σε Linux μπορεί να αποφευχθεί η δημιουργία αρχείου με σωλήνωση, για παράδειγμα για ένα απομακρυσμένο αρχείο ήχου:

curl -s https://raw.githubusercontent.com/progintro/wav/refs/heads/main/la.wav |
  ./soundwave rate 0.5 | play -

Αντίστοιχα, μπορείτε να χρησιμοποιήσετε την παράμετρο της υποεντολής rate προκειμένου να διπλασιάσετε την ταχύτητα αναπαραγωγής του. Διπλασιάζοντας την ταχύτητα αναπαραγωγής (2x speedup), ο χρόνος αναπαραγωγής θα υποδιπλασιασθεί, αφού τα δείγματα που αποτελούν τον ψηφιοποιημένο ήχο θα πρέπει και πάλι να μεταφερθούν αναλλοίωτα. Παραδείγματα εκτέλεσης ακολουθούν:

$ ./soundwave info < LaughSarc.wav
size of file: 1541540
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 48000
bytes/sec: 192000
block alignment: 4
bits/sample: 16
size of data chunk: 1541504
$ ./soundwave rate 2 < LaughSarc.wav > LaughSarc3.wav
$ ./soundwave info < LaughSarc3.wav
size of file: 1541540
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 96000
bytes/sec: 384000
block alignment: 4
bits/sample: 16
size of data chunk: 1541504
$ ./soundwave rate 2.0 < ThePinkPantherTheme.wav > ThePinkPantherTheme3.wav
$ ./soundwave rate 2.0 < narc.wav > narc3.wav
$ ./soundwave rate 2.0 < narc.wav | ./soundwave info
size of file: 4956196
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 88200
bytes/sec: 352800
block alignment: 4
bits/sample: 16
size of data chunk: 4956160
$ ./soundwave rate 2.0 < 8bitmono.wav | tee 8bitmono3.wav | ./soundwave info
size of file: 44136
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 88200
bytes/sec: 88200
block alignment: 1
bits/sample: 8
size of data chunk: 44100

Η υποεντολή channel (20% της βαθμολογίας)

Η υποεντολή channel επιτρέπει στον χρήστη να διαλέξει να αναπαράξει δεδομένα μόνο από το αριστερό ή δεξί κανάλι ήχου στην περίπτωση που ο ήχος της εισόδου είναι στερεοφωνικός. Η σύνταξη της εντολής είναι ως εξής: ./soundwave channel left για να κρατήσει μόνο τα δεδομένα από το αριστερό κανάλι και ./soundwave channel right για να κρατήσει μόνο τα δεδομένα από το δεξί κανάλι. Όπως προηγουμένως, το πρόγραμμά σας πρέπει να πραγματοποιεί έλεγχο ορθότητας των δεδομένων εισόδου και μεταφέρει στην έξοδο, με τη βοήθεια της συνάρτησης putchar, τα δεδομένα μόνο του καναλιού του ήχου που ζήτησε ο χρήστης. Αν ο ήχος στην είσοδο είναι μονοφωνικός, να μην προκύπτει σφάλμα, αλλά απλώς να μεταφέρεται στην έξοδο το μοναδικό κανάλι της εισόδου. Σκεφτείτε ποιες παράμετροι των δεδομένων εισόδου θα πρέπει να αλλάξουν και πώς και ποια από τα bytes του τμήματος δεδομένων της εισόδου θα πρέπει να μεταφερθούν στην έξοδο, ώστε να επιτευχθεί το ζητούμενο. Σε κάθε περίπτωση, η έξοδος του προγράμματος πρέπει να είναι μία νόμιμη ακολουθία από δεδομένα που συνιστούν έναν ήχο με βάση το πρότυπο που έχει περιγραφεί. Ακόμα και αν υπάρχουν στην είσοδο επιπλέον bytes μετά το τμήμα των δεδομένων του (OtherData), θα πρέπει και αυτά να μεταφερθούν στην έξοδο, προφανώς αυτούσια. Παραδείγματα εκτέλεσης ακολουθούν:

$ ./soundwave info < 8bitstereo.wav
size of file: 176436
size of format chunk: 16
WAVE type format: 1
mono/stereo: 2
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 8
size of data chunk: 176400
$ ./soundwave channel left < 8bitstereo.wav | tee 8bitstereo4.wav | ./soundwave info
size of file: 88236
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 44100
block alignment: 1
bits/sample: 8
size of data chunk: 88200
$ ./soundwave channel left < CaliforniaDreamin.wav > CaliforniaDreamin4.wav
$ ./soundwave channel right < 8bitstereo.wav > 8bitstereo5.wav
$ ./soundwave channel right < CaliforniaDreamin.wav > CaliforniaDreamin5.wav

Η υποεντολή volume (Bonus 20% της βαθμολογίας)

Η υποεντολή volume δέχεται έναν πολλαπλασιαστή για την ένταση του ήχου με την σύνταξη ./soundwave volume fp_multiplier και παράγει ένα καινούριο αρχείο ήχου όπου η ένταση κάθε δείγματος πολλαπλασιάζεται με το καινούριο volume: \(\mathrm{trunc}(original \cdot fp\_volume)\) (όπου trunc ο τελεστής αποκοπής σε ακέραιο). Για παράδειγμα, αν το πρόγραμμά σας κληθεί ως εξής: ./soundwave volume 0.125 περιμένουμε ότι το αρχείο ήχου εξόδου θα έχει το 1/8 της έντασης του αρχικού αρχείου. Παραδείγματα εκτέλεσης ακολουθούν:

$ ./soundwave volume 0.125 < 8bitmono.wav > 8bitmono6.wav
$ ./soundwave volume 0.125 < 8bitstereo.wav > 8bitstereo6.wav
$ ./soundwave volume 0.125 < la.wav | tee la6.wav | ./soundwave info
size of file: 88236
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
size of data chunk: 88200

Η υποεντολή generate (Bonus 30% της βαθμολογίας)

Οι παραπάνω εντολές επιτρέπουν στο πρόγραμμά μας να επεξεργάζεται υπάρχοντα αρχεία ήχου. Τι κάνουμε όμως αν εμείς θέλουμε να παράξουμε τους δικούς μας ήχους; Σε αυτό ακριβώς το πρόβλημα έρχεται να δώσει λύση η υποεντολή generate. Η σύνταξη της εντολής generate είναι ./soundwave generate και παράγει στην έξοδο δεδομένα τύπου wav, με βάση τον εξής μαθηματικό τύπο (το \(\pi\) είναι το γνωστό 3.14… και με το sin συμβολίζεται η συνάρτηση του ημιτόνου):

\[f(t) = \mathrm{trunc}(amp \cdot \sin(2\pi f_c t - m_i \cdot \sin(2\pi f_m t)))\]

Για το σκοπό αυτό, ορίστε μία συνάρτηση C με πρωτότυπο το

void mysound(int dur, int sr, double fm, double fc, double mi, double amp);

η οποία να καλείται με κατάλληλες τιμές στα ορίσματά της από τη main συνάρτηση, ώστε να παράγει τον κατάλληλο ήχο με βάση τον μαθηματικό τύπο που δόθηκε. Η υποεντολή, πέρα από τον βασικό τρόπο με τον οποίο καλείται (χωρίς άλλα ορίσματα) πρέπει να μπορεί να υποστηρίζει τα ακόλουθα προαιρετικά ορίσματα για τον καθορισμό των παραμέτρων:

Οι παραπάνω παράμετροι πρέπει να τηρούνται πλήρως κατά την παραγωγή του ηχητικού σήματος. Για το \(\pi\) μπορείτε να χρησιμοποιήσετε τη συμβολική σταθερά M_PI, που είναι ορισμένη στο math.h. Ο ήχος που θα παραχθεί να είναι μονοφωνικός (MonoStereo = 1) και να αναπαρίσταται με 2 bytes ανά δείγμα (BitsPerSample = 16). Καλέστε το πρόγραμμά σας με τις default παραμέτρους. Τι ήχος παράγεται; Ενδεικτική εκτέλεση:

$ ./soundwave generate > mysound.wav
$ ./soundwave info < mysound.wav
size of file: 264636
size of format chunk: 16
WAVE type format: 1
mono/stereo: 1
sample rate: 44100
bytes/sec: 88200
block alignment: 2
bits/sample: 16
size of data chunk: 264600
./soundwave generate --dur 5 --fm 1.2 --fc 300 --mi 100 --amp 15000 > space.wav

Διαγωνισμός Δημιουργικότητας και Τελική Υποβολή

Σας συνιστούμε να πειραματιστείτε και με άλλες δυνατότητες—για παράδειγμα την προσθήκη ορισμάτων --help ώστε να μπορεί να βρούμε μια γρήγορη περιγραφή των διαφόρων δυνατοτήτων του προγράμματός σας. Για να λάβετε συμμετοχή στον διαγωνισμό δημιουργικότητας στο τέλος του εξαμήνου, μπορείτε να υλοποιήσετε μια δική σας υποεντολή ./soundwave dj (με όποια ορίσματα θέλετε) η οποία θα είναι σε θέση να παράξει ενδιαφέροντες και δημιουργικούς ήχους! Αν κάποια υποβολή μας εκπλήξει, θα λάβει επιπλέον bonus μέχρι 50% της βαθμολογίας.

Τέλος, πριν την υποβολή της εργασίας, μην ξεχάσετε το soundwave/README.md, μέσα στο οποίο πρέπει να συμπεριλάβετε τις όποιες παρατηρήσεις σας κατά την διεκπεραίωση της άσκησης. Ο κώδικας απαιτείται να είναι καλά τεκμηριωμένος με σχόλια καθώς αυτό θα είναι μέρος της βαθμολόγησης.

Υπόδειξη

Γράψε πρώτα βοηθητικές συναρτήσεις που διαβάζουν (και γράφουν) έναν ακέραιο 2 ή 4 bytes little-endian με getchar/putchar, συνθέτοντας τα bytes με ολισθήσεις και |, και έλεγξε παντού για EOF. Επειδή δεν χωράει όλο το αρχείο στη μνήμη και δεν επιτρέπονται δομές, επεξεργάσου τα δείγματα σε ροή, ένα-ένα, και σκέψου ποια πεδία της κεφαλίδας αλλάζουν σε κάθε υποεντολή (π.χ. στο channel αλλάζουν τα μεγέθη, όχι μόνο τα δείγματα). Πρόσεξε ότι τα δείγματα των 8 bits είναι χωρίς πρόσημο ενώ των 16 bits με πρόσημο, κάτι που μετράει στο volume, και ότι η generate πρέπει να ξέρει εκ των προτέρων το SizeOfData για να γράψει την κεφαλίδα.

Αριθμός στον οδηγό: Α9.17 (στο κεφάλαιο) · Μόνιμο αναγνωριστικό: hw-2025-hw1-soundwave · Σύνδεσμος: https://progintro.github.io/study/questions/homework/hw-2025-hw1-soundwave.html · Markdown (GitHub)