-
Notifications
You must be signed in to change notification settings - Fork 0
/
cheese.hs
151 lines (124 loc) · 4.47 KB
/
cheese.hs
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
-- Copyright (c) 2020 Shawn Eary
--
-- Cheese - My attempt to create a cheezy Baroque music music piece
-- using Haskell to generate the music
--
-- When this music piece is done, hopefully it won't give you too much
-- gas... Remember, never eat more than 3x your maximum daily allowance
-- of Cheez-Its (R)... No, I wasn't given permission to use the
-- Cheez-It trademark...
--
-- Cheese is Licenced via the MIT License
--
-- COMPILATION STEPS:
-- ghc cheese.hs
--
-- REFERENCES:
-- 1) Install GHC
-- 2) Install GNU Make
-- 3) Change to this directory and run the command
-- make
import Data.Word
import System.IO
import qualified Data.ByteString as BStr
import qualified Generators as Gens
import AudioFormat
----------------------------------------------------------------------
-- GLOBALS --
----------------------------------------------------------------------
outputFile = "out.wav"
numChannels = 1 -- Mono for now
sampleRate = 48000 -- Sampling Rate in Hertz
-- 48000 is *LUDICROUS* overkill for a simple
-- sine wave within the knowable notes on a piano
-- keyboard but it is a common audio standard. In
-- reality 8000 HZ would probably do just find since
-- a sine wave does not have artifacts, but 48000
-- is still used hre since it is a common sampling
-- rate for pro audio tools
genFunction = Gens.sine -- Keep it simple for now
bitsPerSample = 8 -- Keep it simple for now
beatsPerMinute=120.0
-- See [9] for a where these frequencies in Hertz came from
nA4 = 440
nG4 = 392
nF4 = 349
nE4 = 330
nD4 = 294
nC4 = 262 -- 261.6256
nG3 = 196 -- 195.9977
-- Hack for a REST
nRe = 0
-- Tracker Style Notation
bassLine=
[(nC4,1.0), (nG3,1.0) ,(nC4,1.0) ] ++
[(nD4,1.0), (nG3,1.0) ,(nD4,1.0) ] ++
[(nE4,1.0), (nF4,0.5),(nE4,0.5),(nD4,0.5),(nC4,0.5)] ++
[(nD4,1.0), (nG3,1.0) ,(nD4,1.0) ] ++
[(nC4,1.0), (nG3,1.0) ,(nC4,1.0) ] ++
[(nD4,1.0), (nG3,1.0) ,(nD4,1.0) ] ++
[(nD4,1.0), (nG3,1.0) ,(nD4,1.0) ] ++
[(nC4,3.0) ]
melody=
[(nE4,0.5),(nRe,0.5),(nE4,0.5),(nRe,0.5),(nE4,0.5),(nRe,0.5)] ++
[(nE4,1.5) ,(nF4,0.5),(nG4,1.0) ] ++
[(nG4,1.0) ,(nA4,0.5),(nG4,0.5),(nF4,0.5),(nE4,0.5)] ++
[(nD4,1.5) ,(nE4,0.5),(nD4,1.0) ] ++
[(nC4,0.5),(nRe,0.5),(nC4,0.5),(nRe,0.5),(nC4,0.5),(nRe,0.5)] ++
[(nC4,0.5),(nRe,0.5),(nD4,0.5),(nRe,0.5),(nE4,0.5),(nRe,0.5)] ++
[(nE4,0.5),(nRe,0.5),(nC4,0.5),(nRe,0.5),(nD4,0.5),(nRe,0.5)] ++
[(nE4,3.0) ]
-- Broke: Not Implemneted
-- This is probably going to go over like a lead ballon. "mix"
-- the signals by taking their "averge". Sure man...
-- mix :: [BStr.ByteString] -> BStr.ByteString
-- mix theLines = do
-- let numLines = length theLines
-- (theLines !! 0)
getPCMLine :: [(Int, Double)] -> Double -> BStr.ByteString
getPCMLine [] _ =
BStr.pack []
getPCMLine (l:ls) bpm = do
let beats = snd l
-- beats minute 60 seconds
-- ---------- ------- -----
-- beats minute
let seconds = beats / bpm * 60.0;
let freq = fst l
let genFunction =
if (freq == nRe) then
Gens.nullGen
else
Gens.sine
let pcmData =
getPCM
genFunction
sampleRate
freq
0.0
bitsPerSample
seconds
BStr.append pcmData (getPCMLine ls bpm)
avg :: Word8 -> Word8 -> Word8
avg l r = do
let halfOfLeft = (div l 2)
let halfOfRight = (div r 2)
(halfOfLeft + halfOfRight)
main :: IO ()
main = do
hWaveFile <- openFile outputFile WriteMode
let pcmData1 =
getPCMLine bassLine beatsPerMinute
let pcmData2 =
getPCMLine melody beatsPerMinute
-- See [10] for example of zipWith
let poorlyMixedResult =
BStr.pack (BStr.zipWith avg pcmData1 pcmData2)
let waveWrapperByteString =
getWaveByteString
poorlyMixedResult
numChannels
sampleRate
bitsPerSample
BStr.hPutStr hWaveFile waveWrapperByteString
hClose hWaveFile