-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwave.lisp
126 lines (109 loc) · 5.19 KB
/
wave.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
;;;; wave.lisp
;;;;
;;;; Wave class definition and methods
(in-package #:cl-wave)
;;; Wave Class
(defclass wave ()
((io :initarg :io :accessor io)
(chunks :initform (list (list :chunk-id "RIFF"
:chunk-size 36
:chunk-data "WAVE")
(list :chunk-id "fmt "
:chunk-size 16
:chunk-data (list :compression-code 1
:num-channels 1
:sample-rate 44100
:byte-rate 88200
:sample-bytes 2
:sample-bits 16))
(list :chunk-id "data"
:chunk-size 0
:chunk-data '()))
:accessor chunks)
(params :accessor params)
(frames :accessor frames))
(:documentation "General wave class for holding pointer to io stream and params."))
(defclass read-wave (wave) ()
(:documentation "Class for reading wave files."))
(defclass write-wave (wave) ()
(:documentation "Class for writing wave files."))
;;; Wave Methods
(defmethod initialize-instance :after ((wave read-wave) &key)
"Reads the wave's binary data the sets its parameters/frames accordingly."
(setf (chunks wave) (read-chunks (io wave) #'wave-parser))
(setf (params wave) (getf (cadr (chunks wave)) :chunk-data))
(setf (frames wave) (getf (caddr (chunks wave)) :chunk-data)))
(defmethod initialize-instance :after ((wave write-wave) &key)
"Creates a wave with the default parameters and no frames."
(setf (params wave) (getf (cadr (chunks wave)) :chunk-data))
(setf (frames wave) (getf (caddr (chunks wave)) :chunk-data)))
(defmethod get-num-channels ((wave wave))
"Returns the number of channels the wave object has."
(getf (params wave) :num-channels))
(defmethod get-sample-rate ((wave wave))
"Returns the sample rate of the wave object."
(getf (params wave) :sample-rate))
(defmethod get-sample-width ((wave wave) &key bits)
"Returns the sample width in bytes (or bits if specified)."
(getf (params wave) (if bits :sample-bits :sample-bytes)))
(defmethod get-num-frames ((wave wave))
"Returns the number of frames."
(length (frames wave)))
(defmethod get-params ((wave wave))
"Returns several parameters in a property-list."
(list :num-channels (get-num-channels wave)
:sample-rate (get-sample-rate wave)
:sample-width (get-sample-width wave)
:num-frames (get-num-frames wave)))
(defmethod get-frames ((wave wave) &key (start 0) (end nil))
"Returns a list of all the frames or a subset of them."
(if end
(subseq (frames wave) start end)
(subseq (frames wave) start)))
(defmethod set-num-channels ((wave write-wave) num-channels)
"Sets the number of channels."
(setf (getf (params wave) :num-channels) num-channels))
(defmethod set-sample-rate ((wave write-wave) sample-rate)
"Sets the sample rate."
(setf (getf (params wave) :sample-rate) sample-rate))
(defmethod set-sample-width ((wave write-wave) bytes)
"Sets the sample width."
(setf (getf (params wave) :sample-bytes) bytes)
(setf (getf (params wave) :sample-bits) (* bytes 8)))
(defmethod set-frames ((wave write-wave) new-frames)
"Sets the frames."
(setf (frames wave) new-frames))
;;; Parser/Printer for Wave Binary
(defun wave-parser (stream chunk-id chunk-size chunks)
"Parsing function for wave's RIFF chunks."
(cond ((string= chunk-id "fmt ")
(append (list :compression-code (read-uint stream 2)
:num-channels (read-uint stream 2)
:sample-rate (read-uint stream 4)
:byte-rate (read-uint stream 4)
:sample-bytes (read-uint stream 2)
:sample-bits (read-uint stream 2))
(when (= chunk-size 18)
(list :extension-size (read-uint stream 2)))))
((string= chunk-id "data")
(loop with bytes = (getf (getf (cadr chunks) :chunk-data) :sample-bytes)
repeat (/ chunk-size bytes)
collect (read-sint stream bytes)))
(t
(default-parser stream chunk-id chunk-size chunks))))
(defun wave-printer (stream chunk-id chunk-size chunk-data chunks)
"Printing function for wave's RIFF chunks."
(cond ((string= chunk-id "fmt ")
(write-uint stream (getf chunk-data :compression-code) 2)
(write-uint stream (getf chunk-data :num-channels) 2)
(write-uint stream (getf chunk-data :sample-rate) 4)
(write-uint stream (getf chunk-data :byte-rate) 4)
(write-uint stream (getf chunk-data :sample-bytes) 2)
(write-uint stream (getf chunk-data :sample-bits) 2)
(when (= chunk-size 18)
(write-uint stream (getf chunk-data :extension-size) 2)))
((string= chunk-id "data")
(loop with bytes = (getf (getf (cadr chunks) :chunk-data) :sample-bytes)
for frame in chunk-data do (write-sint stream frame bytes)))
(t
(default-printer stream chunk-id chunk-size chunk-data chunks))))