Compare commits

...

3 commits

Author SHA1 Message Date
snt
a935d4e619 multi dispositivo con envío independientes por capa. está sucio con
trozos sn usar y statics, pero funciona.
2024-05-19 01:36:23 +02:00
snt
fc274179ad funcionando en dos dispositivos mediante ring buffer, pero no puedo
mandar a dos dispositivos, si lo pongo con ma_splitter reproduce más
rápido y con glitches
mandar diferentes
2024-05-18 22:52:22 +02:00
snt
7aced09a02 style bypass checkbox 2024-05-15 22:36:46 +02:00
11 changed files with 516 additions and 170 deletions

View file

@ -1,93 +1,99 @@
」゙ー撩答ゥラ<EFBFBD><EFBFBD>據巣⊿瞥劇рネナト<EFBFBD>国勵キコエッ埇ーカサヲュ<EFBFBD><EFBFBD>、ォ<EFBFBD><EFBFBD>隆ソーア<EFBFBD>ォ」ャウニヘ那ヤ販モ
<EFBFBD>槤謠睩恲儸<EFBFBD>狫佸<EFBFBD><EFBFBD>籙爁<EFBFBD>煮鷌謷毿蒺醮獶醛擤鍡粣嚪<EFBFBD><EFBFBD><EFBFBD>
桂冫昒痵<EFBFBD><EFBFBD>䘏忐忳
傾娸眑泭眼儔<EFBFBD>蔔艘権𡵆善鷄☆𣄽洫<EFBFBD>◥挾生<EFBFBD><EFBFBD>笢硠郥朒覕蒘嗖屾<EFBFBD>捹珈陊<EFBFBD><EFBFBD>潯鼨貵桝鸕<EFBFBD>
ㄑ𡵆ˇ蝦憐兢瑚庖陴敏怤昋窔<EFBFBD>ˆ鏽臍嗙睚晸稃<EFBFBD>彶娸眒厞闃
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鸁皸碤秆磗咤犪皭鏺<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
𠼰圪敆<EFBFBD>翫蹢噸版豆戎云鴃瓰噬撒漸
股澭勷蝤蚔迒侕圮蹣鼴藕謊葠<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>妰礼膦鳺鍷撗碯<EFBFBD>𩄍鈼拙
<EFBFBD>迂飯<EFBFBD>胱倅<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𠯋<EFBFBD>
𠮩ハ<EFBFBD><EFBFBD>鍳悌酋隆豆戎丐鶵
習踛檶言虞項斑陶蚔迒侕圮囀
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>マ椥軜桽敆旃瀁臅錒<EFBFBD>
<EFBFBD><EFBFBD>働歇蠆𩄍栁咤𦭓艕鏵襙<EFBFBD><EFBFBD>
垧梉砘鹹<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
課襛銖輕圻奶ㄑㄑˇ蝦遣凳楫
庇檁☆<EFBFBD>𤂍窔<EFBFBD>冫鐘濫澀睚嗖訹<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>糓鼓灢鳿緪鳲飹<EFBFBD>𩄍栁咏𣿫
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
见鍒澣<EFBFBD>糌笢膩囿岳圻圻縈<EFBFBD>蕪蝸擐
宣恲甘岒彴葛鼓寊<EFBFBD>冫鏽擭嗙睚嗖稄忄
蘑郁穢<EFBFBD>𡞵灿灖鳿緪魟僣<EFBFBD>𩄍栁帮<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㶴覶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>椗媏僎岳圻奶<EFBFBD><EFBFBD>蕪蝦遜矰
用斻芃倎眝昋岕<EFBFBD>囁鏽臏澀<EFBFBD><EFBFBD>
<EFBFBD>紜╞狀襟瀁臅鍆鍆𡺤槼蜾摽栽
<EFBFBD>恕匪錂蘟麔嚭<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鍳鮃鬥版牴戎不鴃瓰說撒犒仄項盔盛ヒ捈侕拏ナ苃葺謊袌椽詒<EFBFBD>
尌笣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>移灢鳿緛鸁瘔魬𩄍鈼翦犪皭鏵襡
<EFBFBD><EFBFBD><EFBFBD>樿觙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鍳拳
洮炕斯ぎ摳鰴撚噢儒犒潭玥斑陪玴迒侕圮<EFBFBD>
冫騰痵<EFBFBD><EFBFBD><EFBFBD>㻑彶婟<EFBFBD>迖歞闉鍆澭𡺤槼蜾摳<EFBFBD><EFBFBD>
𨯨檊樏緾公<EFBFBD>悔詗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>嫃窒沷嶋解═贀鈺嗂嶍朌瑣鴢項蓿拳玴昐侕圮ナ鼴<EFBFBD>
臏濘蟠<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>螻劓<EFBFBD>謻罻霙緪絮碯<EFBFBD><EFBFBD>榱厨║蘾纇
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
歎蘙<EFBFBD>姿誚奶Ⅵ<EFBFBD>噢■遣兢毀馬陴敖眝昋゜
<EFBFBD>嚊倎澀睖濛稃媌跂娸眒剞襡擫錴鳿緛<EFBFBD>
<EFBFBD>蜈附櫡厨═錂蘣鵹韗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
𣕑蠅恟<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𥲤悔炤垠豆戎孕鴃瓰鴃撒犖<EFBFBD>
母膱貏鯢嗀昋岓堌冖懼擱澀睚嗍ˆ尌窔娸眑<EFBFBD>
<EFBFBD>盒蕞恍蘡槼蝆灋<EFBFBD><EFBFBD>灋菍║蘾蘾濿嚫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
𡁶袤ペ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>姹閂哈筐坏鷏
<EFBFBD><EFBFBD>活撒爾仄韌敞停玴迒岈桱ナ阹藕<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>䍮玾旃闅臅膮纋豍槼蜾婦<EFBFBD>𩄍鐋咤岜<EFBFBD>
<EFBFBD>砠詮蟨<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
閂囿岳圻<EFBFBD>
不╮瓰噬朌犒虞項敞盛玴迒侕桱ナ鼴藕邀葠椽詀椥匊梊衵旃濿臅鍆氆豍╩蜾摳<EFBFBD>𩄍僰咤犪皭鐐襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>陵閂囿岳宋奶ㄑ<EFBFBD>蕪□遣兢毓筐陴救怤昋窔<EFBFBD>冫鏽蹟澀睚嗖稌儷笝娸眒唒鍙擫膦鳿义鳲皸<EFBFBD>碯栁咤犪皭<EFBFBD>
摳艛<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
悌洮版𡘾漸奴Ⅴ瓰噬朌犒葦
項斑盛𣜯捈巠尕ナ鼴葺謊葺
椽詀椥豽尕眣捈瀁臅癰頠燿
槼蜾摳<EFBFBD>╬鈼咤噂皭鐐襝<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>担惇牧庖圻奶縈<EFBFBD>
蝦遣兢銩庖硎敏怤昋窔奻ˆ
鏽臏澀渕濛覘媌笝娸恮栯闃
擫膦鳿菽鸁蝆蝆𩄍栁翦╜謮
鏵襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>閦悌洮隆豆此
不╮瓰飲朌跼葦項斑拳玴迖
侕圮ナ芢葺檀葺椽詀臢趼桱
衵旃瀁樘癰魰踖槼蜾灋<EFBFBD>𩄍<EFBFBD>
厨║蘾煮濿蹢<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祚降
囿岳圻閂縈礆縈蝦遣斥毓筐
陴救怤鐃窔奻ˆ鏽臏嗙睚剸
稌尌笝<EFBFBD>恮栯闃擫膦鐋緪<EFBFBD>
<EFBFBD>𩄍籊翦<EFBFBD>灖鏵襙<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>鍳悌丙隆幸此不╮撚噬憫
犒虞項斑拳恄迖侕圮袸鼴蹬
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>姘絕灢
鳿緪欘蹥襡碨鍡咤犪艕鏵鵯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
蝦掛僎遣<EFBFBD>
氖不╮瓰ⅤⅢ犒虞隆揚盛玴迒訧觕ナ鼴蹬醣葠椽詀臢屼梊衵捈
𨯨儵鍆濊
踖氂裻榱<EFBFBD>禔僰翦噂儓鏵襙<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
鍳悌洮版揮戎不╮迚噬撒此虞隆斑盛蚔迒匊圮ナ椔藕邀葠椽マ椥訧梊衵迖瀁艛鍆氆𡺤槼裻摳<EFBFBD>碯栁咤噂皭鐐襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祚閂楫岳宋
奶ㄑ<EFBFBD><EFBFBD>遣兢奎絕陴敝𠲍庋恀攰㑤媄<EFBFBD>
<EFBFBD>
睚嗢<EFBFBD>
椥笪囡蹉敆瀁臅鍆纇╒槼蜾榱<EFBFBD>僣栁咤齴
靘鏵襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
炬囿岳圻馱ㄑ□蕪蝦<EFBFBD>
犒虞<EFBFBD>
答遠救怤倓埡虰冫懼軀澀睚嗖ˆ隶笝娸眝
<EFBFBD>
霒逖亮揶温呢見狭嗣吢绦侅彝叫蝤臊隗颀蛄翕<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
些闯旱榆皾湏毄浊紫
晾咻廖Ё悍Τ<EFBFBD><EFBFBD>洓稔鼬晻勽<EFBFBD>灊晻<EFBFBD>犷姛崄堜<EFBFBD>
趔篪鞆帊嫍妷堈殔剝倽€煘潃洑櫂嫋晹拵憪<EFBFBD><EFBFBD><EFBFBD>Е<EFBFBD><EFBFBD>
<EFBFBD>们翁讠<EFBFBD>闯肮舷闲耸扇瞧磐<EFBFBD>
蟹梗<EFBFBD>累谫谶衷窒已酗铐煦<EFBFBD>
麕负牴厄椆<EFBFBD><EFBFBD>黯觚矧耩弾崒嫋
涱刳蕾謵潃煘潨洑渼棖晹搾憪<EFBFBD>
钾蝻栲盖<EFBFBD><EFBFBD>沧籴<EFBFBD>蓟夯胺蜂ǔ脖衔屯樦
劢檪噸英灆仛侠圳仝咧砸弦研镱眄个
麍陡鼬汊徉<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鲺酾<EFBFBD>
銗质拊櫀増噯厔個潃煘潨洑殑
咑膳诶烂艏爆<EFBFBD><EFBFBD>ЁЦ<EFBFBD>烤骄<EFBFBD>
<EFBFBD>丕厉徉牠衔吞耸耸燮拍寐晾俾
蠣劃僧晝喥弦研镱眍轹殍珂邃沐<EFBFBD>
騼『鞖桢<EFBFBD>鲺趔痼鞆帊寢妶垱
旟勰掱哑缽€洑櫂棖棖彃憪<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ш垢范刀碑毕瓮趟怂<EFBFBD>
栈及拷π咎淋圳儇自兹右研镱祜<EFBFBD>
鴶憮殮凅晲檨灬<EFBFBD><EFBFBD><EFBFBD>赭梵蝰饛帉迼
橍耋桚<EFBFBD>鷳鳊朦巼殭槜枙枒帒惎<EFBFBD><EFBFBD><EFBFBD>
黑哐篡壑丿忒牷汗阜斗动脖衔吞事<EFBFBD>
诤砍曰欢赶┈ゥ扰刈终杂杏田铐祀觇猁
魸潝汃枬嫓铉<EFBFBD><EFBFBD>鲺鲴铖饛帊寛迺
<EFBFBD><EFBFBD><EFBFBD>螯撱摐煘潨洑洑嫋晹搾憮<EFBFBD>
吭逸迅凶苴本<EFBFBD>烤郊垢ジ范荡吵嘤
墀檲煁帓重詴洕剨塘苒谫刈鬃扔已酗铑瑚
鴬潤掯羼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鲺趔驙<EFBFBD>
<EFBFBD><EFBFBD>殝殯唴剝倎仢倽湜殭槜膲
敁挊尟<EFBFBD><EFBFBD><EFBFBD><EFBFBD>亥ぃ〗牽淼牷汗极兜闯<EFBFBD>衔刃耸扇燮拍呸晾邹淋圳弈字菰弦研珧盱腼蹊珑怿汊范泾<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
趔蝙鞚钛萋汌忠敊剝個湡灉攪殭槚姇敁拺惎<EFBFBD>
<EFBFBD><EFBFBD>吹裴<EFBFBD>敖牽看牷汉公兜床<EFBFBD>衔吞耸稍
瞧盘咝<EFBFBD>殱埼勤氽帐赵變托镱祓腙殍珂邃<EFBFBD>
忉圜怙湩<EFBFBD>鑻┆瘁铖饗軕寢寠攪唴厽倎€煘潨泦
櫂棡墕笪蕾控蝠<EFBFBD><EFBFBD>牒沪アЬ<EFBFBD>疙〖缓袱范荡巢毕<EFBFBD>
吞寺遮<EFBFBD>攳哟灉媼熖<EFBFBD>喪酥沼囄研骐耢腙梏珂邃汊徉<EFBFBD>
<EFBFBD><EFBFBD>骐槴Ъ鋮<EFBFBD>ぺ虧钰詻攪唽偀倎咽倽湜泤槜枙敁拺<EFBFBD>
截麴<EFBFBD>Еゥ竣 竣疥缓垢贩┐巢坝瓮倘<EFBFBD>
劬灇惼艳晾哌淋圹倌种赵右诱箢盱牿殍玟<EFBFBD>
鰰唤叠灬<EFBFBD><EFBFBD>澉鲷麸篌饛帊實枆垏嚈剝個<EFBFBD>
嶈睦螝媱棖晻彃憫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>┄ェ工牸烤郊<EFBFBD>
ㄏ珉忄霭牠衔屯资缮勤睦寐晾挢淋圳倌字兆<EFBFBD>
困彸焊<EFBFBD><EFBFBD>桤驿<EFBFBD>忄嚆<EFBFBD><EFBFBD><EFBFBD><EFBFBD>牾趔蝽饛帍<EFBFBD>
欬衷佑菂憺亐煙仠洓檮柪晹搾搾钞<EFBFBD><EFBFBD>┄Ё<EFBFBD>
睹箐汴<EFBFBD>蓟焊し洞疮氨衔吞藶杖瞧拓寐聯<EFBFBD>
叹槃毸淖终障已扬蝻祀觊桄铢溷忾<EFBFBD><EFBFBD><EFBFBD>
铏う垮埇<EFBFBD>鈸帊寠枆垎啓唭倎€煘虁洑檺嫋晳枎
<EFBFBD><EFBFBD>浼贼<EFBFBD>沪イ⒕<EFBFBD>揪【缓垢范悒巢鼻彝趟险
惹婆拿铝<EFBFBD>
咿蒈圳儇酥赵右研矧盱腙殍珂<EFBFBD>汊徉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鲺麸蝰饛帊寢枆垏唴剝倽€煘潨洑檮棖晹搾憪钞<EFBFBD><EFBFBD>┄Шイ<EFBFBD>烤〖缓垢范胆巢毕瓮趟稚惹婆拿螺肋掭苒谫淖终杂已畜铐祀觊桤<EFBFBD>溷忉<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鲺梵蝰饛帊寳妷垏唴剝瀬€煘潨洑厴棖晹搾憣<EFBFBD><EFBFBD><EFBFBD>┄沪イ<EFBFBD>
<EFBFBD>Ш垢范荡钞毕瓮兴噬熔婆拿蘖肋蘖苒谫<EFBFBD>
字赵右傊箢祆膂殍珂<EFBFBD>汊狳
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>膂趑箢耩弾憣媻墧
噯厔儌亣優湝泦櫂棖墧捔檶
<EFBFBD><EFBFBD><EFBFBD>┋沪い<EFBFBD>烤〖洪堡
范荡巢庀彝退收惹婆孛铝烂
掭苒谫嬜收沼彝酗铐痣觊棼
驽溷忉楚恺<EFBFBD><EFBFBD><EFBFBD>鲺梵簌饟
帊寢妷蹌殔厠倽€煘潃洓憳<EFBFBD>
枙敁拺铆箔<EFBFBD>┑ěΕΓ
窘蓟汗鞍<EFBFBD>党箔衔吞资扇勤
拍寐晾邹淋谝倌字赵弦研矧
盱腙殍镧<EFBFBD>怅狳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
豸篁耩噷憣妭墧噯厔焸亐焸
潨洑櫂煉墧挌憣<EFBFBD><EFBFBD>藩┄Ш
<EFBFBD>坊〖翰工范荡<EFBFBD>毕窝
趟噬惹蚊孛蒙烂掭苒瀑刈稚
杂已酗驽痣脶棼驽溷<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>梵簌饟帊寢枆垏啓
剝倎€煐虁洓憳嫋晹搸憪<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ě<EFBFBD>牐窘蓟<EFBFBD>阜订
闯脖衔艠资认捼拍寐堇咿堇
圳儇字輥弦凶候盱腙蹊珂屮
汊徉<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>牾趔蝽饛帊<EFBFBD>
媻増噯謤焸€稚倽湜殔槚烂<EFBFBD>
搾憪<EFBFBD><EFBFBD><EFBFBD>窈イ綘捐霠
┢嚓蹉柔珉喱洀姙垿箓挏浹<EFBFBD>
晾咿廖善耸四侨右研箢盱牿殍珂<EFBFBD>汊狳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鲺趔<EFBFBD>
耩弾崒堒<EFBFBD>
殨殫枱悡<EFBFBD>
焵潨洑櫂嫋嫈搾憪<EFBFBD><EFBFBD><EFBFBD>Е工舰<EFBFBD>烤綘护垢范荡<EFBFBD><EFBFBD>瓮趟收
谡谂拿螺
烂蘖芮谂厮稚韵彝旭铐祀觊<EFBFBD>
琥屮泾狳<EFBFBD>恺帑纟澉牾梵<EFBFBD>
耢彃崘
増噯厔儌潃煘潨洑檮棖晹彃憪<EFBFBD><EFBFBD><EFBFBD>Е<EFBFBD>郊沪垢范┐巢庇瓮趟稚惹瀑拿铝苓掭芮谫刈收杂彝酗铐痣觊棼驽溷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>澉鲺麸蝰饛拲寢姇垏唴槂倎€優潨泦櫂棖<EFBFBD>
敁拺尟<EFBFBD><EFBFBD><EFBFBD>ě亥ぃ牸弧航景豢剧ǔ<EFBFBD>
<EFBFBD>
吞松<EFBFBD>
惹桥匮休懒掭苒谫淖日杂已畜铙祀觊桤<EFBFBD>
邃忏<EFBFBD><EFBFBD><EFBFBD><EFBFBD>黯轸眚耩弾崘嫈増噯厔<EFBFBD>
倎仢倧巼殗槜枙敁帒幆<EFBFBD><EFBFBD><EFBFBD>üΕ<EFBFBD>
<EFBFBD>郊缓垢范ù巢币瓮趟咨惹曝拿铝肋掭苒谫暸<EFBFBD>
允右研镱耢腙轸珂邃<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>黯轸睑麴弾崘嫈増噯厔焸焵煘潨泦
<EFBFBD>

