Karasuro 0 Posted January 25, 2015 Share Posted January 25, 2015 (edited) Hello! Karasuro here. I just downloaded OpenComputers recently and have been testing things out. Here is my first program I've written in OC and it needs lots of improvement and optimization but at least it works. Note:You may need a high-end computer for this to work. I made it using Teir 3 everything. (Creative Mode)Also you will need to hook up a note block. Now checks the resolution of the system before changing it's local resolution. Returns to the previous resolution upon exit. To-Do: Add variable tempo. Switch to Computer.beep() for extra pitch support. Add variable scales. Code: Optimized to mpmxyz's recommendations. --[[OpenMatrix v0.7.1 by Karasuro]]-- -- Requirements local computer = require "computer"; local component = require "component"; local term = require "term"; local event = require "event"; local gpu = component.gpu; local source = component.note_block; local note = require "note"; local keyboard = require "keyboard"; local color = require "colors"; -- Variables and Tables term.clear(); local maxX, maxY = gpu.getResolution(); if (maxX ~= 80) then if (maxY ~= 25) then gpu.setResolution(80, 25); end end local w, h = gpu.getResolution(); local UI = {bg=0x000000, fg=0xFFFFFF, txt=0x000000, width=w, height=h}; local UI_btn = {on=0xFFFFFF, off=0xFFAA00, play=0xFFFF55}; local UI_menu = {default=0xFFAA00, hit=0xFFFF55}; local buttons = {}; for Y = 2,16 do local row = {}; table.insert(buttons, row); for X = 2,47,3 do if (Y == 2) then table.insert(row, {state=3, posX=X, posY=Y, pitch=25}); elseif (Y == 3) then table.insert(row, {state=3, posX=X, posY=Y, pitch=24}); elseif (Y == 4) then table.insert(row, {state=3, posX=X, posY=Y, pitch=22}); elseif (Y == 5) then table.insert(row, {state=3, posX=X, posY=Y, pitch=20}); elseif (Y == 6) then table.insert(row, {state=3, posX=X, posY=Y, pitch=18}); elseif (Y == 7) then table.insert(row, {state=3, posX=X, posY=Y, pitch=17}); elseif (Y == 8) then table.insert(row, {state=3, posX=X, posY=Y, pitch=15}); elseif (Y == 9) then table.insert(row, {state=3, posX=X, posY=Y, pitch=13}); elseif (Y == 10) then table.insert(row, {state=3, posX=X, posY=Y, pitch=12}); elseif (Y == 11) then table.insert(row, {state=3, posX=X, posY=Y, pitch=10}); elseif (Y == 12) then table.insert(row, {state=3, posX=X, posY=Y, pitch=8}); elseif (Y == 13) then table.insert(row, {state=3, posX=X, posY=Y, pitch=6}); elseif (Y == 14) then table.insert(row, {state=3, posX=X, posY=Y, pitch=5}); elseif (Y == 15) then table.insert(row, {state=3, posX=X, posY=Y, pitch=3}); else table.insert(row, {state=3, posX=X, posY=Y, pitch=1}) end end end local printDebug = false; local mX = 0; local mY = 0; local pitch = 1; local playing = false; local tick = 0; local beat = 16; local tempo = 40; local cycle = 0; local dt = 0; local menu = { {id="play", posX=2, posY=(h - 1), state=1, label="Play", width=6, height=1} }; local header = {posX=47,posY=18,width=2,height=1,col=0x00AA00}; local myEventHandlers = setmetatable({}, {__index = function() return unknownEvent end}); -- Functions function unknownEvent() -- Do Nothing! end function myEventHandlers.key_up(adress, char, code, playerName) -- Space Bar if (code == 0x39) then playing = not playing; end -- Backspace if (code == 0x0E) then gpu.setResolution(maxX, maxY); term.clear(); os.exit(); end -- Grave or ~ if (code == 0x29) then printDebug = not printDebug; end end function myEventHandlers.touch(screenAdress, x, y, button, playerName) mX = x; mY = y; if (button == 0) then -- Buttons Table Handling for r in pairs(buttons) do for c in pairs(buttons[r]) do if (mX >= buttons[r][c].posX) and (mX <= (buttons[r][c].posX + 2)) and (mY == buttons[r][c].posY) then if (buttons[r][c].state == 3) then buttons[r][c].state = 1; else buttons[r][c].state = 3; end end end end -- Menu Table Handling for i in pairs(menu) do if (mX >= menu[i].posX) and (mX <= (menu[i].posX + menu[i].width)) and (mY == menu[i].posY) then --play/stop button if menu[i].id == "play" then playing = not playing; menu[i].label = "Stop"; end end end end end function handleEvent(eventID, ...) if (eventID) then myEventHandlers[eventID](...); end end function playTone(pitch) if (source ~= nil) then source.trigger(pitch); else computer.beep(pitch); end end --Draw Instructions ONCE gpu.setBackground(UI.bg); --Black gpu.setForeground(UI.fg); --White gpu.set(2,20,"~ = debug info | space = play/stop | backspace = exit"); gpu.set(2,21,"Multiple notes on each column = more processing time.") -- Main Loop while true do --[[UPDATE DATA]]-- if playing then -- Update UI menu[1].label = "Stop"; -- Start ticking tick = tick + (tempo * 0.1); if tick > 1 then header.posX = header.posX + 3; if header.posX > 47 then header.posX = 2; end tick = 0; beat = beat + 1; end if (beat > 16) then beat = 1; end -- Get Active Notes for r in pairs(buttons) do for c in pairs(buttons[r]) do if (buttons[r][c].posX == header.posX) then if (buttons[r][c].state == 1) then buttons[r][c].state = 2; pitch = buttons[r][c].pitch; playTone(pitch); end else if (buttons[r][c].state == 2) then buttons[r][c].state = 1; end end end end else -- Reset UI header.posX = 47; tick = 0; beat = 16; menu[1].label = "Play"; for r in pairs(buttons) do for c in pairs(buttons[r]) do if (buttons[r][c].state == 2) or (buttons[r][c].state == 1) then buttons[r][c].state = 1; else buttons[r][c].state = 3; end end end end --[[DRAW STUFF]]-- -- Draw Buttons and their states for r in pairs(buttons) do for c in pairs(buttons[r]) do if (buttons[r][c].state == 3) then --Draw Button OFF gpu.setBackground(UI_btn.off); --Orange gpu.fill(buttons[r][c].posX,buttons[r][c].posY,2,1," "); gpu.setBackground(UI.bg); --Black end if (buttons[r][c].state == 2) then -- Draw Buttons ON gpu.setBackground(UI_btn.on); --White gpu.fill(buttons[r][c].posX,buttons[r][c].posY,2,1," "); gpu.setBackground(UI.bg); --Black end if (buttons[r][c].state == 1) then -- Draw Buttons PLAY gpu.setBackground(UI_btn.play); --Yellow gpu.fill(buttons[r][c].posX,buttons[r][c].posY,2,1," "); gpu.setBackground(UI.bg); --Black end end end -- Draw Play Head gpu.setBackground(header.col); --Green gpu.fill(header.posX,header.posY,2,1," "); gpu.setBackground(UI.bg); --Black if (header.posX ~= 2) then gpu.fill((header.posX - 3),header.posY,2,1," "); end if (header.posX == 2) then gpu.fill(47,18,2,1," "); end if (header.posX == 47) then gpu.fill(2,header.posY,45,1," "); end --Draw Menu for i in pairs(menu) do if (menu[i].state == 1) then gpu.setBackground(UI_menu.default) --Orange gpu.fill(menu[i].posX,menu[i].posY,menu[i].width,menu[i].height," "); gpu.setForeground(UI.txt); --Black gpu.set(menu[i].posX,menu[i].posY,menu[i].label); gpu.setBackground(UI.bg); --Black gpu.setForeground(UI.fg); --White end if (menu[i].state == 2) then gpu.setBackground(UI_menu.hit); --Yellow gpu.fill(menu[i].posX,menu[i].posY,menu[i].width,menu[i].height," "); gpu.setForeground(UI.txt); --Black gpu.set(menu[i].posX,menu[i].posY,menu[i].label); gpu.setBackground(UI.bg); --Black gpu.setForeground(UI.fg); --White end end -- print debug information if (printDebug) then gpu.fill(50,2,80,5," "); gpu.setBackground(UI.bg) --Black gpu.setForeground(UI.fg) --White gpu.set(50,2,tostring(mX)..", "..tostring(mY)); gpu.set(50,3,"playing: "..tostring(playing)); gpu.set(50,4,"beat: "..tostring(beat)); gpu.set(50,5,"pitch: "..tostring(pitch)); else gpu.fill(50,2,80,5," "); end handleEvent(event.pull(0.001)); end Edited March 18, 2015 by SpiritedDusty Put code in spoiler Quote Link to post Share on other sites
mpmxyz 27 Posted January 25, 2015 Share Posted January 25, 2015 I had some fun playing around with this. Here some hints for improvement: Did you know you could rewrite the following line {["state"]=3, ["posX"]=2, ["posY"]=2, ["pitch"]=25}, to {state=3, posX=2, posY=2, pitch=25}, ? It does exactly the same and isn't cluttered with brackets and quotes. And you should definitely try two for loops to create your buttons: --iterate through posY = 2,3,4 ... 16 for posY = 2,16 do local row = {} --add table row to the list buttons table.insert(buttons, row) --iterate through posX = 2,5,8 ... 44 (notice how the third parameter = 3 defines how much posX is changing) for posX = 2,44,3 do --create a table for the button and add it to the row table.insert(row, {state=3, posX=posX, posY=posY, pitch=25}) end end (That saves ~250 lines of code and makes it easier to move the buttons! :-)) If you have a question about this code: Feel free to ask! Quote Link to post Share on other sites
Karasuro 0 Posted January 25, 2015 Author Share Posted January 25, 2015 Yeah, I don't know why I went in and added the [""] to the tables. I guess I wasn't really thinking at the time. XP Brain process was string instead of variable. Also, I was looking for a better way to make the buttons array. That helps me out a lot! However, I'll need to figure out an algorith for pitch.. the scale is F# Major (F#3 - F#5) This may also allow me to implement a setScale() function and instead of using note blocks just use computer.beep(). Larger range and note durration support. ;P The original design had speed variation hence the tempo and dt variables. Also I need to figure out if doing multiple note.trigger() at once is possible.. This project is a port from my Love2D application AudynMatrix. https://dl.dropboxusercontent.com/u/16913227/AudynMatrix.zip Quote Link to post Share on other sites
kreezxil 1 Posted June 19, 2016 Share Posted June 19, 2016 I like this program. I put it on pastebin since copy and paste to edit will cause it to truncate. pastebin get d4Hhg5PR openMatrix Make sure you have an adapter block with a note_block attached to it connected to the computer and the run "openMatrix" Quote Link to post Share on other sites