write.scm 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. (library (riff-wave-writer)
  2. (export pi
  3. sine*
  4. make-sine-func
  5. make-stepper
  6. make-sine-oscillator
  7. sample-function
  8. float->bytevector
  9. integer->bytevector
  10. max-amplitude)
  11. (import (except (rnrs base) let-values vector-for-each)
  12. (only (guile)
  13. lambda* λ
  14. ;; printing
  15. ;; display
  16. ;; simple-format
  17. ;; numbers
  18. inexact->exact
  19. ;; input output
  20. call-with-output-file
  21. current-output-port)
  22. (ice-9 exceptions)
  23. (ice-9 binary-ports)
  24. (rnrs bytevectors)
  25. (srfi srfi-43)
  26. ;; structs
  27. (srfi srfi-9)
  28. ;; functional structs
  29. (srfi srfi-9 gnu)
  30. (bytevector-utils)
  31. (model)
  32. (math)))
  33. ;;; function utilities
  34. (define make-stepper
  35. (λ (func step-size)
  36. "Make a function, which calls FUNC with an argument, which
  37. is calculated according to a given STEP-SIZE."
  38. (λ (n)
  39. (func (* n step-size)))))
  40. (define make-sine-oscillator
  41. (λ (sine-func step-size)
  42. "Return a function, which takes a factor for a step-index to
  43. calculate a sine value at that step."
  44. (make-stepper sine-func step-size)))
  45. (define sample-function
  46. (λ (stepped-func num-samples)
  47. "Given a function FUNC, return a vector of NUM-SAMPLES
  48. consequtive samples."
  49. (let ([sample-vector (make-vector num-samples 0)])
  50. (let iter ([counter 0])
  51. (cond
  52. [(< counter num-samples)
  53. (vector-set! sample-vector
  54. counter
  55. ;; Expects a stepped function. A
  56. ;; stepped function translates the
  57. ;; input argument to the nth step as
  58. ;; input argument. Such as produced
  59. ;; by make-stepper.
  60. (stepped-func counter))
  61. (iter (+ counter 1))]
  62. [else sample-vector])))))
  63. ;;; calculation
  64. (define max-amplitude
  65. (λ (bit-depth)
  66. (- (expt 2 (- bit-depth 1)) 1)))
  67. (define write-riff-wave
  68. (λ (file-name riff-wave bit-depth)
  69. (define maximum-amplitude (max-amplitude bit-depth))
  70. (define convert-sample
  71. (λ (sample)
  72. (integer->bytevector
  73. (float->scaled-truncated-integer sample maximum-amplitude)
  74. 2 #:endianness 'little)))
  75. (define chunk-header-bytevectors
  76. (λ (id size)
  77. "Construct a list of bytevectors for given chunk header
  78. information and return it."
  79. (list (ascii-string->bytevector id 4 #:endianness 'big)
  80. (integer->bytevector size 4 #:endianness 'little))))
  81. (call-with-output-file file-name
  82. (λ (out-port)
  83. (let ([header-chunk (riff-wave-header-chunk riff-wave)]
  84. [format-chunk (riff-wave-format-chunk riff-wave)]
  85. [data-chunk (riff-wave-data-chunk riff-wave)])
  86. ;; Write the header chunk -- The header chunk only
  87. ;; has a header. Or interpreted differently, its
  88. ;; data are the other chunks.
  89. (for-each (λ (bv) (put-bytevector out-port bv))
  90. (append
  91. (chunk-header-bytevectors
  92. (header-chunk-id header-chunk)
  93. (header-chunk-size header-chunk))
  94. (list
  95. (ascii-string->bytevector (header-chunk-riff-type header-chunk)
  96. 4 #:endianness 'big))))
  97. ;; Write the format chunk header.
  98. (for-each (λ (bv) (put-bytevector out-port bv))
  99. (chunk-header-bytevectors
  100. (format-chunk-id format-chunk)
  101. (format-chunk-size format-chunk)))
  102. ;; Write the format chunk.
  103. (put-bytevector
  104. out-port
  105. (integer->bytevector
  106. (format-chunk-compression-code format-chunk)
  107. COMPRESSION-CODE-BYTES #:endianness 'little))
  108. (put-bytevector
  109. out-port
  110. (integer->bytevector
  111. (format-chunk-num-channels format-chunk)
  112. NUM-CHANNELS-BYTES #:endianness 'little))
  113. (put-bytevector
  114. out-port
  115. (integer->bytevector
  116. (format-chunk-sample-rate format-chunk)
  117. SAMPLE-RATE-BYTES #:endianness 'little))
  118. (put-bytevector
  119. out-port
  120. (integer->bytevector
  121. (format-chunk-avg-byte-rate format-chunk)
  122. AVG-BYTE-RATE-BYTES #:endianness 'little))
  123. (put-bytevector
  124. out-port
  125. (integer->bytevector
  126. (format-chunk-block-align format-chunk)
  127. BLOCK-ALIGN-BYTES #:endianness 'little))
  128. (put-bytevector
  129. out-port
  130. (integer->bytevector
  131. (format-chunk-significant-bits-per-sample format-chunk)
  132. SIGNIFICANT-BITS-PER-SAMPLE-BYTES #:endianness 'little))
  133. ;; Write the data chunk header.
  134. (for-each (λ (bv) (put-bytevector out-port bv))
  135. (chunk-header-bytevectors
  136. (data-chunk-id data-chunk)
  137. (data-chunk-size data-chunk)))
  138. ;; Write the data chunk.
  139. (vector-for-each
  140. (λ (_index sample)
  141. (put-bytevector out-port (convert-sample sample)))
  142. (data-chunk-samples data-chunk)))))))
  143. (let* ([file-name "waveform.wav"]
  144. [duration 2 #|seconds|#]
  145. [sample-rate 44100]
  146. [step-size (/ 1 sample-rate)]
  147. [sine-func (make-sine-func #:amplitude #e0.5 #:frequency 440)]
  148. [oscillator (make-sine-oscillator sine-func step-size)]
  149. [num-channels 1] ; mono
  150. [compression-code 1] ; uncompressed
  151. [bit-depth 16] ; multiple of 8
  152. [extra-format-bytes-count 0]
  153. [samples-count (* duration sample-rate)]
  154. [samples (sample-function oscillator samples-count)])
  155. (let ([riff-wave
  156. (make-riff-wave
  157. (make-header-chunk (calculate-header-chunk-size
  158. (calculate-format-chunk-size extra-format-bytes-count)
  159. (calculate-data-chunk-size samples-count
  160. bit-depth
  161. num-channels)))
  162. (make-format-chunk compression-code
  163. num-channels
  164. sample-rate
  165. bit-depth)
  166. (make-data-chunk samples
  167. bit-depth
  168. num-channels))])
  169. (write-riff-wave file-name riff-wave bit-depth)))