From d5637f0c8d51eca4d7fe14d1e2b9c5c8bc0121b3 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Wed, 9 Jan 2019 20:25:45 -0500 Subject: audio: Add WAV module. * chickadee/audio/wav.scm: New file. * Makefile.am (SOURCES): Add it. --- Makefile.am | 1 + chickadee/audio/wav.scm | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 chickadee/audio/wav.scm diff --git a/Makefile.am b/Makefile.am index f9776f8..765a488 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,7 @@ SOURCES = \ chickadee/math/easings.scm \ chickadee/math/path-finding.scm \ chickadee/audio/openal.scm \ + chickadee/audio/wav.scm \ chickadee/render/color.scm \ chickadee/render/gl.scm \ chickadee/render/gpu.scm \ diff --git a/chickadee/audio/wav.scm b/chickadee/audio/wav.scm new file mode 100644 index 0000000..9b39ad4 --- /dev/null +++ b/chickadee/audio/wav.scm @@ -0,0 +1,104 @@ +;;; Chickadee Game Toolkit +;;; Copyright © 2019 David Thompson +;;; +;;; Chickadee is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published +;;; by the Free Software Foundation, either version 3 of the License, +;;; or (at your option) any later version. +;;; +;;; Chickadee is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program. If not, see +;;; . + +;;; Commentary: +;; +;; WAV decoder. +;; +;;; Code: + +(define-module (chickadee audio wav) + #:use-module (ice-9 binary-ports) + #:use-module (ice-9 format) + #:use-module (rnrs bytevectors) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-9 gnu) + #:export (open-wav + close-wav + wav? + wav-num-channels + wav-sample-rate + wav-byte-rate + wav-bits-per-sample + wav-length + wav-read + wav-time-seek)) + +(define-record-type + (make-wav num-channels sample-rate byte-rate + block-align bits-per-sample length port) + wav? + (num-channels wav-num-channels) + (sample-rate wav-sample-rate) + (byte-rate wav-byte-rate) + (block-align wav-block-align) + (bits-per-sample wav-bits-per-sample) + (length wav-length) + (port wav-port)) + +(define (display-wav wav port) + (format port "#" + (wav-num-channels wav) + (wav-sample-rate wav) + (wav-byte-rate wav) + (wav-block-align wav) + (wav-bits-per-sample wav) + (wav-length wav))) + +(set-record-type-printer! display-wav) + +(define (open-wav file-name) + (let* ((port (open-file file-name "r")) + (bv (get-bytevector-n port 44)) + (data-length (bytevector-uint-ref bv 40 'little 4))) + ;; Validate the magic values that must be present in the header. + (unless (and (= (bytevector-uint-ref bv 0 'big 4) #x52494646) ; RIFF + (= (bytevector-uint-ref bv 8 'big 4) #x57415645) ; WAVE + (= (bytevector-uint-ref bv 12 'big 4) #x666d7420) ; fmt + (= (bytevector-uint-ref bv 36 'big 4) #x64617461)) ; data + (error "invalid WAV header in file:" file-name)) + ;; Only PCM data is supported. + (unless (= (bytevector-uint-ref bv 20 'little 2) 1) + (error "WAV data not in PCM format:" file-name)) + (make-wav (bytevector-uint-ref bv 22 'little 2) ; num channels + (bytevector-uint-ref bv 24 'little 4) ; sample rate + (bytevector-uint-ref bv 28 'little 4) ; byte rate + (bytevector-uint-ref bv 32 'little 2) ; block align + (bytevector-uint-ref bv 34 'little 2) ; bits per sample + data-length + port))) + +(define (close-wav wav) + "Close the open file port for WAV." + (close-port (wav-port wav))) + +(define (wav-read wav bv) + "Fill BV with audio samples from WAV and return the number of bytes +read." + (let ((bytes-read (get-bytevector-n! (wav-port wav) bv 0 (bytevector-length bv)))) + (if (eof-object? bytes-read) 0 bytes-read))) + +(define (wav-time-seek wav time) + "Change the play head to TIME in WAV." + (seek (wav-port wav) + (+ 44 (inexact->exact + (ceiling + (* time + (wav-num-channels wav) + (wav-byte-rate wav) + (wav-sample-rate wav))))) + SEEK_SET)) -- cgit v1.2.3