diff --git a/app/main.lua b/app/main.lua index 6fe0bfd..d6df9e6 100644 --- a/app/main.lua +++ b/app/main.lua @@ -140,7 +140,7 @@ window:setRootViewController(VIEWCONTROLLER(function(m) local super = nav.cell.mnew function nav.cell.mnew(_) local m = super(_) - m:textLabel():setFont(objc.UIFont:fontWithName_size('HelveticaNeue-Bold', 22)) + m:textLabel():setFont(objc.UIFont:fontWithName_size('HelveticaNeue-Light', 18)) return m end local selected_view = objc.UIView:alloc():initWithFrame{{0, 0},{2, 44}} @@ -149,10 +149,6 @@ window:setRootViewController(VIEWCONTROLLER(function(m) local item = nav.items[section][row] m:textLabel():setText(item.title) m:imageView():setImage(item.icon) - if item.icon then - local siz = 22 - m:imageView():setTransform(C.CGAffineTransformMakeScale(siz/item.icon:size().width, siz/item.icon:size().height)) - end if item.view == active then m:addSubview(selected_view) end @@ -241,4 +237,5 @@ CHECK_UPDATE(function(json, err) end) end) -require 'autorun_loader'('app') +require 'page.crossfeed' +require 'page.compressor' diff --git a/app/page/compressor.lua b/app/page/compressor.lua new file mode 100644 index 0000000..052a4e7 --- /dev/null +++ b/app/page/compressor.lua @@ -0,0 +1,93 @@ +-- put this into /var/tweak/com.r333d.eqe/lua/autorun/app/ +-- load by restarting the EQE app + +local str_esc = require 'str_esc' +local md = require 'md' + +local page = {} +page.title = 'Compressor (beta)' +page.icon = IMG('radio-waves.png', PAGE_ICON_COLOR):retain() + +local function ipc(s, safe) + s = str_esc(s) + if safe then + return IPC('return eqe.raw('..s..')') + else + return IPC('return eqe.raw('..s..', true)') + end +end + +local pad = 11 +local function create_switch(y, canvaswidth, title, m) + local target = ns.target:new() + target.switch = objc.UISwitch:alloc():init() + local s = target.switch:frame().size + local x = canvaswidth - s.width - pad*3 + target.switch:setFrame{{x, y},s} + target.switch:setOnTintColor(COLOR(0x4bc2ffaa)) + target.switch:setTintColor(COLOR(0xffffff55)) + target.switch:addTarget_action_forControlEvents(target.m, target.sel, UIControlEventValueChanged) + + target.label = objc.UILabel:alloc():init() + target.label:setFont(objc.UIFont:fontWithName_size('HelveticaNeue', 16)) + target.label:setTextColor(COLOR(0xffffff8d)) + target.label:setBackgroundColor(objc.UIColor:clearColor()) + target.label:setText(title) + target.label:sizeToFit() + local switchS = s + local s = target.label:frame().size + target.label:setFrame{{x - s.width - pad, y + (switchS.height - s.height)/2},s} + + m:view():addSubview(target.label) + m:view():addSubview(target.switch) + return target, y + target.switch:frame().size.height +end + +function page:init() + local vc = VIEWCONTROLLER(function(m) + local frame = m:view():frame() + local width = frame.size.width + + local y = 64 + + local enable, y = create_switch(y, width, 'Enabled', m) + function enable.onaction() + local on = objc.weirdbool(enable.switch:isOn()) + ipc('compressor.enabled('..tostring(on)..')') + ipc('compressor.save()') + end + self.enable = enable + + local r = md.new(width - pad*2) + self.helper_text = r.m + self.helper_text:setFrame{{pad, y + pad},{0,0}} + m:view():addSubview(self.helper_text) + r:init[[ +This basically makes your audio more "level" and "loud". Good for listening to podcasts and that kinda stuff. [Wikipedia article](https://en.wikipedia.org/wiki/Dynamic_range_compression) + +This is a super basic version of a compressor, it's literally just an enable switch with some super basic presets. There should be more options here but I don't know how compressors work. + +If you know how to use a compressor, hop on the [Discord chat](https://discord.gg/RSJWAuX). I can show you the under-the-hood settings in Terminal. + +This code is open source. +]] + + end) + self.view = vc:view() +end + +function page:refresh() + local enabled = ipc('return compressor.enabled()') == 'true' + + self.enable.switch:setOn(enabled) +end + +function page:hide(hiding) + if not hiding then + self:refresh() + end + +end + +Page.compressor = page +ADD_NAV_PAGE(page, Page.eqe) diff --git a/app/page/crossfeed.lua b/app/page/crossfeed.lua new file mode 100644 index 0000000..296325d --- /dev/null +++ b/app/page/crossfeed.lua @@ -0,0 +1,199 @@ +-- put this into /var/tweak/com.r333d.eqe/lua/autorun/app/ +-- load by restarting the EQE app + +local str_esc = require 'str_esc' +local md = require 'md' + +local page = {} +page.title = 'Crossfeed (beta)' +page.icon = IMG('headphone.png', PAGE_ICON_COLOR):retain() + +local function ipc(s, safe) + s = str_esc(s) + if safe then + return IPC('return eqe.raw('..s..')') + else + return IPC('return eqe.raw('..s..', true)') + end +end + +local thumbImg = IMG('thumb.png'):retain() + +local pad = 11 +local function create_slider(y, width, title, m) + local self = {} + self.onchange = function() end + self.onfinish = function() end + + self.label = objc.UILabel:alloc():initWithFrame{{pad,y},{width - pad*2,44}} + self.label:setFont(objc.UIFont:fontWithName_size('HelveticaNeue', 16)) + self.label:setTextColor(COLOR(0xffffff8d)) + self.label:setBackgroundColor(objc.UIColor:clearColor()) + self.label:setText(title) + + y = y + self.label:frame().size.height + + self.slider = objc.EQEOBSlider:alloc():initWithFrame{{pad,y},{width - pad*2,44}} + self.slider:setThumbImage_forState(thumbImg, UIControlStateNormal) + self.slider:setMinimumTrackTintColor(COLOR(0xffffff80)) + self.slider:setMaximumTrackTintColor(COLOR(0xffffff50)) + + local target = ns.target:new() + function target.onaction() + self.onfinish() + end + self.slider:addTarget_action_forControlEvents(target.m, target.sel, bit.bor(UIControlEventTouchUpInside, UIControlEventTouchUpOutside)) + + local target = ns.target:new() + function target.onaction() + self.onchange() + end + self.slider:addTarget_action_forControlEvents(target.m, target.sel, bit.bor(UIControlEventValueChanged)) + + local target = ns.target:new() + self.slider:addTarget_action_forControlEvents(target.m, target.sel, UIControlEventValueChanged) + function self.updatetext() + self.label:setText(title..': '..self.slider:value()) + end + function target.onaction() + self.updatetext() + end + + y = y + self.slider:frame().size.height + + m:view():addSubview(self.slider) + m:view():addSubview(self.label) + + return self, y +end + +local function create_button(x, y, canvaswidth, title, m) + local height = 34 + local width = canvaswidth*2/3 + local button = ui.button:new() + button.m:setFrame{{x + (canvaswidth-width)/2, y},{width,height}} + button.m:layer():setCornerRadius(8) + button:setFont('HelveticaNeue', 16) + button:setColor(COLOR(0xff, 0xff, 0xff, 0xff*0.7)) + button.m:setBackgroundColor(COLOR(0xff, 0xff, 0xff, 0xff*0.07)) + button:setTitle(title) + m:view():addSubview(button.m) + return button, y + height +end + +local function create_switch(y, canvaswidth, title, m) + local target = ns.target:new() + target.switch = objc.UISwitch:alloc():init() + local s = target.switch:frame().size + local x = canvaswidth - s.width - pad*3 + target.switch:setFrame{{x, y},s} + target.switch:setOnTintColor(COLOR(0x4bc2ffaa)) + target.switch:setTintColor(COLOR(0xffffff55)) + target.switch:addTarget_action_forControlEvents(target.m, target.sel, UIControlEventValueChanged) + + target.label = objc.UILabel:alloc():init() + target.label:setFont(objc.UIFont:fontWithName_size('HelveticaNeue', 16)) + target.label:setTextColor(COLOR(0xffffff8d)) + target.label:setBackgroundColor(objc.UIColor:clearColor()) + target.label:setText(title) + target.label:sizeToFit() + local switchS = s + local s = target.label:frame().size + target.label:setFrame{{x - s.width - pad, y + (switchS.height - s.height)/2},s} + + m:view():addSubview(target.label) + m:view():addSubview(target.switch) + return target, y + target.switch:frame().size.height +end + +function page:init() + local vc = VIEWCONTROLLER(function(m) + local frame = m:view():frame() + local width = frame.size.width + + local intensity, y = create_slider(64, width, 'Intensity', m) + intensity.slider:setMinimumValue(0) + intensity.slider:setMaximumValue(1) + function intensity.onchange() + ipc('crossfeed.intensity('..intensity.slider:value()..')') + end + function intensity.onfinish() + intensity.onchange() + ipc('crossfeed.save()') + end + self.intensity = intensity + + local delay, y = create_slider(y, width, 'Delay (ms)', m) + delay.slider:setMinimumValue(0) + delay.slider:setMaximumValue(4) + function delay.onchange() + ipc('crossfeed.delay('..delay.slider:value()..')') + end + function delay.onfinish() + delay.onchange() + ipc('crossfeed.save()') + end + self.delay = delay + + --[[ + y = y + pad*2 + + self.save = create_button(0, y, width/2, 'Save', m) + local load, y = create_button(width/2, y, width/2, 'Load', m) + self.load = load + + function self.save.ontoggle() + ipc('crossfeed.save()') + end + + function self.load.ontoggle() + ipc('crossfeed.load()') + self:refresh() + end + ]] + + y = y + pad*2 + + local enable, y = create_switch(y, width, 'Enabled', m) + function enable.onaction() + local on = objc.weirdbool(enable.switch:isOn()) + ipc('crossfeed.enabled('..tostring(on)..')', true) + end + self.enable = enable + + local r = md.new(width - pad*2) + self.helper_text = r.m + self.helper_text:setFrame{{pad, y + pad},{0,0}} + m:view():addSubview(self.helper_text) + r:init[[ +If you have no clue what this does, [here's a pretty good explanation](http://www.meier-audio.homepage.t-online.de/crossfeed.htm). + +Basically, you should use this if you're using headphones, it makes it sound more "full" and "open", like speakers. + +Credits to xC0nfused on [Discord](https://discord.gg/RSJWAuX) for helping make this. This code is open source.]] + + end) + self.view = vc:view() +end + +function page:refresh() + local intensity = tonumber(ipc('return crossfeed.intensity()')) + local delay = tonumber(ipc('return crossfeed.delay()')) + local enabled = ipc('return crossfeed.enabled()') == 'true' + + self.intensity.slider:setValue(intensity) + self.intensity.updatetext() + self.delay.slider:setValue(delay) + self.delay.updatetext() + self.enable.switch:setOn(enabled) +end + +function page:hide(hiding) + if not hiding then + self:refresh() + end + +end + +Page.crossfeed = page +ADD_NAV_PAGE(page, Page.eqe) diff --git a/app/page/history/init.lua b/app/page/history/init.lua index cbf38b1..f154d25 100644 --- a/app/page/history/init.lua +++ b/app/page/history/init.lua @@ -67,9 +67,9 @@ function page:init() function tbl.cell.onshow(_, m, section, row) local item = items[row] m:textLabel():setText(item.title) - local scale = 22 + local scale = 32 scale = scale/math.max(item.icon:size().width, item.icon:size().height) - m:imageView():setTransform(C.CGAffineTransformMakeScale(scale, scale)) + m:setImageViewSize{scale*item.icon:size().width, scale*item.icon:size().height} m:imageView():setImage(item.icon) end function tbl.cell.onselect(_, section, row) diff --git a/app/page/history/top/init.lua b/app/page/history/top/init.lua index 00f88dc..a7d154d 100644 --- a/app/page/history/top/init.lua +++ b/app/page/history/top/init.lua @@ -43,7 +43,7 @@ return function(query, render) if icon then local scale = 22 scale = scale/math.max(icon:size().width, icon:size().height) - m:imageView():setTransform(C.CGAffineTransformMakeScale(scale, scale)) + m:setImageViewSize{scale*icon:size().width, scale*icon:size().height} end end diff --git a/app/page/history/whitelist.lua b/app/page/history/whitelist.lua index 1c80a72..61350c9 100644 --- a/app/page/history/whitelist.lua +++ b/app/page/history/whitelist.lua @@ -81,9 +81,9 @@ return function(m) m:accessoryView():setOn(app.enabled == 1 and true or false) if icon then - local scale = 22 + local scale = 32 scale = scale/math.max(icon:size().width, icon:size().height) - m:imageView():setTransform(C.CGAffineTransformMakeScale(scale, scale)) + m:setImageViewSize{scale*icon:size().width, scale*icon:size().height} end end end diff --git a/app/page/settings.lua b/app/page/settings.lua index 3c5eadf..eeff0ff 100644 --- a/app/page/settings.lua +++ b/app/page/settings.lua @@ -24,7 +24,7 @@ function page:init() local items = { { title = 'Enable mediaserverd hook', - subtitle = 'When disabled, audio will not be processed. Basically the equivalent of disabling in iCleaner.', + subtitle = 'Handles processing of all audio.', cb = function(enabled) if enabled == nil then return IPC('return GET_ENABLED()') == 'true' diff --git a/app/page/update.lua b/app/page/update.lua index 6893413..3ec3dd1 100644 --- a/app/page/update.lua +++ b/app/page/update.lua @@ -110,12 +110,7 @@ function page:init() end local cydia_notice_text = "If you want, you can just update through Cydia. Both methods are compatible with each other." - local version_info_text - if string.find(EQE_TWEAK_VERSION, '%~beta') then - version_info_text = 'Current version: '..EQE_TWEAK_VERSION..'\ngit commit: '..string.sub(require 'config.default.git_commit', 1, 6)..'\n\nIf you are reporting an issue, please specify the git commit as well.' - else - version_info_text = 'Current version: '..EQE_TWEAK_VERSION - end + local version_info_text = 'Current version: '..EQE_TWEAK_VERSION local cydia_notice = objc.UILabel:alloc():init() cydia_notice:setColor(COLOR(0xffffff5d)) diff --git a/app/ui/cell.lua b/app/ui/cell.lua index 8c9fa38..3e94fea 100644 --- a/app/ui/cell.lua +++ b/app/ui/cell.lua @@ -33,6 +33,7 @@ function ui.cell:mnew() self.m = m objc.ref(m, self) + m:setImageViewSize{32, 32} m:textLabel():setTextColor(objc.UIColor:whiteColor()) m:textLabel():setBackgroundColor(objc.UIColor:clearColor()) m:detailTextLabel():setTextColor(objc.UIColor:whiteColor()) @@ -49,7 +50,7 @@ end function ui.cell:dealloc() end -ui.cell.class = objc.GenerateClass('UITableViewCell') +ui.cell.class = objc.GenerateClass('EQEEditCell') local class = ui.cell.class function class.dealloc(m) diff --git a/app/util.lua b/app/util.lua index 539c15c..8771a4e 100644 --- a/app/util.lua +++ b/app/util.lua @@ -4,8 +4,6 @@ DIR *opendir(const char *); int closedir(DIR *dirp); ]] -ls = require 'ls' - _G.ANIMATE = function(arg1, arg2, arg3, arg4, arg5) local duration = 0.2 local delay = 0 diff --git a/common/autorun_loader.lua b/common/autorun_loader.lua index eaf6d85..b801a74 100644 --- a/common/autorun_loader.lua +++ b/common/autorun_loader.lua @@ -1,8 +1,7 @@ -local ls = require 'ls' local prefix = LUA_PATH..'/../autorun/' local function run(dir) - for k,v in pairs(ls(dir) or {}) do + for k,v in pairs(io.ls(dir) or {}) do v = dir..'/'..v if string.sub(v, #v - 3, #v) == '.lua' then dofile(v) diff --git a/common/ls.lua b/common/ls.lua index ba6fe6a..1f447b5 100644 --- a/common/ls.lua +++ b/common/ls.lua @@ -1,3 +1,9 @@ +if LUA_PATH == '/var/tweak/com.r333d.eqe/lua/core' then + -- TODO rewrite this to use the Lua C API + return function() return {} end +end + + local ffi = require 'ffi' local C = ffi.C diff --git a/core/eqe.lua b/core/eqe.lua index 8ec8418..91e2df2 100644 --- a/core/eqe.lua +++ b/core/eqe.lua @@ -39,7 +39,8 @@ _G.filters = setmetatable({}, { end, __newindex = function() error('read only') - end + end, + __len = FILTER_COUNT, }) function eqe:reset() diff --git a/core/init.lua b/core/init.lua index 281426b..1da482d 100644 --- a/core/init.lua +++ b/core/init.lua @@ -1,14 +1,9 @@ -if jit.arch == 'arm64' then - jit.off() -end - package.path = LUA_PATH..'/?.lua;'.. LUA_PATH..'/?/init.lua;'.. LUA_PATH..'/../common/?.lua;'.. LUA_PATH..'/../common/?/init.lua;'.. package.path -ffi = require 'ffi' -C = ffi.C + eqe = {} require 'util' require 'preset' diff --git a/core/preset.lua b/core/preset.lua index 74fe478..84f6100 100644 --- a/core/preset.lua +++ b/core/preset.lua @@ -5,7 +5,7 @@ function preset_file(name) end local function list(folder, ignore, should_return_table) - local t = ls(folder) + local t = io.ls(folder) local r = should_return_table and {} or '' for k,v in pairs(t) do if not(v == ignore) and string.sub(v, #v - 3, #v) == '.lua' then @@ -70,8 +70,11 @@ end function eqe.load(name, target) target = target or eqe local f = loadfile(preset_file(name)) - setfenv(f, {}) -- prevent "heres my preset" OSHIT PWNED situations - local t, attr = f() + local t, attr + do + local _ENV = {} -- prevent "heres my preset" OSHIT PWNED situations + t, attr = f() + end -- clear all bands if target == eqe then local to_insert = {} diff --git a/core/util.lua b/core/util.lua index 6bffd89..02579e8 100644 --- a/core/util.lua +++ b/core/util.lua @@ -1,5 +1,3 @@ -ls = require 'ls' - function getcoefs(presetname) local filters if presetname then diff --git a/raw/compressor.lua b/raw/compressor.lua new file mode 100644 index 0000000..08c2970 --- /dev/null +++ b/raw/compressor.lua @@ -0,0 +1,37 @@ +local prefspath = '/var/tweak/com.r333d.eqe/db/compressor.lua' + +local defaults = { + pregain = 0, + threshold = -24, + knee = 30, + ratio = 12, + attack = 0.003, + release = 0.25, + predelay = 0.006, + releasezone1 = 0.09, + releasezone2 = 0.16, + releasezone3 = 0.42, + releasezone4 = 0.98, + postgain = 0.98, + wet = 1, +} + +function compressor.save() + IPCD_WRITE(prefspath, { + enabled = compressor.enabled(), + comp = compressor.comp(), + }) +end + +function compressor.load() + local success, prefs = pcall(dofile, prefspath) + if not success then + compressor.save() + return compressor.load() + end + + compressor.enabled(prefs.enabled) + compressor.comp(prefs.comp or defaults) + + return t +end diff --git a/raw/crossfeed.lua b/raw/crossfeed.lua new file mode 100644 index 0000000..95f548e --- /dev/null +++ b/raw/crossfeed.lua @@ -0,0 +1,38 @@ +package.path = '/var/tweak/com.r333d.eqe/lua/core/?.lua;' + ..'/var/tweak/com.r333d.eqe/lua/core/?/init.lua;' + ..package.path + +local prefspath = '/var/tweak/com.r333d.eqe/db/crossfeed.lua' + +function crossfeed.save() + IPCD_WRITE(prefspath, { + enabled = crossfeed.enabled(), + delay = crossfeed.delay(), + intensity = crossfeed.intensity(), + }) +end + +function crossfeed.load() + local success, prefs = pcall(dofile, prefspath) + if not success then + crossfeed.save() + return crossfeed.load() + end + + crossfeed.enabled(prefs.enabled) + crossfeed.delay(prefs.delay) + crossfeed.intensity(prefs.intensity) + + return true +end + + +local f = require('filter.lowpass'):new() +f.Q = 0.048578 +f.frequency = 9604.148 + +crossfeed.coefs({{f:get_coefs(44100)}}) +crossfeed.enabled(false) +crossfeed.delay(0.3) +crossfeed.intensity(0.4) +crossfeed.load() diff --git a/raw/init.lua b/raw/init.lua index f702a64..521332a 100644 --- a/raw/init.lua +++ b/raw/init.lua @@ -1,78 +1,9 @@ -if jit.arch == 'arm64' then - jit.off() -end - package.path = LUA_PATH..'/?.lua;'.. LUA_PATH..'/?/init.lua;'.. LUA_PATH..'/../common/?.lua;'.. LUA_PATH..'/../common/?/init.lua;'.. package.path -local ffi = require 'ffi' -local C = ffi.C -ffi.cdef[[ -typedef void (*filter_function_t)(float **samples, int num_frames, int num_channels, float sampleRate); -size_t eqe_filter_set_raw_c_no_lock(filter_function_t f); -size_t eqe_filter_unset_raw_c_no_lock(size_t idx); -filter_function_t eqe_filter_get_raw_c(size_t idx); -]] - -_G.examples = require 'examples' -_G.raw = {} - -local luamap = {} -local cmap = {} - -local luastorage = {} -local cstorage = {} - -local function genclosure(map, setfunc, unsetfunc, storage) - local function closure(t, k, v) - if v == nil then - local idx = map[k] - if not idx then return end - - unsetfunc(idx) - map[k] = nil - storage[k] = nil - for k,v in pairs(map) do - -- the array was reallocated, shift everything > idx down by 1 - if v > idx then - map[k] = v - 1 - end - end - else - local chan0 = ffi.new('float[20]') - local chan1 = ffi.new('float[20]') - local audio = ffi.new('float *[2]', chan0, chan1) - if type(v) == 'function' then - v(audio, 20, 2, 44100, true) - else - v(audio, 20, 2, 44100) - end - - -- remove the old one if it exists - closure(t, k, nil) - - -- add it - local len = setfunc(v) - map[k] = len - 1 - storage[k] = v - end - end - return closure -end - -_G.raw.lua = setmetatable({}, { - __index = luastorage, - __newindex = genclosure(luamap, SET_MAIN, UNSET_MAIN, luastorage), -}) - -_G.raw.c = setmetatable({}, { - __index = cstorage, - __newindex = genclosure(cmap, C.eqe_filter_set_raw_c_no_lock, C.eqe_filter_unset_raw_c_no_lock, cstorage), -}) - _G.IPCD = function(s) return DAEMON_IPC(s, true) or IPCD(s) end @@ -90,4 +21,5 @@ _G.IPCD_WRITE = function(filepath, contents) ]]) end -require 'autorun_loader'('raw') +dofile(LUA_PATH..'/crossfeed.lua') +dofile(LUA_PATH..'/compressor.lua')