Add some overengineered-to-hell sound
author |
Steve Losh <steve@stevelosh.com> |
date |
Mon, 21 Nov 2016 20:29:54 +0000 |
parents |
553c97ea41b7
|
children |
e20d9e9b90b3
|
branches/tags |
(none) |
files |
cl-chip8.asd src/debugger.lisp src/emulator.lisp |
Changes
--- a/cl-chip8.asd Mon Nov 21 17:57:45 2016 +0000
+++ b/cl-chip8.asd Mon Nov 21 20:29:54 2016 +0000
@@ -11,6 +11,7 @@
:losh
:cl-arrows
:bordeaux-threads
+ :cl-portaudio
:qtools
:qtcore
:qtgui
--- a/src/debugger.lisp Mon Nov 21 17:57:45 2016 +0000
+++ b/src/debugger.lisp Mon Nov 21 20:29:54 2016 +0000
@@ -149,14 +149,18 @@
(cond
((<= row 15) (format nil "V~X" row))
((= row 16) "I")
- ((= row 17) "PC")))
+ ((= row 17) "PC")
+ ((= row 18) "DT")
+ ((= row 19) "ST")))
(defun registers-value (chip row)
(cond
((<= row 15) (format nil "~2,'0X"
(aref (chip8::chip-registers chip) row)))
((= row 16) (format nil "~4,'0X" (chip8::chip-index chip)))
- ((= row 17) (format nil "~3,'0X" (chip8::chip-program-counter chip)))))
+ ((= row 17) (format nil "~3,'0X" (chip8::chip-program-counter chip)))
+ ((= row 18) (format nil "~2,'0X" (chip8::chip-delay-timer chip)))
+ ((= row 19) (format nil "~2,'0X" (chip8::chip-sound-timer chip)))))
;;;; Model
@@ -170,12 +174,12 @@
(define-override (registers-model row-count) (index)
(declare (ignore index))
- 18)
+ 20)
(defun registers-index-valid-p (index)
(and (q+:is-valid index)
- (< (q+:row index) 18)))
+ (< (q+:row index) 20)))
(define-override (registers-model data) (index role)
(let ((row (q+:row index))
--- a/src/emulator.lisp Mon Nov 21 17:57:45 2016 +0000
+++ b/src/emulator.lisp Mon Nov 21 20:29:54 2016 +0000
@@ -286,7 +286,7 @@
(if (not paused) ; if we're not paused, we never need to wait
nil
(if take-step
- (progn (setf take-step nil ; if we're paused, but are ready to step, go
+ (progn (setf take-step nil ; if we're paused, but are ready to step, go
print-needed t)
nil)
t)))) ; otherwise we're fully paused -- wait
@@ -533,6 +533,82 @@
(draw-sprite chip (register rx) (register ry) size))
+;;;; Sound --------------------------------------------------------------------
+(defconstant +pi+ (float pi 1.0))
+(defconstant +tau+ (* 2 +pi+))
+(defconstant +sample-rate+ 44100d0)
+(defconstant +audio-buffer-size+ 1024)
+(defconstant +audio-buffer-time+ (* +audio-buffer-size+ (/ +sample-rate+)))
+
+(deftype angle ()
+ `(single-float 0.0 ,+tau+))
+
+(deftype audio-buffer ()
+ `(simple-array single-float (,+audio-buffer-size+)))
+
+
+(declaim
+ (ftype (function (angle) (single-float -1.0 1.0))
+ square sine)
+ (ftype (function (audio-buffer function angle angle) angle)
+ fill-buffer)
+ (inline square sine fill-buffer))
+
+
+(defun make-audio-buffer ()
+ (make-simple-array 'single-float +audio-buffer-size+ :initial-element 0.0))
+
+
+(defun square (angle)
+ (declare (optimize (debug 0) (safety 0) (speed 3)))
+ (if (< angle +pi+)
+ 1.0
+ -1.0))
+
+(defun sine (angle)
+ (declare (optimize (debug 0) (safety 0) (speed 3)))
+ (sin angle))
+
+
+(defun fill-buffer (buffer function rate start)
+ ; (declare (optimize (debug 0) (safety 0) (speed 3)))
+ (iterate
+ (declare (iterate::declare-variables))
+ (for (the fixnum i) :index-of-vector buffer)
+ (for (the angle angle) :first start :then (mod (+ angle rate) +tau+))
+ (setf (aref buffer i) (funcall function angle))
+ (finally (return angle))))
+
+(defun fill-square (buffer rate start)
+ (fill-buffer buffer #'square rate start))
+
+(defun fill-sine (buffer rate start)
+ (fill-buffer buffer #'sine rate start))
+
+
+(defun audio-rate (frequency)
+ (float (* (/ +tau+ +sample-rate+) frequency) 1.0))
+
+(defun run-sound (chip)
+ (portaudio:with-audio
+ (portaudio:with-default-audio-stream
+ (audio-stream 0 1
+ :sample-format :float
+ :sample-rate +sample-rate+
+ :frames-per-buffer +audio-buffer-size+)
+ (with-chip (chip)
+ (iterate (with buffer = (make-audio-buffer))
+ (with angle = 0.0)
+ (with rate = (audio-rate 440))
+ (while running)
+ (if (and (plusp sound-timer)
+ (not (debugger-paused-p debugger)))
+ (progn
+ (setf angle (fill-square buffer rate angle))
+ (portaudio:write-stream audio-stream buffer))
+ (sleep +audio-buffer-time+)))))))
+
+
;;;; Timers -------------------------------------------------------------------
(declaim
(ftype (function (chip) null) decrement-timers run-timers))
@@ -655,6 +731,7 @@
(load-rom chip rom-filename)
(bt:make-thread (curry #'run-cpu chip))
(bt:make-thread (curry #'run-timers chip))
+ (bt:make-thread (curry #'run-sound chip))
(chip8.gui::run-gui chip)))