CL-RemiWav
CL-RemiWav is a library for reading and writing WAVE files. It supports (or will support) multiple bit depths and sample rates; IEEE Floating Point WAVs; and μ-law, A-law, and (some) ADPCM encodings. It also contains utilities for dithering, bit rate conversions, and ADPCM decoding/encoding.
CL-RemiWav is licensed under the GNU Affero General Public License version 3
You will need Fossil to clone this source code repository.
Wanna support me? Buy me a coffee on Ko-Fi
Features
- Reading WAV files
- [x] 1 to 24 channels
- [x] Sample rates from 8000 to 192000
- [x] Integer sample formats: unsigned 8-bit, signed 12, 16, 24, 32, and 64-bit.
- [x] IEEE Floating Point sample formats: 32-bit and 64-bit.
- [x] μ-law and A-law sample formats
- [ ] Extensible formats (ADPCM, MP3, etc.)
- [ ] Related RIFF chunks (cue , inst, smpl, ltxt, note, labl, plst, etc.)
- Writing WAV files
- [x] 1 to 24 channels
- [x] Sample rates from 8000 to 192000
- [x] Integer sample formats: unsigned 8-bit, signed 12, 16, 24, 32, and 64-bit.
- [x] IEEE Floating Point sample formats: 32-bit and 64-bit.
- [x] μ-law and A-law sample formats
- [ ] Extensible formats (ADPCM, MP3, etc.)
- [ ] Related RIFF chunks (cue , inst, smpl, ltxt, note, labl, plst, etc.)
- Streaming API
- [x] Reading samples from a streamed WAV
- [x] Writing samples to a streamed WAV
- [x] Arbitrary sample conversion during writing
- Miscellaneous
- [x] Bit-depth conversion with optional TPDF dithering
- [ ] Sample rate conversions
- [x] Integer -> Floating Point sample conversions
- [x] High quality μ-law and A-law conversion
- [x] YM2610 ADPCM-A codec
- [ ] YM2610 ADPCM-B codec
Examples
Print some information about a WAV.
(let ((wav (cl-remiwav:read-wav #P"/path/to/file.wav")))
(format t "WAV file format: ~a-bit ~a ~a Hz ~a channel~:*~p~%"
(cl-remiwav:wav-bit-depth wav)
(cl-remiwav:wav-encoding wav)
(cl-remiwav:wav-sample-rate wav)
(cl-remiwav:wav-channels wav))
(format t "WAV file has ~:d sample~:*~p~%"
(truncate (length (cl-remiwav:wav-file-data wav))
(cl-remiwav:wav-channels wav))))
Read a WAV, then write it to another file using the streaming API.
(let ((orig (cl-remiwav:read-wav #P"/path/to/file.wav")))
(cl-remiwav:with-output-to-wav-file
(wav #P"/tmp/foo.wav"
:if-exists :error ;; Don't clobber existing files
:bit-depth (cl-remiwav:wav-bit-depth orig)
:sample-rate (cl-remiwav:wav-sample-rate orig)
:encoding (cl-remiwav:wav-encoding orig)
:channels (cl-remiwav:wav-channels orig))
(cl-remiwav:write-samples wav (cl-remiwav:wav-file-data orig))))
Generate a sine wav for 5 seconds, using a one-second buffer, and write it to a WAV using the streaming API.
(let* ((sample-rate 22050)
(frequency 440.0d0) ;; A below middle C
(seconds 5)
(volume 0.5)
(buffer (make-array sample-rate :element-type '(signed-byte 16)
:initial-element 0))
(x 0.0d0))
(cl-remiwav:with-output-to-wav-file
(wav #P"/path/to/new-file.wav"
:if-exists :error ;; Don't clobber existing files
:bit-depth 16
:sample-rate sample-rate
:encoding :lpcm
:channels 1)
;; The buffer is only one second long, and we want 5 seconds.
(dotimes (i 5)
;; Fill the buffer, which is only one second long
(loop for idx from 0 below (length buffer) do
(setf (aref buffer idx)
(sdm:coerce-to-int16
;; Convert the float sample -> 16-bit sample
(truncate (* 32768 (* volume (sin (/ (* pi x frequency)
sample-rate)))))))
(incf x))
;; Write the buffer to the WAV
(cl-remiwav:write-samples wav buffer))))
Generate a sine wav for 5 seconds, and write it to a µ-law encoded WAV using the streaming API.
(let* ((sample-rate 8000)
(frequency 440.0d0) ;; A below middle C
(seconds 5)
(volume 0.5)
(buffer (make-array (* sample-rate seconds)
:element-type '(signed-byte 16)
:initial-element 0))
(x 0.0d0))
(cl-remiwav:with-output-to-wav-file
(wav #P"/path/to/new-file.wav"
:if-exists :error ;; Don't clobber existing files
:bit-depth 8
:sample-rate sample-rate
:encoding :mu-law
:channels 1)
;; Fill the buffer, which is only one second long
(loop for idx from 0 below (length buffer) do
(setf (aref buffer idx)
(sdm:coerce-to-int16
;; Convert the float sample -> 16-bit sample
(truncate (* 32768 (* volume (sin (/ (* pi x frequency)
sample-rate)))))))
(incf x))
;; Write the buffer to the WAV using a converter function since we have
;; 16-bit PCM samples.
(cl-remiwav:write-samples wav buffer #'cl-remiwav:int16->mu-law)))
Building and Development
This has been tested with SBCL, CCL, and Clisp. Please see the Building article in the wiki for information on loading the library and running tests.
Style info
I use a slightly different style for my code.
- Keep lines 118 characters or shorter. Obviously sometimes you can't, but please try. Use 80 characters for Markdown files, though.
- New type declarations should have their names prefixed with
T/
, for example,t/uint32-vector
. This is only for DEFTYPEs and DEFINE-PSEUDO-ENUMs.
How do I contribute?
- Go to https://chiselapp.com/user/MistressRemilia/repository/cl-remiwav/ and clone the Fossil repository.
- Create a new branch for your feature.
- Push locally to the new branch.
- Create a bundle with Fossil that contains your changes.
- Get in contact with me.
Contributors
- Remilia Scarlet - creator and maintainer
- Homepage: https://alexa.partition36.com/
- Mastodon: @MistressRemilia@mastodon.sdf.org
- Email: zremiliaz@postzeoz.jpz My real address does not contain Z's
Other
Test WAV files in the t/
directory are taken from
http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Samples.html