View file

@ -8,9 +8,11 @@ HEADERS += src/libremediaserver-audio.h \
src/dmxwidget.h \
src/filterbankwidget.h \
src/libremediaserver-audio-gui.h \
src/ma_writer_node.h \
src/main.h \
src/miniaudio.h \
src/medialibrary.h \
src/miniaudio.h \
src/ma_writer_node.h \
src/miniaudioengine.h \
src/olathread.h \
src/audiolayerwidget.h \
@ -26,10 +28,11 @@ SOURCES += src/main.cpp \
src/dmxwidget.cpp \
src/filterbankwidget.cpp \
src/libremediaserver-audio-gui.cpp \
src/miniaudio.c \
src/libremediaserver-audio.cpp \
src/medialibrary.cpp \
src/miniaudio.c \
src/miniaudioengine.cpp \
src/ma_writer_node.c \
src/olathread.cpp \
src/audiolayerwidget.cpp \
src/audiowidget.cpp \

View file

@ -1,15 +1,18 @@
#ifndef DEFINES_H
#define DEFINES_H
#define VERSION "LibreMediaServerAudio v0.2.0 Antigona"
#define COPYRIGHT "(C) 2014-2024 Santi Noreña <lms@criptomart.net>"
#define LICENSE "GPL 3 Licensed. See LICENSE.txt."
#define DEFAULT_FILE "lms-audio.xlm"
#define MAX_LAYERS 4
#define MAX_AUDIODEVICES 8
#define UI_REFRESH_TIME 100
#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks
#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer
#define VERSION "LibreMediaServerAudio v0.2.0 Antigona"
#define COPYRIGHT "(C) 2014-2024 Santi Noreña <lms@criptomart.net>"
#define LICENSE "GPL3 Licensed. See LICENSE.txt."
#define DEFAULT_FILE "lms-audio.xlm"
#define MAX_LAYERS 4
#define MAX_AUDIODEVICES 8
#define FORMAT ma_format_f32 /* Must always be f32. */
#define CHANNELS 2
#define SAMPLE_RATE 48000
#define UI_REFRESH_TIME 100
#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks
#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer
struct dmxSetting {
int address;
@ -18,7 +21,7 @@ struct dmxSetting {
int audioDevice;
};
enum class Status
enum Status
{
Stopped,
Paused,
@ -30,6 +33,15 @@ enum class Status
PlayingFolderRandom
};
enum Slider
{
Volume,
Pan,
Pitch,
Bypass
};
#ifdef __cplusplus
constexpr const char* statusToString(Status e) noexcept
{
switch (e)
@ -45,27 +57,6 @@ constexpr const char* statusToString(Status e) noexcept
default: return "--++--";
}
}
/*
static const char* StatusStr[] =
{
"Stop",
"Pause",
"Play One",
"Play One Loop",
"Iddle",
"Play Folder",
"Play Folder Loop",
"Play Folder Rand",
0x0
};*/
enum Slider
{
Volume,
Pan,
Pitch,
Bypass
};
#include <QString>
struct layerData {
@ -81,4 +72,5 @@ struct layerData {
unsigned int universe;
int device;
};
#endif // __cplusplus
#endif // DEFINES_H

View file

@ -23,9 +23,10 @@
#define HIGH_FREQ 19
#define HIGH_Q 20
#define HIGH_GAIN 21
#define SEND1 22
#define SEND2 23
#define LAYER_CHANNELS 24
#define FILTER_BANK_GAIN 22 // not implemented yet
#define SEND1 23
#define SEND2 24
#define LAYER_CHANNELS 25
constexpr const char* dmxChannelToString(int e) noexcept
{
@ -43,6 +44,7 @@ constexpr const char* dmxChannelToString(int e) noexcept
case HIGH_FREQ: return "High Cutoff Frec";
case HIGH_Q: return "High Slope";
case HIGH_GAIN: return "High Gain";
case FILTER_BANK_GAIN: return "Post Filters Gain";
default: return "++--++--++";
}
}

