smallpond

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/smallpond
Log | Files | Refs

commit 25104c0f73448eb83495f3b8539ad6fecc2153d7
parent b46e8c54bb5df04ee1fefaeac1a803b7392ed948
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Mon, 26 Sep 2022 11:28:00 -0500

add new step in pipeline to enable beam drawing

Diffstat:
Mmain.c | 25+++++++++++++++++++++++++
Msmallpond.lua | 75++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 89 insertions(+), 11 deletions(-)

diff --git a/main.c b/main.c @@ -35,6 +35,29 @@ draw_line(lua_State *L) } int +draw_quad(lua_State *L) +{ + double x1 = lua_tonumber(L, -8); + double y1 = lua_tonumber(L, -7); + double x2 = lua_tonumber(L, -6); + double y2 = lua_tonumber(L, -5); + double x3 = lua_tonumber(L, -4); + double y3 = lua_tonumber(L, -3); + double x4 = lua_tonumber(L, -2); + double y4 = lua_tonumber(L, -1); + + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + + cairo_move_to(cr, x1, y1); + cairo_line_to(cr, x2, y2); + cairo_line_to(cr, x3, y3); + cairo_line_to(cr, x4, y4); + cairo_fill(cr); + + return 0; +} + +int draw_glyph(lua_State *L) { unsigned int val = lua_tonumber(L, -3); @@ -77,6 +100,8 @@ main(int argc, char *argv[]) lua_setglobal(L, "draw_glyph"); lua_pushcfunction(L, draw_line); lua_setglobal(L, "draw_line"); + lua_pushcfunction(L, draw_quad); + lua_setglobal(L, "draw_quad"); lua_pushcfunction(L, glyph_extents); lua_setglobal(L, "glyph_extents"); FT_Library library; diff --git a/smallpond.lua b/smallpond.lua @@ -131,25 +131,34 @@ f = assert(io.open("score.sp")) local time = 0 -- time in increments of denom local octave = 0 local clef = Clef.treble --- abstract placement -staff = {} +local lastnote = nil +-- first-order placement +first_order = {} abstract_dispatch = { newnote = function(data) local i = clef.place(data.note, octave) - table.insert(staff, {kind="note", acc=data.acc, stemdir=data.stemdir, length=data.count, time=time, sy=i}) + local beamed = false + if data.count == 8 and (time % .25 == 0 or lastnote.beamed) then + beamed = true + -- TODO: should we be emitting a beam here? + end + local note = {kind="note", acc=data.acc, beamed=beamed, stemdir=data.stemdir, stemlen=3.5, length=data.count, time=time, sy=i} + table.insert(first_order, note) + lastnote = note time = time + 1 / data.count end, changeclef = function(data) local class = assert(Clef[data.kind]) - table.insert(staff, {kind="clef", class=class}) + table.insert(first_order, {kind="clef", class=class}) clef = class octave = class.defoctave end, changetime = function(data) - table.insert(staff, {kind="time", num=data.num, denom=data.denom}) + table.insert(first_order, {kind="time", num=data.num, denom=data.denom}) end, barline = function(data) - table.insert(staff, {kind="barline"}) + table.insert(first_order, {kind="barline"}) + lastnote = nil end, changeoctave = function(data) octave = octave + data.count @@ -157,8 +166,44 @@ abstract_dispatch = { } for tok in parse(f:read("*a")) do - local func = assert(abstract_dispatch[tok.command]) - func(tok) + assert(abstract_dispatch[tok.command])(tok) +end + +-- second-order placement +local staff = {} +local tobeam = {} + +for i, el in ipairs(first_order) do + if el.kind == 'note' and el.beamed then + tobeam[#tobeam + 1] = el + else + if #tobeam > 1 then + -- check which way the stem should point on all the notes in the beam + local ysum = 0 + for _, note in ipairs(tobeam) do + ysum = ysum + note.sy + end + + local stemdir + if ysum >= 0 then + stemdir = -1 + else + stemdir = 1 + end + + -- update the stem direction + for _, note in ipairs(tobeam) do + note.stemdir = stemdir + table.insert(staff, note) + end + table.insert(staff, {kind='beam', first=tobeam[1], last=tobeam[#tobeam]}) + elseif #tobeam == 1 then + tobeam[1].beamed = false + table.insert(staff, tobeam[1]) + end + tobeam = {} + table.insert(staff, el) + end end drawables = {} @@ -222,13 +267,17 @@ for i, el in ipairs(staff) do if el.stemdir then if el.stemdir == -1 then -- stem up - table.insert(drawables, {kind="line", t=1, x1=w + rx - .5, y1=ry - .168*em, x2=w + rx - .5, y2=ry -.168*em - 3.5*em}) + el.stemx = w + rx - .5 + el.stemy = ry -.168*em - el.stemlen*em + table.insert(drawables, {kind="line", t=1, x1=w + rx - .5, y1=ry - .168*em, x2=w + rx - .5, y2=ry -.168*em - el.stemlen*em}) else - table.insert(drawables, {kind="line", t=1, x1=rx + 0.5, y1=ry + .168*em, x2=rx + 0.5, y2=ry + 3.5*em}) + el.stemx = rx - .5 + el.stemy = ry + el.stemlen*em + table.insert(drawables, {kind="line", t=1, x1=rx + 0.5, y1=ry + .168*em, x2=rx + 0.5, y2=ry + el.stemlen*em}) end end - if el.length == 8 then + if el.length == 8 and not el.beamed then if el.stemdir == 1 then table.insert(drawables, {kind="glyph", glyph=Glyph["flag8thDown"], x=rx, y=ry + 3.5*em}) else @@ -240,6 +289,8 @@ for i, el in ipairs(staff) do end x = x + 100 / el.length + 10 lasttime = el.time + elseif el.kind == "beam" then + table.insert(drawables, {kind="quad", x1=el.first.stemx - 0.5, y1=el.first.stemy, x2=el.last.stemx, y2=el.last.stemy, x4=el.first.stemx - 0.5, y4=el.first.stemy + 5, x3=el.last.stemx, y3=el.last.stemy + 5}) elseif el.kind == "barline" then x = x + 20 table.insert(drawables, {kind="line", t=1, x1=x + xoffset, y1=yoffset, x2=x + xoffset, y2 = yoffset + 4*em}) @@ -260,6 +311,8 @@ for i, d in ipairs(drawables) do draw_glyph(d.glyph, d.x, d.y) elseif d.kind == "line" then draw_line(d.t, d.x1, d.y1, d.x2, d.y2) + elseif d.kind == "quad" then + draw_quad(d.t, d.x1, d.y1, d.x2, d.y2, d.x3, d.y3, d.x4, d.y4) end end