aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--music.nim59
-rw-r--r--musiclib.nim20
2 files changed, 48 insertions, 31 deletions
diff --git a/music.nim b/music.nim
index 15a2fc3..24c01ca 100644
--- a/music.nim
+++ b/music.nim
@@ -1,7 +1,7 @@
-import musiclib, std/math
+import musiclib, std/[math, sugar]
# Number of times to sample each second
-let bitrate = 44100
+const bitrate = 44100
func osc_piano*(f, t: float): float =
## Returns the intensity of a tone of frequency f sampled at time t
@@ -20,15 +20,28 @@ func osc_piano*(f, t: float): float =
Y *= 1 + 16 * t * math.exp(-6 * t)
Y
+func osc_pulse*(f,t:float):float =
+ let width = (1.0 / f) / 2
+ let phase: float = t mod (width * 2)
+ if phase < width: 1.0 else: -1.0
+
func freq*(octave, step: float): float =
## Returns the frequency of a note
55 * pow(2, (octave + step / 12 - 1))
-func p*(len, octave, step, vol: float = 1): Note =
+var osc: OscFn = (f, t: float) => 0.0
+
+proc p*(len, octave, step, vol: float = 1): Note =
## Note helper constructor
- let osc: OscFn = osc_piano
(len, freq(octave, step), vol, osc)
+
+#------- song region -------
+
+const GAIN_NORMAL = 0.24
+
+osc = (f, t: float) => osc_piano(f, t) * GAIN_NORMAL
+
let intro = [
p(1,3,3),
p(1,3,7),
@@ -51,6 +64,8 @@ let intro = [
p(8,3,7),
]
+# osc = osc_pulse
+
let melody = [
p(1,3,3),
p(1,3,7),
@@ -119,17 +134,6 @@ let melody = [
p(2,4,10),
]
-let bass = [
- p(1,1,3),
- p(1,1,10),
- p(1,1,1),
- p(1,1,8),
- p(1,1,3),
- p(1,2,3),
- p(1,1,1),
- p(1,1,10),
-]
-
let melody2 = [
p(1,0,0),
p(1,5,10),
@@ -273,6 +277,19 @@ let outro = [
p(16,3,7,2),
]
+osc = (f, t: float) => osc_piano(f, t) * GAIN_NORMAL * 1.5
+
+let bass = [
+ p(1,1,3),
+ p(1,1,10),
+ p(1,1,1),
+ p(1,1,8),
+ p(1,1,3),
+ p(1,2,3),
+ p(1,1,1),
+ p(1,1,10),
+]
+
from std/algorithm import sort
# Process all lists of notes
@@ -280,16 +297,16 @@ var music: seq[ProcessedNote] = @[]
music.process(intro, 0, 4)
music.process(melody, 8, 4)
music.process(melody, 24, 4)
-music.process(bass, 24, gain=1.5)
-music.process(bass, 32, gain=1.5)
+music.process(bass, 24)
+music.process(bass, 32)
music.process(melody, 40, 4)
music.process(melody2, 40, 4)
-music.process(bass, 40, gain=1.5)
-music.process(bass, 48, gain=1.5)
+music.process(bass, 40)
+music.process(bass, 48)
music.process(melody, 56, 4)
music.process(melody3, 56, 4)
-music.process(bass, 56, gain=1.5)
-music.process(bass, 64, gain=1.5)
+music.process(bass, 56)
+music.process(bass, 64)
music.process(outro, 72, 4)
music.sortByStart()
diff --git a/musiclib.nim b/musiclib.nim
index 4984596..91e63c4 100644
--- a/musiclib.nim
+++ b/musiclib.nim
@@ -16,12 +16,9 @@ type
vol: float
osc: OscFn
-## give some seconds for the note to fade out
-const HACK_DROPOFF_DELAY = 2.0
-
const HACK_LONGEST_NOTE = 16.0
-func process*(music: var seq[ProcessedNote], notes: openArray[Note]; start_init: float, speed: float=1, gain:float = 1) =
+func process*(music: var seq[ProcessedNote], notes: openArray[Note]; start_init: float, speed: float=1) =
## Adds a list of notes to the music list
##
## `notes` sequence of notes with no rests in between
@@ -32,7 +29,7 @@ func process*(music: var seq[ProcessedNote], notes: openArray[Note]; start_init:
assert note.len <= HACK_LONGEST_NOTE, &"note too long: {note.len}"
start = t
let stop = t + note.len / speed
- music &= (start, stop, note.freq, note.vol * gain, note.osc)
+ music &= (start, stop, note.freq, note.vol, note.osc)
t = stop
func sortByStart*(music: var seq[ProcessedNote]) =
@@ -45,7 +42,7 @@ func bisect(music: openArray[ProcessedNote], x: float): int =
music.lowerBound(x, (m, key) => cmp(m.start, key))
-const GAIN_BIAS: float = pow(2.0, 28.0)
+const GAIN_BIAS: float = pow(2.0, 31.0)
proc at*(music: openArray[ProcessedNote], t: float): int32 =
## Returns the total intensity of music sampled at time t
@@ -59,10 +56,13 @@ proc at*(music: openArray[ProcessedNote], t: float): int32 =
while i >= 0:
let m = music[i]
assert m.start <= t
- if m.stop + HACK_DROPOFF_DELAY >= t:
- ret += m.vol * m.osc(m.freq, t - m.start)
- if m.start + HACK_LONGEST_NOTE + HACK_DROPOFF_DELAY < t:
+ if m.start + HACK_LONGEST_NOTE < t:
break
+ else:
+ ret += m.vol * m.osc(m.freq, t - m.start)
i -= 1
- int32(ret * GAIN_BIAS)
+ ret *= GAIN_BIAS
+
+ # clip sample
+ clamp(ret, int32.low.float..int32.high.float).int32