View file

@ -10,10 +10,10 @@ FilterBankWidget::FilterBankWidget(QWidget *parent)
layout->setAlignment(Qt::AlignHCenter);
layout->setContentsMargins(0, 2, 0, 2);
layout->setSpacing(0);
this->setStyleSheet("border: 1px solid #5a4855;"
this->setStyleSheet("border: 2px solid #5a4855;"
"margin: 0px;"
"margin-top: 2px;"
"margin-bottom: 2px;"
"margin-top: 3px;"
"margin-bottom: 3px;"
"background-color: #383034;"
);
for (int i = 0; i < 13; i++) {
@ -25,8 +25,13 @@ FilterBankWidget::FilterBankWidget(QWidget *parent)
QVBoxLayout *master = new QVBoxLayout;
fb[0]->setRange(0, 500);
m_bypass = new QCheckBox;
connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int)));
master->addWidget(m_bypass);
m_bypass->setText("Bypass");
m_bypass->setStyleSheet("QCheckBox { border: 2px solid #2a0825;"
"margin: 0px;"
"background-color: #885074;"
"font-size: 7px;}");
connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int)));
master->addWidget(fb[0]);
layout->addLayout(master);
for (int i = 1; i < 13;) {

View file

@ -35,7 +35,7 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent)
topWidget->setContentsMargins(0, 0, 0, 0);
addDockWidget(Qt::TopDockWidgetArea, topWidget);
connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup()));
this->setContentsMargins(5, 5, 5, 5);
this->setContentsMargins(3, 3, 3, 3);
this->setStyleSheet(
"color: white;"
"background-color: #4f4048;"

View file

@ -140,7 +140,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
m_played.append(m_ola->getValue(layer, DMX_FILE));
}
#endif
} else if (channel >= HP_FREQ && channel <= HIGH_GAIN) {
} else if (channel >= HP_FREQ) {
m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value);
#ifndef NOGUI
if (m_ui) {

178
src/ma_writer_node.c Normal file
View file

@ -0,0 +1,178 @@
#include "ma_writer_node.h"
#include "miniaudio.c"
MA_API ma_writer_node_config ma_writer_node_config_init(ma_uint32 channels, ma_uint32 bufferSizeInFrames, ma_pcm_rb *rb)
{
ma_writer_node_config config;
MA_ZERO_OBJECT(&config);
config.nodeConfig = ma_node_config_init();
config.channels = channels;
config.bufferSizeInFrames = bufferSizeInFrames;
config.pBuffer = rb;
return config;
}
static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
{
ma_writer_node* pWriteNode = (ma_writer_node*)pNode;
MA_ASSERT(pWriteNode != NULL);
MA_ASSERT(ma_node_get_input_bus_count(&pWriteNode->baseNode) == 2);
if (*pFrameCountIn > 0) {
void *pWriteBuffer = NULL;
ma_pcm_rb_acquire_write(pWriteNode->pBuffer, pFrameCountIn, &pWriteBuffer);
if (pWriteBuffer != NULL) {
ma_copy_pcm_frames(pWriteBuffer, ppFramesIn[1], *pFrameCountIn, ma_format_f32, pWriteNode->channels);
ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn);
}
}
//*pFrameCountOut = 0;
ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels);
}
static ma_node_vtable g_ma_writer_node_vtable =
{
ma_writer_node_process_pcm_frames,
NULL,
2,
1,
0
// MA_NODE_FLAG_CONTINUOUS_PROCESSING
// MA_NODE_FLAG_SILENT_OUTPUT
};
MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode)
{
ma_result result;
ma_node_config baseConfig;
ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable.
ma_uint32 outputChannels[1];
if (pWriteNode == NULL || pConfig == NULL || pConfig->pBuffer == NULL \
|| (pConfig->channels > MA_MAX_NODE_BUS_COUNT) ) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pWriteNode);
inputChannels[0] = pConfig->channels;
inputChannels[1] = pConfig->channels;
outputChannels[0] = pConfig->channels;
baseConfig = pConfig->nodeConfig;
baseConfig.vtable = &g_ma_writer_node_vtable;
baseConfig.pInputChannels = inputChannels;
baseConfig.pOutputChannels = outputChannels;
result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pWriteNode->baseNode);
if (result != MA_SUCCESS) {
return result;
}
pWriteNode->bufferSizeInFrames = pConfig->bufferSizeInFrames;
pWriteNode->pBuffer = pConfig->pBuffer;
pWriteNode->channels = pConfig->channels;
return MA_SUCCESS;
}
MA_API void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_node_uninit(&pWriteNode->baseNode, pAllocationCallbacks);
}
/*
* Data Source Ring Buffer
*/
ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_data_source_rb* ds = (ma_data_source_rb*)pDataSource;
ma_uint32 pcmFramesAvailableInRB = 0;
ma_uint32 pcmFramesProcessed = 0;
// lo mismo que en el callback, va el doble de rápido y con glitches.
while (pcmFramesProcessed < frameCount) {
pcmFramesAvailableInRB = ma_pcm_rb_available_read(ds->rb);
if (pcmFramesAvailableInRB == 0) {
break;
}
ma_uint32 framesToRead = frameCount - pcmFramesProcessed;
if (framesToRead > pcmFramesAvailableInRB) {
framesToRead = pcmFramesAvailableInRB;
}
void* pReadBuffer = NULL;
ma_pcm_rb_acquire_read(ds->rb, &framesToRead, &pReadBuffer);
if (pReadBuffer != NULL) {
ma_copy_pcm_frames(pFramesOut, pReadBuffer, framesToRead, ma_format_f32, 2);
ma_pcm_rb_commit_read(ds->rb, framesToRead);
pcmFramesProcessed += framesToRead;
}
else {
break;
}
}
*pFramesRead += pcmFramesProcessed;
return MA_SUCCESS;
}
ma_result ma_data_source_rb_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
(void)pDataSource;
(void)frameIndex;
return MA_NOT_IMPLEMENTED;
}
ma_result ma_data_source_rb_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
(void)pDataSource;
*pFormat = ma_format_f32;
*pChannels = 2;
*pSampleRate = ma_standard_sample_rate_48000;
return MA_SUCCESS;
}
ma_result ma_data_source_rb_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
(void)pDataSource;
*pCursor = 0;
return MA_NOT_IMPLEMENTED;
}
ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
(void)pDataSource;
*pLength = 0;
return MA_NOT_IMPLEMENTED;
}
ma_data_source_vtable g_ma_data_source_rb_vtable =
{
ma_data_source_rb_read,
ma_data_source_rb_seek,
ma_data_source_rb_get_data_format,
ma_data_source_rb_get_cursor,
ma_data_source_rb_get_length
};
ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer)
{
ma_result result;
ma_data_source_config baseConfig;
baseConfig = ma_data_source_config_init();
baseConfig.vtable = &g_ma_data_source_rb_vtable;
result = ma_data_source_init(&baseConfig, &pMyDataSource->base);
if (result != MA_SUCCESS) {
return result;
}
pMyDataSource->rb = ringBuffer;
return MA_SUCCESS;
}
void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource)
{
ma_data_source_uninit(&pMyDataSource->base);
}

