Skip to content

Commit

Permalink
Add recorder that handles individual tapes
Browse files Browse the repository at this point in the history
  • Loading branch information
jmiskovic committed Mar 24, 2020
1 parent 2f5af75 commit 3f3d71d
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 58 deletions.
28 changes: 10 additions & 18 deletions main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ local l = require('lume')

local controls = require('controls')
local selector = require('selector')
local recorder = require('tapeRecorder')
local recorder = require('recorder')
local efx = require('efx')
local mock = require('mock')

local time = 0
local sw, sh, dpi
local patch = selector
local stream = {}
local tape1, tape2
local tape1

function love.resize()
sw, sh = love.graphics.getDimensions()
Expand All @@ -24,9 +24,9 @@ function love.load()
require('toolset') -- import module only after love.draw is defined
controls.load()
selector.load('patches')
tape1 = recorder.create()
tape1 = recorder.addTape()
tape2 = recorder.addTape()
tape1.position = {-1.65, -0.88}
tape2 = recorder.create()
tape2.position = {-1.30, -0.88}
mock.load()
love.audio.setPosition(0, 0, 0)
Expand Down Expand Up @@ -61,17 +61,12 @@ function love.update(dt)
if love.system.getOS() ~= 'Android' then
mock.process(stream)
end

recorder.interpret(stream, patch == selector)
patch:process(stream)
local t2r = tape2.recording
tape1:process(stream, patch)
tape2:process(stream, patch)
if t2r and not tape2.recording then
tape2.time = 0
tape2.time = tape2.length - tape1.length -- align start
tape2.length = tape1.length
end
recorder.process(stream)
efx.process(stream)
love.timer.sleep(0.003)
love.timer.sleep(0.053)
--stream is garbage collected
end

Expand All @@ -80,12 +75,10 @@ function love.draw()
love.graphics.origin()
transform()
patch:draw(stream)
tape1:draw()
tape2:draw()
recorder.draw()
love.graphics.origin()
--mock.draw(stream)
--drawTable(stream)
track("t %1.1f %1.1f", {tape1.time, tape2.time})
--track('fps %2.1f', love.timer.getFPS())
end

Expand All @@ -94,8 +87,7 @@ function loadPatch(newPatch)
time = 0 -- back to big bang
efx.load() -- restore efx to defaults
patch = newPatch.load()
tape1:patchChanged(newPatch)
tape2:patchChanged(newPatch)
recorder.patchChanged(newPatch)
end


Expand Down
126 changes: 86 additions & 40 deletions tape.lua → recorder.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local recorder = {}
local tape = {}
tape.__index = tape

Expand All @@ -8,60 +9,101 @@ local colorScheme = {
background = {l.hsl(0, 0, 0.1)},
grooves = {l.hsl(0, 0, 0.15)},
head = {l.hsl(0, 0.3, 0.5)},
spindle = {l.hsl(0, 0, 0.6)},
spindle = {l.hsl(0, 0.1, 0.3)},
note = {l.hsl(0, 0.6, 0.4)},
}

-- global for all tapes
recorder.speed = 1
recorder.time = 0
recorder.tapes = {}
recorder.loadedPatch = nil

--[[
TODO:
per-tape volume: low mid high
changing tempo
syncing between length multiples (4 bars against 1 bar)
track icon pressing doesn't play note
adding echo track with dotted eighth delay
adjustable track icon position (on main screen)
saving and loading to storage
more than 2 tracks, adding and removing
]]

function tape.create()
function recorder.addTape()
local self = setmetatable({}, tape)
self.position = {-1.5, -0.85}
self.recording = false
self.notes = {}
self.touchId = nil
self.patch = nil
self.patch = nil -- a copy of patch is instantiated just for tape playback
self.time = 0
self.timePrev = 0
self.length = math.huge -- huge!
self.lastPlayed = -1
self.recordingStop = false
self.canvas = love.graphics.newCanvas(200, 200)
self:drawVinyl()
table.insert(recorder.tapes, self)
return self
end

function recorder.patchChanged(patch)
recorder.loadedPatch = patch.load()
end

function recorder.interpret(s, inSelector)
for i,tape in ipairs(recorder.tapes) do
tape:interpret(s, inSelector)
end
end


function tape:startStop(s)
-- record start / stop
function recorder.process(s)
for i,tape in ipairs(recorder.tapes) do
tape:process(s)
end
end