52
src/ma_writer_node.h Normal file
View file

@ -0,0 +1,52 @@
/* Include ma_writer_node.h after miniaudio.h */
#ifndef ma_writer_node_h
#define ma_writer_node_h
#ifdef __cplusplus
extern "C" {
#endif
#include "miniaudio.h"
typedef struct
{
ma_node_config nodeConfig;
ma_uint32 channels;
ma_uint32 bufferSizeInFrames;
ma_pcm_rb *pBuffer;
} ma_writer_node_config;
MA_API ma_writer_node_config ma_writer_node_config_init(ma_uint32 channels, ma_uint32 bufferSizeInFrames, ma_pcm_rb *rb);
typedef struct
{
ma_node_base baseNode;
ma_uint32 bufferSizeInFrames;
ma_pcm_rb *pBuffer;
ma_uint32 channels;
} ma_writer_node;
MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode);
MA_API void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocation_callbacks* pAllocationCallbacks);
/**
* data source ring buffer
*/
typedef struct
{
ma_data_source_base base;
ma_pcm_rb *rb;
} ma_data_source_rb;
ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
ma_result ma_data_source_rb_seek(ma_data_source* pDataSource, ma_uint64 frameIndex);
ma_result ma_data_source_rb_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
ma_result ma_data_source_rb_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor);
ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* pLength);
ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer);
void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource);
#ifdef __cplusplus
}
#endif
#endif /* ma_writer_node_h */