function recorder.draw()
for i,tape in ipairs(recorder.tapes) do
tape:draw()
end
end


-- tape functions --


function tape:interpret(s, inSelector)
local cnt = 0
for id,touch in pairs(s.touches) do
cnt = cnt + 1
local x, y = love.graphics.inverseTransformPoint(touch[1], touch[2])
if (self.position[1] - x)^2 + (self.position[2] - y)^2 < 0.03 then
-- on new touch toggle recording
if id ~= self.touchId then
if not self.recording then
self.patch = self.loadedPatch
self.recording = true
self.time = 0
self.notes = {}
if (x - self.position[1])^2 + (y - self.position[2])^2 < 0.03 then
if inSelector then
if y - self.position[2] > 0 then
recorder.speed = recorder.speed * 0.998
else
self.recording = false
self.recordingStop = true
self.length = self.time
self.masterVolume = 0.5
recorder.speed = recorder.speed * 1.002
end
else -- on new touch toggle recording
if id ~= self.touchId then
if not self.recording then
self.patch = recorder.loadedPatch
self.recording = true
self.time = 0
self.notes = {}
else
self.recording = false
self.recordingStop = true
self.length = self.time
self.masterVolume = 0.5
end
self.touchId = id -- mark id to distinguish new touch from held touch
end
self.touchId = id -- mark id to know if it is held touch of new touch
end
s.touches[id] = nil -- sneakily remove touch from stream to prevent unintended notes
end
end
if cnt == 0 then
Expand All @@ -70,12 +112,10 @@ function tape:startStop(s)
end


function tape:process(s, patch)
self:startStop(s)
function tape:process(s)
-- tape recording
if self.recording then
table.insert(self.notes, {self.time, s})
self.time = self.time + s.dt
end
-- tape playback
if not self.recording and #self.notes > 0 and self.patch then
Expand All @@ -85,17 +125,17 @@ function tape:process(s, patch)
self.patch.sampler:processTouches(s.dt, stream.touches)
end
end
self.timePrev = self.time
-- loop tape back to start
if self.time > self.length then
self.time = 0
self.timePrev = -s.dt
end
self.timePrev = self.time
self.time = self.time + s.dt
end
self.time = self.time + s.dt * recorder.speed
end


function tape:drawNotes()
function tape:drawVinyl()
love.graphics.origin()
love.graphics.setCanvas(self.canvas)
love.graphics.clear()
Expand All @@ -109,10 +149,24 @@ function tape:drawNotes()
love.graphics.setLineWidth(0.04)
love.graphics.circle('line', 0, 0, l.remap(i, 1, grooveCount, 0.4, 0.85))
end
-- notes
-- start marker
love.graphics.setColor(colorScheme.head)
love.graphics.setLineWidth(0.06)
love.graphics.line(0.7, 0, 0.9, 0)
-- center spindle
love.graphics.setColor(colorScheme.spindle)
love.graphics.circle("fill", 0, 0, 0.25)
love.graphics.setCanvas()
end

function tape:drawNotes()
love.graphics.origin()
love.graphics.setCanvas(self.canvas)
love.graphics.setBlendMode("alpha")
love.graphics.translate(100,100)
love.graphics.scale(100)
love.graphics.setColor(colorScheme.note)
love.graphics.setLineWidth(0.08)
love.graphics.line(0.5, 0, 0.7, 0)
-- notes
for i, rec in ipairs(self.notes) do
noteTime, stream = unpack(rec)
for id, touch in pairs(stream.touches) do
Expand All @@ -126,10 +180,6 @@ function tape:drawNotes()
end
end
end
-- center spindle
love.graphics.setColor(colorScheme.spindle)
love.graphics.circle("fill", 0, 0, 0.03)

love.graphics.setCanvas()
end

Expand All @@ -138,6 +188,7 @@ function tape:draw()
-- when recording stops, map recorded notes onto circle
if self.recordingStop then
love.graphics.push()
self:drawVinyl()
self:drawNotes()
self.recordingStop = false
love.graphics.pop()
Expand Down Expand Up @@ -171,9 +222,4 @@ function tape:draw()
end


function tape:patchChanged(patch)
self.loadedPatch = patch.load()
end


return tape
return recorder

0 comments on commit 3f3d71d

Please sign in to comment.