View file

@ -4,16 +4,48 @@
#define BIAS 0.99f
#define FILTER_ORDER 3
static ma_pcm_rb aux1Buffer;
static ma_data_source_node g_dataSupplyNode;
static ma_data_source_rb g_dataSourceRB;
MiniAudioEngine::MiniAudioEngine() {}
void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
(void)pInput;
ma_result result;
result = ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": error audio callback.";
}
(void)pInput;
}
void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
(void)pDevice;
ma_result result;
ma_uint32 pcmFramesAvailableInRB = 0;
ma_uint32 pcmFramesProcessed = 0;
while (pcmFramesProcessed < frameCount) {
pcmFramesAvailableInRB = ma_pcm_rb_available_read(&aux1Buffer);
if (pcmFramesAvailableInRB == 0) {
break;
}
ma_uint32 framesToRead = frameCount - pcmFramesProcessed;
if (framesToRead > pcmFramesAvailableInRB) {
framesToRead = pcmFramesAvailableInRB;
}
void* pReadBuffer = NULL;
ma_pcm_rb_acquire_read(&aux1Buffer, &framesToRead, &pReadBuffer);
if (pReadBuffer != NULL) {
ma_copy_pcm_frames(pOutput, pReadBuffer, framesToRead, FORMAT, CHANNELS);
ma_pcm_rb_commit_read(&aux1Buffer, framesToRead);
pcmFramesProcessed += framesToRead;
}/* else { break; }*/
}
(void)pInput;
}
void MiniAudioEngine::stopEngine()
@ -23,6 +55,7 @@ void MiniAudioEngine::stopEngine()
}
for (uint i = 0; i < m_devicesSelected; i++) {
for (uint j = 0; j < m_layersQty; j++) {
ma_node_uninit(&m_filterBank[i][j].input, NULL);
ma_hpf_node_uninit(&m_filterBank[i][j].hpf, NULL);
ma_loshelf_node_uninit(&m_filterBank[i][j].loshelf, NULL);
ma_peak_node_uninit(&m_filterBank[i][j].mLow, NULL);
@ -30,6 +63,8 @@ void MiniAudioEngine::stopEngine()
ma_hishelf_node_uninit(&m_filterBank[i][j].hishelf, NULL);
ma_splitter_node_uninit(&m_filterBank[i][j].output, NULL);
}
//ma_writer_node_uninit(&m_sendToAux[0], NULL);
//ma_pcm_rb_uninit(&aux1Buffer);
ma_engine_uninit(&m_engine[i]);
ma_device_uninit(&m_device[i]);
}
@ -60,56 +95,55 @@ bool MiniAudioEngine::startEngine(uint layers)
ma_result MiniAudioEngine::createFilterBank(int id, uint layer)
{
ma_result result;
ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]);
ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]);
filterBank *fb = &m_filterBank[id][layer];
filterBank *fb = &m_filterBank[id][layer];
ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS);
result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize input node." << endl;
cout << "ERROR " << result << ": Failed to init input node." << endl;
return result;
}
fb->hpfConfig = ma_hpf_node_config_init(CHANNELS, SAMPLE_RATE, 16, FILTER_ORDER);
result = ma_hpf_node_init(ng, &fb->hpfConfig, NULL, &fb->hpf);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize high pass filter node." << endl;
cout << "ERROR " << result << ": Failed to init high pass filter node." << endl;
return result;
}
fb->loshelfConfig = ma_loshelf_node_config_init(CHANNELS, SAMPLE_RATE, 0.0f, 1.0f, 30);
result = ma_loshelf_node_init(ng, &fb->loshelfConfig, NULL, &fb->loshelf);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize low pass filter node." << endl;
cout << "ERROR " << result << ": Failed to init low pass filter node." << endl;
return result;
}
fb->mLowConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 4.0, 200); // double gainDB, double q, double frequency);
result = ma_peak_node_init(ng, &fb->mLowConfig, NULL, &fb->mLow);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize peak low filter node." << endl;
cout << "ERROR " << result << ": Failed to init peak low filter node." << endl;
return result;
}
fb->mHighConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 0.0, 600); // double gainDB, double q, double frequency);
result = ma_peak_node_init(ng, &fb->mHighConfig, NULL, &fb->mHigh);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize peak high filter node." << endl;
cout << "ERROR " << result << ": Failed to init peak high filter node." << endl;
return result;
}
fb->hishelfConfig = ma_hishelf_node_config_init(CHANNELS, SAMPLE_RATE, 0.0f, 1.0f, 20000);
result = ma_hishelf_node_init(ng, &fb->hishelfConfig, NULL, &fb->hishelf);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize hi shelf filter node." << endl;
cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl;
return result;
}
result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize output node." << endl;
cout << "ERROR " << result << ": Failed to init output node." << endl;
return result;
}
@ -120,7 +154,7 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer)
}
result = ma_node_attach_output_bus(&fb->input, 1, &fb->output, 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach high pass pass filter node." << endl;
cout << "ERROR " << result << ": Failed to attach bypass connection." << endl;
return result;
}
ma_node_set_output_bus_volume(&fb->input, 1, 0.0f);
@ -149,10 +183,17 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer)
cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl;
return result;
}
result = ma_node_attach_output_bus(&fb->output, 0, endpoint, 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output node to engine." << endl;
return result;
if (id == 0) {
result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output node to engine." << endl;
return result;
}
result = ma_node_attach_output_bus(&fb->output, 1, &m_sendToAux[id], 1);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl;
return result;
}
}
return result;
}
@ -161,6 +202,27 @@ ma_result MiniAudioEngine::setNodeGraph(int id) {
ma_result result = MA_SUCCESS;
uint i = 0;
if (id == 0) {
ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]);
size_t sizeInFrames = SAMPLE_RATE; // ma_get_bytes_per_frame(FORMAT, CHANNELS);
result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &aux1Buffer);
if (result != MA_SUCCESS) {
printf("Failed to initialize ring buffer.\n");
return result;
}
ma_silence_pcm_frames(aux1Buffer.rb.pBuffer, sizeInFrames, FORMAT, CHANNELS);
ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &aux1Buffer);
result = ma_writer_node_init(ng, &writerConfig, NULL, &m_sendToAux[id]);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to init writer node." << endl;
return result;
}
result = ma_node_attach_output_bus(&m_sendToAux[id], 0, ma_engine_get_endpoint(&m_engine[id]), 0); // Pull API
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach writer node." << endl;
return result;
}
}
while (result == MA_SUCCESS && i < m_layersQty) {
result = this->createFilterBank(id, i);
i++;
@ -176,12 +238,19 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
m_devicesSelected = nb;
for (uint internalId = 0; internalId < nb; internalId++) {
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig = ma_device_config_init(ma_device_type_duplex);
deviceConfig.capture.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id;
deviceConfig.capture.format = m_resourceManager.config.decodedFormat;
deviceConfig.capture.channels = CHANNELS;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id;
deviceConfig.playback.format = m_resourceManager.config.decodedFormat;
deviceConfig.playback.channels = 0;
deviceConfig.playback.channels = CHANNELS;
deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate;
deviceConfig.dataCallback = audioDataCallback;
if (internalId == 0)
deviceConfig.dataCallback = audioDataCallback;
else if (internalId == 1)
deviceConfig.dataCallback = audioDataCallback1;
deviceConfig.pUserData = &m_engine[internalId];
result = ma_device_init(&m_context, &deviceConfig, &m_device[internalId]);
if (result != MA_SUCCESS) {
@ -191,6 +260,7 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
engineConfig = ma_engine_config_init();
engineConfig.pDevice = &m_device[internalId];
engineConfig.pResourceManager = &m_resourceManager;
engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 100;
engineConfig.noAutoStart = MA_TRUE;
result = ma_engine_init(&engineConfig, &m_engine[internalId]);
if (result != MA_SUCCESS) {
@ -209,6 +279,23 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
}
cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << systemId[internalId] << " " << m_pPlaybackDeviceInfos[systemId[internalId]].name << endl;
}
//result = ma_data_source_rb_init(&g_dataSourceRB, &aux1Buffer);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to init data source ring buffer" << endl;
return false;
}
ma_data_source_node_config dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSourceRB);
//result = ma_data_source_node_init(ma_engine_get_node_graph(&m_engine[1]), &dataSupplyNodeConfig, NULL, &g_dataSupplyNode);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to init data source node" << endl;
return false;
}
//result = ma_node_attach_output_bus(&g_dataSupplyNode, 0, ma_engine_get_endpoint(&m_engine[1]), 0);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to attach data source rb node" << endl;
return false;
}
cout << "data source node state " << ma_node_get_state(&g_dataSupplyNode.base) << endl;
return true;
}
@ -255,12 +342,8 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice)
{
ma_result result;
// ToDo: ver si s puede attach dos dispositivos a la vez. si no:
// - enchufar a un splitter al sonido y attach cada uno de los lados.
// - iniciar un sonido por cada capa, copiar la capa en otro dispositivo
// - splitter al final de filterBank, esas señales se mezclan en un nodo mudo
// y se escribe la mezcla en un buffer. Mezclar el buffer en disco con el
// del otro device en el audio callback .
// - writer node y source con el buffer escrito en el otro device
if (m_mediaLoaded[layer] == true)
{
ma_sound_uninit(&m_currentSound[layer]);
@ -275,7 +358,7 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice)
}
result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].input, 0);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl;
cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl;
//return result;
}
m_mediaLoaded[layer] = true;
@ -343,7 +426,7 @@ void MiniAudioEngine::volChanged(int layer, float vol)
return;
if (vol >= 1)
vol = 0.99f;
ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, vol, FADE_TIME);
ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, pow(vol, 3), FADE_TIME);
m_currentLayerValues[layer].vol = vol;
}
@ -540,8 +623,20 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch
cout << "ERROR " << result << ": Failed set gain high shelf filter node." << endl;
return result;
}
}
return (result);
} else if (channel == SEND1) {
ma_node_set_output_bus_volume(&fb->output, 0, pow((value / 255.0f), 2));
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed set Send 1 Volume." << endl;
return result;
}
} else if (channel == SEND2) {
ma_node_set_output_bus_volume(&fb->output, 1, pow((value / 255.0f), 2));
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed set Send 2 Volume." << endl;
}
return result;
}
return (result);
}
bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass)

View file

@ -1,21 +1,20 @@
#ifndef MINIAUDIOENGINE_H
#define MINIAUDIOENGINE_H
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS 1
#define MA_ENABLE_JACK 1
#define MA_NO_GENERATION 1
#define MA_DEBUG_OUTPUT 1
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
#define MA_ENABLE_JACK
#define MA_NO_GENERATION
#define MA_DEBUG_OUTPUT
#define MA_DISABLE_PULSEAUDIO
#define MA_DEBUG_OUTPUT
#define MA_LOG_LEVEL_DEBUG DEBUG
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#include "defines.h" // MAX_LAYERS
#include "ma_writer_node.h"
#include <bits/stdc++.h>
using namespace std;
#include "defines.h"
/* Data Format */
#define FORMAT ma_format_f32 /* Must always be f32. */
#define CHANNELS 2
#define SAMPLE_RATE 48000
typedef struct
{
@ -31,12 +30,23 @@ typedef struct
ma_hishelf_node hishelf;
ma_hishelf_node_config hishelfConfig;
ma_splitter_node output;
ma_writer_node send1;
ma_data_source_node return1;
ma_audio_buffer_ref supplyReturn1;
} filterBank;
typedef struct
{
ma_engine m_engine[MAX_AUDIODEVICES];
filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS];
ma_writer_node m_sendAux1[MAX_LAYERS];
ma_pcm_rb *aux1Buffer;
} audioObjects;
class MiniAudioEngine
{
friend class libreMediaServerAudio;
static ma_pcm_rb *rb;
public:
MiniAudioEngine();
@ -44,6 +54,7 @@ public:
bool startEngine(uint layersQty);
bool startDevice(uint *id, uint nb);
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
static void audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
bool setBypass(int audioDevice, int layer, bool bypass);
protected:
@ -76,6 +87,8 @@ private:
filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS];
ma_engine m_engine[MAX_AUDIODEVICES];
uint m_layersQty;
ma_writer_node m_sendToAux[MAX_LAYERS];
audioObjects m_audioObjects;
ma_result getAllAudioDevices();
ma_result startContext();