Compare commits
13 commits
4ee82c5e5f
...
7631e54d51
Author | SHA1 | Date | |
---|---|---|---|
|
7631e54d51 | ||
|
f67ad9b1e1 | ||
|
cd0105c9f9 | ||
|
0979c3608e | ||
|
7a9c0cd0ac | ||
|
5915d4898e | ||
|
d34b972a54 | ||
|
246a8a2f98 | ||
|
ef653553d9 | ||
|
389966782d | ||
|
5a7a82736f | ||
|
88704cd726 | ||
|
1fccbf64fd |
31 changed files with 1135 additions and 702 deletions
|
@ -1,76 +1,79 @@
|
||||||
^皾湏毄讍悊€潫憙嚈曀寑剛扰臓崙櫗泛疮鷼岸沪瓲驖か<EFBFBD><EFBFBD><EFBFBD><EFBFBD>堪彪Й,称蛽咴斕<EFBFBD>
|
^皾湏毄讍悊€潫憙嚈曀寑剛扰臓崙櫗泛疮鷼岸沪瓲驖か<EFBFBD><EFBFBD><EFBFBD><EFBFBD>堪彪Й,称蛽咴斕<EFBFBD>
|
||||||
霒逖亮揶温呢見狭嗣吢绦侅鳇稆<EFBFBD><EFBFBD><EFBFBD>雠疰鬻惆苗稔钋祆铉轴耵鋶〖墴摉
|
霒逖亮揶温呢見狭嗣吢绦侅鳇稆<EFBFBD><EFBFBD><EFBFBD>雠疰鬻惆苗稔钋祆铉轴耵鋶〖墴摉
|
||||||
<EFBFBD>婆糖抻綆墑徍守受
|
<EFBFBD>婆糖抻綆墑徍守受
|
||||||
渡杂矣听挻京繑匠看嚩牕到憣汞&觌鋲<EFBFBD>挨嵹谠蓁咚我臈槕悵掝凵拍垍
|
傾娸眑泭𣖕儔<EFBFBD>蔔艘権𡵆善鷄☆𣄽洫拍魨綫卄跘殗衯遻鏽捘<EFBFBD><EFBFBD><EFBFBD>曙湆暋珅<EFBFBD>
|
||||||
槜棔垞拺敵<EFBFBD><EFBFBD>订ě<EFBFBD>ぃⅰ伎窘姬汗付<EFBFBD>闯抄舷浲资扇瞧拍棉
|
<EFBFBD>麪痍洮音豆伽腦╮迚噬撒此虞隆斑盒蚔迒忒圪葿椔藕謊葠暌
|
||||||
应€倶亷守仕终杂已嘘蝽祀觊桤纟
|
优忖ㄒ滑玾旃翲臇瀄氆豍槼蜱<EFBFBD>
|
||||||
鰞晨蜚<EFBFBD><EFBFBD><EFBFBD><EFBFBD>牾趔蝰饛趹
|
<EFBFBD><EFBFBD>厰翦犪鐊鐍謺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
烗照芤臈槂倎倵灉瀲殭槜枙敋<EFBFBD>
|
𨫼稃仝<EFBFBD>橶蟹<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祚閂囿庖
|
||||||
冩鲵<EFBFBD>藩┄ギゥ【<EFBFBD>烤郊徊<EFBFBD>
|
耋咏<EFBFBD>聹ˇ蝦遣兢痕絕陴救怤<EFBFBD>
|
||||||
<EFBFBD>赇<EFBFBD>汊斳烟耸衫乔秦寐晾咿輱<EFBFBD>
|
楰<EFBFBD><EFBFBD>掑<EFBFBD><EFBFBD>洠<EFBFBD>囡椥赻楗<EFBFBD>迖瀁臅錭網
|
||||||
泉噳挆嫃劳酗铐祀腚翮驽溷忉层
|
<EFBFBD><EFBFBD>‵<EFBFBD>𡵆ㄧ氄║蘱煏覶艛<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
鞗'郡<EFBFBD>麇偑<EFBFBD>鈸帊寢妷堉殔剝倎€煘<EFBFBD>
|
閙婓<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
庮妮谵喺耸陶偝<EFBFBD><EFBFBD>ⅸ<EFBFBD>亥ぃⅰ牽健
|
諄鐓欙輕圻奶ㄑ𨯂ˇ蝦遣兢揪
|
||||||
<EFBFBD>潺<EFBFBD>φ腙祯吒敀僦扇瞧湍聯堇咿蒈圳谀
|
忍檶<EFBFBD><EFBFBD>畑窔<EFBFBD>⼳鐃濫澀睚嗖窙<EFBFBD>
|
||||||
哦寪€娒田铐铍觇犒驽溷忉帻<EFBFBD>
|
鼴尕衵旃瀅瀔鍆氆豍誽<EFBFBD>
|
||||||
餁う讥㈡麈矧耩弾崓帠増噯厔冄<EFBFBD>
|
賾<EFBFBD>𩄍栁咏𣿫皭鏵襙<EFBFBD><EFBFBD>
|
||||||
掶亮倨蠅殗嗵势€崘<EFBFBD><EFBFBD><EFBFBD>牬Еイ"◇<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
<EFBFBD>牷汗阜斗动脖衔吞嗜<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𨯿炳洮版豆丑<EFBFBD>
|
||||||
谡谂拿铝垒芰苒谫刈鬃<EFBFBD>
|
掠<EFBFBD>蕪蝦遙誘毓絕陴最<EFBFBD>
|
||||||
晾托镱盱腓媵珂邃汊噔<EFBFBD>
|
葠訧圮ナ齬醣謊葠椽椥<EFBFBD>
|
||||||
祜帑<EFBFBD><EFBFBD>鲼鲲蝰饛帊崏<EFBFBD>
|
岒彶娸眒匎旚擫膦鳿瘜<EFBFBD>
|
||||||
増噥檮儌仠煘暅嚉櫂枈晹洅崘<EFBFBD>┌<EFBFBD>┅沪イぞ<EFBFBD>烤〖缓堡范荡<EFBFBD>毕茄趟律郧婆曔铝冗<EFBFBD>
|
蜾摞裻𨯨╒║丙濊麔襗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>妙惇囿捎圻迨縈<EFBFBD>楷蝦遛<EFBFBD>
|
||||||
蒈坜攀穵劃铆弲<EFBFBD>盱腚蹊珑眸汊後泾<EFBFBD><EFBFBD><EFBFBD>麝
|
虞飭芋秫<EFBFBD>摀<EFBFBD>觚ナ齬葺謠袌椽詗臢趼梊衵捈
|
||||||
豸篥礅焓姨櫀増啅檮儊€湡灊潎殭槜枙敁<EFBFBD>
|
瀁罽蠲䠋蒂蠲蜾骫裻<EFBFBD>埾║蠰濊麔嚫<EFBFBD><EFBFBD>
|
||||||
憪<EFBFBD>本他祀虼工!<烤鬼Ш垢丢荡巢毕瓮<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD>槢亅<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𥕛<EFBFBD><EFBFBD><EFBFBD>祚閂囿岳<EFBFBD>
|
||||||
耸商墼<EFBFBD>拫鸭€仢吻谫軈收哉淹酗铎痣觊桤驽<EFBFBD><EFBFBD>
|
戎井噫濕濻甭樉囓玥晰酯玴冾訧圮ヽ鼴藕謊葠<EFBFBD>
|
||||||
饤梗<EFBFBD>铉<EFBFBD><EFBFBD>牾趄蝽鹳帊寢妶攪唴嚐倎€渹
|
嗖硢霰<EFBFBD><EFBFBD>禮𢰧爾涇灖魨禊鳲撗<EFBFBD>𩄍烟咤犪皭鏵<EFBFBD>
|
||||||
応缕虤厞晹摀崘<EFBFBD><EFBFBD><EFBFBD>┄ЕА竣<EFBFBD>饥郊桓<EFBFBD>
|
嚫<EFBFBD><EFBFBD>鄵媮楧稃跂<EFBFBD>蒢<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祚為囿岳圻奶<EFBFBD>
|
||||||
<EFBFBD>镩岵牠衔屯资缮勤钠寐晾哓淋圳谀字照<EFBFBD>
|
╮甅0塉鋺阪澭馰臐<EFBFBD>𣠺訧匢邁鼴<EFBFBD>暌葠傱詀椥趼梊<EFBFBD>
|
||||||
困壋豁<EFBFBD>觊桄<EFBFBD>溻恺喱<EFBFBD><EFBFBD><EFBFBD>澉鲺黠蝰饛<EFBFBD>
|
嬪<EFBFBD>魂礼膦鳽义鳱禔鄔𩄍栁咏噂皭耰襙<EFBFBD><EFBFBD>
|
||||||
燏灾葺艆棙儌亖優潩泦槣棖晹挃崘<EFBFBD><EFBFBD><EFBFBD>┇<EFBFBD>
|
稾眚<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>挈閂咧<EFBFBD>
|
||||||
从<EFBFBD><EFBFBD>鲷饨<EFBFBD>蓟焊し洞疮氨衔吞讼杖瞧秦寐谅<EFBFBD>
|
碧<EFBFBD>╖1<EFBFBD>蕪<EFBFBD>遣虜奐毀陴救㈱昋岓堌冫鑣
|
||||||
太儑帉氈纳杂倚田铎祺肟桤驽驷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
郱<EFBFBD><EFBFBD>恉稌寎彶婞眝邾鍙擫鳷鐋緪<EFBFBD>皸<EFBFBD><EFBFBD>
|
||||||
鍠け哀沆弾崓棅墘嚉噭儌亐熓仠洑潉棖柷<EFBFBD>
|
<EFBFBD>丹限裂賥麔嚭<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
€蛟痤堪<EFBFBD>┅沪ゥ> 烤郊翰ジ范报巢皻<EFBFBD>
|
<EFBFBD>冾冖珥摹洮爸揮忖凶嵗瓰噬撫此虞隆斑眾<EFBFBD>
|
||||||
攥棝€鼗櫄勓蘖肋吡苒圪恼终杂已侒铐祜鲩桠泫
|
僈<EFBFBD><EFBFBD>摼婬鏽臍嗙睖剸<EFBFBD>尌笝笤恮厞闃擫膱<EFBFBD>
|
||||||
鰞景╋仯╅纟<EFBFBD>鏖趔篑鞃帊寢妷逈唴剣瀬€煕<EFBFBD>
|
<EFBFBD>插甅齘<EFBFBD>𩄍烟咤╜艗鏵襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
湜殭槜枙<EFBFBD>
|
鐥釋<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祚閂炎筐圻飛ㄑ𣙷<EFBFBD>
|
||||||
搾憪<EFBFBD><EFBFBD>藩┄Еイ><EFBFBD>烤郊缓ジ范荡巢庇瓮趟噬惹谂拿铝肋蘖苒谫刈终扔已酗铐祺觊桤驽溷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鲺趔蝰鞆帊寢妷垱唴剝倎€焸潨洑櫂棖墧搾憪<EFBFBD><EFBFBD><EFBFBD>┄Еイ<EFBFBD>
|
看魛顝殲澨旬盛珫捈佫尕齪鼴藕<EFBFBD>蹬椽蚙椥眑<EFBFBD>
|
||||||
俺伎窘蓟汗斧兜闯<EFBFBD>衔托耸扇燮拍棉晾咿<EFBFBD>
|
⑼<EFBFBD><EFBFBD>㭠廖灖鳿踛鳲蝁𦶠𩄍栁咤栘皭鐉闃<EFBFBD><EFBFBD>
|
||||||
苒谫刈忠扔友畜铐祀鲩桤纟
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
溷忉<EFBFBD><EFBFBD><EFBFBD>帑<EFBFBD><EFBFBD>鲺趔铖饛帒
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祚閂囿筐圻奶ㄑ□蕪蝦遣兢奎絕陴救恮昋岕<EFBFBD>冫媄臏澀睚剸稌尌笝娸恮厞鍙擫艕鳿緪鳲皸<EFBFBD>𩄍栁咤齴皭鏵襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
寢妷垏諆槂儊€優潨泦櫂棖<EFBFBD>
|
<EFBFBD><EFBFBD>祚閂囿岳誚奶ˇ<EFBFBD>蕪□遣馱毓絕租救恮
|
||||||
敁拺惎<EFBFBD>矮<EFBFBD>ɑΕぃ尽牽尽
|
昋岕<EFBFBD>妚媄藪擭睚嗖ˆ尌窔
|
||||||
蓟汗阜灏ǔ嘲氁吞耸杖瞧咆
|
娸眒厞赭謻錁叡緪鳲碯<EFBFBD>碯
|
||||||
寐晾咿庁勤儇资赵右托镱眇
|
栁咤犪瓙鼐鵨<EFBFBD><EFBFBD><EFBFBD><EFBFBD>伷<EFBFBD>
|
||||||
腙殍珂邈<EFBFBD>忄<EFBFBD><EFBFBD>恺<EFBFBD><EFBFBD><EFBFBD>鲺<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㤲<EFBFBD>
|
||||||
篁耩弾迧棅垐嚉厔儌潃煘潃
|
洮版豆鶗腦ㄐ迚噬撒此虞隆
|
||||||
洑櫂棖茣彃悙<EFBFBD><EFBFBD><EFBFBD>胆Еジ
|
斑盛玴𩼰訧<EFBFBD>マ鼴藕暌葠暌
|
||||||
"<EFBFBD>烤罴Ш赴藩荡巢<EFBFBD>瓮套
|
詀椥趼<EFBFBD>玾倠濿臅鍆纇緰氂
|
||||||
噬惹婆椓蘖吝蘖苒谫淖终韵
|
蜾摳<EFBFBD>寗<EFBFBD>踖斸癰蘟麔艛<EFBFBD><EFBFBD>
|
||||||
已酗铐块鲩殓纟溷忉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
<EFBFBD><EFBFBD>鲺<EFBFBD>铖饛帒寢妷攪唴劅
|
<EFBFBD><EFBFBD>祚蠿楫岳宋奶ㄑ<EFBFBD>蕪<EFBFBD>
|
||||||
倎€煘潝泦櫂棖墧搾憣<EFBFBD><EFBFBD><EFBFBD>
|
遣兢毓嵿租救恮昋岕堌冫懼
|
||||||
<EFBFBD>ěΕ<EFBFBD>尽牽尽蓟汗し兜疮
|
臏澀睚<EFBFBD>ˆ尌窔娸眒泬鍙檉
|
||||||
脖衔吞蒙杖瞧咆寐晾棉蒈燮
|
膦鳿緪唬碯<EFBFBD>碯栁咤噂皭鐐
|
||||||
摔巹梺畤厜緧府<EFBFBD>珖枺苯拣<EFBFBD>
|
襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
<EFBFBD><EFBFBD><EFBFBD>嚅桢赍赙骘蝰饛拲寢嫊垏唴槂倎€優潨焼櫂棖晹搾<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鍳拳洮版揮戎凶
|
||||||
惎<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
╮瓰噬毉此虞隆斑盛蚔迒匊
|
||||||
荡苟本巢<EFBFBD>
|
蛓<EFBFBD><EFBFBD><EFBFBD><EFBFBD>罁<EFBFBD><EFBFBD>𡺨<EFBFBD><EFBFBD>龬<EFBFBD>
|
||||||
荆蓟汗阜<EFBFBD><EFBFBD>脖衔托嗽扇瞧拍呗呃咿蒈燮倨字赵右托耦盱腙轸
|
厞鍙蹠灢𦭓啝<EFBFBD>皸<EFBFBD>禔栁嵆犪皭鼐襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
豸<EFBFBD>汊狳
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
<EFBFBD>恺帑纟澉牾梵铖鞆悕寢妷垱
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
啓劅倽€優仠嚉厴嫋墧彃<EFBFBD>
|
拿洮版豆漸漆╮瓰鴃憧犒虞項迅炳玴迒匊屼ナ鼴藕暌醣椽詀椔
|
||||||
惓<EFBFBD><EFBFBD>
|
鼴尕衵捈
|
||||||
<EFBFBD>
|
濿艛錂濊踖氂裻榱<EFBFBD>僣栁咤齴
|
||||||
ěΕぃⅰ伎窘蓟汗斧兜闯<EFBFBD>衔托耸扇燮拍棉晾咿淋圳倌字赵弦研矧盱腙蹊珂屮汊徉泾<EFBFBD><EFBFBD><EFBFBD>黯轸篁耢弾崒棅増嚉厔儌<EFBFBD>
|
灖鐐襡<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
€煘潃洑櫂嫋晹搸憪<EFBFBD><EFBFBD><EFBFBD>诞·Ⅰン┘竣
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
<EFBFBD><EFBFBD>
|
<EFBFBD>
|
||||||
汗付<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𥲤悌洮版酉戎不鴃瓰鴃撒犒仄項敞盛玴捈侕尕ナ鼴葺謊葺椽詀臢趼桱衵旃鵹臅錂氆豍╩蜾榱<EFBFBD>𩄍𥌓咤犪艕鏵襡
|
||||||
荡舶<EFBFBD>苎陶噬惹婆孛芰肋掭芮谇刈终杂<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>勹<EFBFBD><EFBFBD>租
|
||||||
脹镱盱腙殍<EFBFBD>邃<EFBFBD><EFBFBD>徉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鬻鲺趔蝰饛帊屍槙
|
蕪<EFBFBD>
|
||||||
墮唴剝倎湡灊渿殭槜<EFBFBD>
|
版谷<EFBFBD>
|
||||||
晹搾<EFBFBD>
|
奶<EFBFBD>蔡迫耦遣兢毓庖革救怤杶忑<EFBFBD>冫鏽<EFBFBD>
|
||||||
惐Θ<EFBFBD><EFBFBD>揣腑。ⅰ牐荆蓟汗阜<EFBFBD><EFBFBD>脖衔托
|
<EFBFBD>葠椽詀椥忒梊衃旃瀁謽鍆澨豍槼蜾摳<EFBFBD>𩄍揸鳺
|
||||||
<EFBFBD>
|
╞皭鏵襙<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>陵閉囿岳宋朮ㄑ<EFBFBD>蕪<EFBFBD>
|
||||||
|
<EFBFBD>
|
||||||
|
|
|
@ -4,39 +4,45 @@ Libre Media Server Audio - An Open source Media Server for arts and performing.
|
||||||
https://git.criptomart.net/libremediaserver
|
https://git.criptomart.net/libremediaserver
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
|
|
||||||
Lbre Media Server ChangeLog
|
Libre Media Server ChangeLog
|
||||||
|
|
||||||
v 0.2.0 Antigona (24/04/2024)
|
v 0.2.0 Antígona (26/05/2024)
|
||||||
+ change engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing.
|
+ Change audio engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing.
|
||||||
+ Refactor all audio methods to MiniAudioEngine.
|
+ Refactor all audio methods to MiniAudioEngine class.
|
||||||
+ Select sound device output.
|
+ Select sound device output.
|
||||||
+ pan.
|
+ Pan.
|
||||||
+ Show faders values.
|
+ Show faders values. New SliderGroup class.
|
||||||
+ play offset.
|
+ Entry Point 16 bits.
|
||||||
+ Refactor AudioMasterWidget to AudioDMXReceptionWidget.
|
+ Refactor AudioMasterWidget to AudioDMXReceptionWidget.
|
||||||
+ mp3, flac, wav (mp3 has given some errors seeking cursor...).
|
+ Read mp3, flac, wav (mp3 has given some errors seeking cursor...).
|
||||||
+ settings dialog not working, only read the conf file at startup.
|
+ Removed settings dialog, only read xml conf file at startup.
|
||||||
+ variable number of layers.
|
+ Real dynamic variable number of layers based on conf file setting.
|
||||||
+ olathread, send double channels only once for each dmx frame buffer.
|
+ OlaThread send double channels (volume, entry point, load media) only once for each dmx frame buffer.
|
||||||
|
+ Terminal mode without graphical interface. All audio methods has been refactorized out of QWidget world.
|
||||||
|
+ Compilation without GUI (-DNOGUI).
|
||||||
|
+ New Status "Iddle" in playbacks if is not loaded.
|
||||||
|
+ New DMX personality version, better sort for audio needs (first load media, set vol, pan, etc, last playback order);
|
||||||
|
+ Refresh layer values when it loads a new sound file.
|
||||||
|
+ No QtSignals for sending data, better performance about 20% in my machine. Now, libremediaserver only updates values in AudioWidget, ui refresh is doing with a timer in audiowidget, so there is not problems between graphical and ola thread (the callback).
|
||||||
|
+ Load media files from ui clicking in the media labels.
|
||||||
|
|
||||||
v 0.1.3 Unreleased (19/04/2024)
|
v 0.1.3 Leúcade (19/04/2024)
|
||||||
|
|
||||||
+ Ubuntu 22.04 jammy.
|
+ Ubuntu 22.04 jammy.
|
||||||
+ Use SFML as audio engine.
|
|
||||||
+ Qt 5.15.3.
|
+ Qt 5.15.3.
|
||||||
+ pitch.
|
+ Pitch.
|
||||||
+ loop.
|
+ Loop.
|
||||||
|
|
||||||
v 0.1.2 Mayordomo (12/08/2015)
|
v 0.1.2 Mayordomo (12/08/2015)
|
||||||
|
|
||||||
- GUI config
|
- GUI config.
|
||||||
- Several bugs tested in real world
|
- Several bugs tested in real world.
|
||||||
- variable layers
|
- Variable layers.
|
||||||
- SFML as audio engine
|
- SFML as audio engine.
|
||||||
|
|
||||||
v 0.1.1 Pascual (24/09/2014)
|
v 0.1.1 Pascual (24/09/2014)
|
||||||
|
|
||||||
+ First Version: 4 layers playing .ogg
|
+ First Version: 4 layers playing .ogg.
|
||||||
+ Needs Open Lighting Arquitecture => 0.9.0
|
+ Needs Open Lighting Arquitecture => 0.9.0.
|
||||||
+ Pure Data as audio engine
|
+ Pure Data as audio engine.
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<dmxSettings fileVersion="1" layersNumber="4" path="/home/snt/Documentos/lab/lms/media/sound">
|
<lmsAudio ui="1" layersNumber="4" path="../media/sound" >
|
||||||
<audioDevice id="3" />
|
<audioDevice devicesNumber="2" id0="3" id1="4" />
|
||||||
<layer0 dmx="1" universe="1" />
|
<layer id="0" dmx="1" universe="1" />
|
||||||
<layer1 dmx="17" universe="1" />
|
<layer id="1" dmx="17" universe="1" />
|
||||||
<layer2 dmx="33" universe="1" />
|
<layer id="2" dmx="33" universe="1" />
|
||||||
<layer3 dmx="49" universe="1" />
|
<layer id="3" dmx="49" universe="1" />
|
||||||
</dmxSettings>
|
</lmsAudio>
|
||||||
|
|
|
@ -5,7 +5,6 @@ https://git.criptomart.net/libremediaserver
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
|
|
||||||
Libre Media Server Roadmap
|
Libre Media Server Roadmap
|
||||||
(en continuo crecimiento...)
|
|
||||||
|
|
||||||
v 0.2.x
|
v 0.2.x
|
||||||
- skin, UI/UX
|
- skin, UI/UX
|
||||||
|
@ -20,8 +19,8 @@ v 0.2.2
|
||||||
+ hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente.
|
+ hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente.
|
||||||
+ https://github.com/ETCLabs/sACN
|
+ https://github.com/ETCLabs/sACN
|
||||||
- Qt6.
|
- Qt6.
|
||||||
- audio processing (eq, rev, compresor, ...) por master y capa.
|
- Audio processing (eq, rev, compresor, ...) by master and layer.
|
||||||
- CIPT/MSex, send icons play-pause-stop.
|
- CIPT/MSex, send icons play/pause/stop.
|
||||||
- Rasp build.
|
- Rasp build.
|
||||||
- Octopus Sound Card support (6 outputs - 8 inputs).
|
- Octopus Sound Card support (6 outputs - 8 inputs).
|
||||||
|
|
||||||
|
@ -41,15 +40,15 @@ v 0.2.1
|
||||||
- audio device linked, outputs will be redirected there.
|
- audio device linked, outputs will be redirected there.
|
||||||
- dmx address + universe settings.
|
- dmx address + universe settings.
|
||||||
- Rose noise and sine generator in menu to test system.
|
- Rose noise and sine generator in menu to test system.
|
||||||
- Keyboards strokes, load media files from ui.
|
- Ui/Ux; Keyboards strokes.
|
||||||
- Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante.
|
- Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante.
|
||||||
- Logs, verbosity, timestamp.
|
- Logs, verbosity, timestamp.
|
||||||
- Bufgix: depurar errores cuando no carga la librería de medias, cambia el númmero de capas, cambia el universo, etc.
|
- New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH
|
||||||
- New control mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH
|
|
||||||
- Vumeter or indicator about audio output in layer and master.
|
|
||||||
- SettingsDialog.
|
- SettingsDialog.
|
||||||
- Load/save conf file.
|
- Load/save conf file.
|
||||||
- ¿stop offset? is it needed?
|
- ¿Exit Point? is it needed?
|
||||||
- decouple MiniAudioEngine from AudioWidget, starts whith no gui or with audio in a dedicated thread.
|
- Hardening: check return errors, try/catch exceptions, i'm too happy....
|
||||||
- New Status "Iddle" in playbacks if is not loaded.
|
- Tests: errors on wrong conf file.
|
||||||
- check return errors, we are too happy....
|
|
||||||
|
v0.2.0:
|
||||||
|
- Vumeter or indicator about audio output in layer and master, add to sliderGroup.
|
||||||
|
|
|
@ -2,7 +2,10 @@ TEMPLATE = app
|
||||||
TARGET = libremediaserver-audio
|
TARGET = libremediaserver-audio
|
||||||
QT += webkitwidgets widgets
|
QT += webkitwidgets widgets
|
||||||
HEADERS += src/libremediaserver-audio.h \
|
HEADERS += src/libremediaserver-audio.h \
|
||||||
|
src/clickablelabel.h \
|
||||||
src/dmxwidget.h \
|
src/dmxwidget.h \
|
||||||
|
src/libremediaserver-audio-gui.h \
|
||||||
|
src/main.h \
|
||||||
src/miniaudio.h \
|
src/miniaudio.h \
|
||||||
src/medialibrary.h \
|
src/medialibrary.h \
|
||||||
src/miniaudioengine.h \
|
src/miniaudioengine.h \
|
||||||
|
@ -14,7 +17,9 @@ HEADERS += src/libremediaserver-audio.h \
|
||||||
src/settings.h \
|
src/settings.h \
|
||||||
src/slidergroup.h
|
src/slidergroup.h
|
||||||
SOURCES += src/main.cpp \
|
SOURCES += src/main.cpp \
|
||||||
|
src/clickablelabel.cpp \
|
||||||
src/dmxwidget.cpp \
|
src/dmxwidget.cpp \
|
||||||
|
src/libremediaserver-audio-gui.cpp \
|
||||||
src/miniaudio.c \
|
src/miniaudio.c \
|
||||||
src/libremediaserver-audio.cpp \
|
src/libremediaserver-audio.cpp \
|
||||||
src/medialibrary.cpp \
|
src/medialibrary.cpp \
|
||||||
|
@ -24,10 +29,10 @@ SOURCES += src/main.cpp \
|
||||||
src/audiowidget.cpp \
|
src/audiowidget.cpp \
|
||||||
src/settings.cpp \
|
src/settings.cpp \
|
||||||
src/slidergroup.cpp
|
src/slidergroup.cpp
|
||||||
FORMS += src/libremediaserver-audio.ui
|
FORMS += src/libremediaserver-audio-gui.ui
|
||||||
CCFLAG += -msse2 -mavx2 #-fsanitize=address -g -O0
|
CCFLAG += -msse2 -mavx2 #-fsanitize=address -g3 -O0
|
||||||
QMAKE_CXXFLAGS += $$(CXXFLAG)
|
QMAKE_CXXFLAGS += $$(CXXFLAG)
|
||||||
#QMAKE_CXXFLAGS += -fsanitize=address -g -O0
|
#QMAKE_CXXFLAGS += -fsanitize=address -g3 -O0
|
||||||
QMAKE_CFLAGS += $$(CCFLAG)
|
QMAKE_CFLAGS += $$(CCFLAG)
|
||||||
QMAKE_LFLAGS += $$(LDFLAG)
|
QMAKE_LFLAGS += $$(LDFLAG)
|
||||||
LIBS += -lola -lolacommon -ldl -lpthread -lm
|
LIBS += -lola -lolacommon -ldl -lpthread -lm
|
||||||
|
|
|
@ -1,64 +1,89 @@
|
||||||
#include "audiolayerwidget.h"
|
#include "audiolayerwidget.h"
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
|
||||||
AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer):
|
QWidget(parent)
|
||||||
QGroupBox(parent)
|
|
||||||
, m_layer(layer)
|
, m_layer(layer)
|
||||||
, m_suspendResumeButton(0)
|
, m_suspendResumeButton(0)
|
||||||
{
|
{
|
||||||
this->setTitle(name);
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
|
||||||
QHBoxLayout *progressTime = new QHBoxLayout;
|
QVBoxLayout *playback = new QVBoxLayout;
|
||||||
m_progressTime = new QTimeEdit;
|
m_folderValue = new ClickableLabel;
|
||||||
m_progressTime->text();
|
m_folderValue->setMaximumWidth(160);
|
||||||
m_progressTime->setDisplayFormat("h:mm:ss:zzz");
|
m_folderValue->setAlignment(Qt::AlignLeft);
|
||||||
m_progressTime->setReadOnly(true);
|
m_folderValue->setStyleSheet(
|
||||||
m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
"color: white;"
|
||||||
m_progressTime->setMaximumWidth(90);
|
"background-color: black;"
|
||||||
m_progressTime->setFocusPolicy(Qt::NoFocus);
|
);
|
||||||
progressTime->addWidget(m_progressTime);
|
playback->addWidget(m_folderValue);
|
||||||
m_totalTimeValue = new QTimeEdit;
|
m_fileValue = new ClickableLabel;
|
||||||
m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz");
|
connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog()));
|
||||||
m_totalTimeValue->setReadOnly(true);
|
connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog()));
|
||||||
m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
m_fileValue->setMaximumWidth(160);
|
||||||
m_totalTimeValue->setMaximumWidth(90);
|
m_fileValue->setAlignment(Qt::AlignLeft);
|
||||||
m_totalTimeValue->setFocusPolicy(Qt::NoFocus);
|
m_fileValue->setStyleSheet(
|
||||||
progressTime->addWidget(m_totalTimeValue);
|
"color: white;"
|
||||||
layout->addLayout(progressTime);
|
"background-color: black;"
|
||||||
|
);
|
||||||
m_progressSlider = new QSlider(Qt::Horizontal);
|
playback->addWidget(m_fileValue);
|
||||||
m_progressSlider->setFocusPolicy(Qt::NoFocus);
|
playback->setSpacing(0);
|
||||||
layout->addWidget(m_progressSlider);
|
playback->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->addLayout(playback);
|
||||||
QGridLayout *status = new QGridLayout;
|
|
||||||
m_statusValue = new QLabel;
|
|
||||||
status->addWidget(m_statusValue, 0, 0);
|
|
||||||
m_folderValue = new QLabel;
|
|
||||||
m_folderValue->setMaximumWidth(200);
|
|
||||||
status->addWidget(m_folderValue, 1, 0);
|
|
||||||
m_fileValue = new QLabel;
|
|
||||||
m_fileValue->setMaximumWidth(200);
|
|
||||||
status->addWidget(m_fileValue, 2, 0);
|
|
||||||
layout->addLayout(status);
|
|
||||||
|
|
||||||
QHBoxLayout *volumeBox = new QHBoxLayout;
|
|
||||||
m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL);
|
|
||||||
volumeBox->addWidget(m_volume);
|
|
||||||
connect(m_volume, SIGNAL(valueChanged(float)), this, SLOT(volumeChanged(float)));
|
|
||||||
m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL);
|
|
||||||
volumeBox->addWidget(m_pan);
|
|
||||||
connect(m_pan, SIGNAL(valueChanged(float)), this, SLOT(panChanged(float)));
|
|
||||||
m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL);
|
|
||||||
volumeBox->addWidget(m_pitch);
|
|
||||||
connect(m_pitch, SIGNAL(valueChanged(float)), this, SLOT(pitchChanged(float)));
|
|
||||||
layout->addLayout(volumeBox);
|
|
||||||
|
|
||||||
m_suspendResumeButton = new QPushButton(this);
|
m_suspendResumeButton = new QPushButton(this);
|
||||||
m_suspendResumeButton->setText(StatusStr[Status::Stopped]);
|
m_suspendResumeButton->setText(StatusStr[Status::Iddle]);
|
||||||
connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume()));
|
connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume()));
|
||||||
layout->addWidget(m_suspendResumeButton);
|
layout->addWidget(m_suspendResumeButton);
|
||||||
|
|
||||||
|
m_progress = new QProgressBar(this);
|
||||||
|
m_progress->setOrientation(Qt::Horizontal);
|
||||||
|
m_progress->setRange(0, 0);
|
||||||
|
m_progress->setValue(0);
|
||||||
|
m_progress->setFormat("%v / %m");
|
||||||
|
layout->addWidget(m_progress);
|
||||||
|
|
||||||
|
m_progressTime = new QTimeEdit;
|
||||||
|
m_progressTime->setToolTip("Current Time");
|
||||||
|
m_progressTime->setObjectName("Current Time");
|
||||||
|
m_progressTime->setDisplayFormat("mm:ss:zz");
|
||||||
|
m_progressTime->setReadOnly(true);
|
||||||
|
m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||||||
|
m_progressTime->setMinimumWidth(80);
|
||||||
|
m_progressTime->setMaximumWidth(80);
|
||||||
|
m_progressTime->setFocusPolicy(Qt::NoFocus);
|
||||||
|
m_progressTime->setAlignment(Qt::AlignHCenter);
|
||||||
|
m_progressTime->setContentsMargins(0,0,0,0);
|
||||||
|
m_totalTimeValue = new QTimeEdit;
|
||||||
|
m_totalTimeValue->setObjectName("Track Length");
|
||||||
|
m_totalTimeValue->setToolTip("Track Length");
|
||||||
|
m_totalTimeValue->setDisplayFormat("mm:ss:zzz");
|
||||||
|
m_totalTimeValue->setReadOnly(true);
|
||||||
|
m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||||||
|
m_totalTimeValue->setMinimumWidth(80);
|
||||||
|
m_totalTimeValue->setFocusPolicy(Qt::NoFocus);
|
||||||
|
m_totalTimeValue->setAlignment(Qt::AlignHCenter);
|
||||||
|
m_totalTimeValue->setContentsMargins(0,0,0,0);
|
||||||
|
QHBoxLayout *status = new QHBoxLayout;
|
||||||
|
status->addWidget(m_progressTime);
|
||||||
|
status->addWidget(m_totalTimeValue);
|
||||||
|
layout->addLayout(status);
|
||||||
|
QHBoxLayout *volumeBox = new QHBoxLayout;
|
||||||
|
m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL);
|
||||||
|
volumeBox->addWidget(m_volume);
|
||||||
|
connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
|
||||||
|
m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL);
|
||||||
|
volumeBox->addWidget(m_pan);
|
||||||
|
connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int)));
|
||||||
|
m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL);
|
||||||
|
volumeBox->addWidget(m_pitch);
|
||||||
|
volumeBox->setSpacing(0);
|
||||||
|
volumeBox->setContentsMargins(0, 0, 0, 0);
|
||||||
|
connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int)));
|
||||||
|
layout->addLayout(volumeBox);
|
||||||
|
layout->setAlignment(Qt::AlignHCenter);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setContentsMargins(2, 2, 2, 2);
|
||||||
this->setLayout(layout);
|
this->setLayout(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,17 +93,17 @@ AudioLayerWidget::~AudioLayerWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
// From UI.
|
// From UI.
|
||||||
void AudioLayerWidget::volumeChanged(float value)
|
void AudioLayerWidget::volumeChanged(int value)
|
||||||
{
|
{
|
||||||
emit(uiSliderChanged(m_layer, Slider::Volume, value));
|
emit(uiSliderChanged(m_layer, Slider::Volume, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::panChanged(float value)
|
void AudioLayerWidget::panChanged(int value)
|
||||||
{
|
{
|
||||||
emit(uiSliderChanged(m_layer, Slider::Pan, value));
|
emit(uiSliderChanged(m_layer, Slider::Pan, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::pitchChanged(float value)
|
void AudioLayerWidget::pitchChanged(int value)
|
||||||
{
|
{
|
||||||
emit(uiSliderChanged(m_layer, Slider::Pitch, value));
|
emit(uiSliderChanged(m_layer, Slider::Pitch, value));
|
||||||
}
|
}
|
||||||
|
@ -93,12 +118,28 @@ void AudioLayerWidget::toggleSuspendResume()
|
||||||
break;
|
break;
|
||||||
case Status::Paused:
|
case Status::Paused:
|
||||||
case Status::Stopped:
|
case Status::Stopped:
|
||||||
this->setPlaybackStatus(Status::PlayingOnce);
|
this->setPlaybackStatus(Status::PlayingLoop);
|
||||||
emit uiPlaybackChanged(m_layer, Status::PlayingOnce);
|
emit uiPlaybackChanged(m_layer, Status::PlayingLoop);
|
||||||
|
case Status::Iddle:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::openMediaDialog()
|
||||||
|
{
|
||||||
|
QFileDialog dialog(this);
|
||||||
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
dialog.setNameFilter(tr("Sound Tracks (*.mp3 *.mp3 *.flac *.wav"));
|
||||||
|
dialog.setViewMode(QFileDialog::Detail);
|
||||||
|
dialog.setDirectory(Settings::getInstance()->getPathMedia());
|
||||||
|
if (!dialog.exec())
|
||||||
|
return;
|
||||||
|
QStringList fileNames;
|
||||||
|
fileNames = dialog.selectedFiles();
|
||||||
|
emit uiLoadMedia(m_layer, fileNames.at(0));
|
||||||
|
this->setMediaFile(fileNames.at(0));
|
||||||
|
}
|
||||||
|
|
||||||
// from DMX signals
|
// from DMX signals
|
||||||
void AudioLayerWidget::setVol(float vol)
|
void AudioLayerWidget::setVol(float vol)
|
||||||
{
|
{
|
||||||
|
@ -121,7 +162,7 @@ void AudioLayerWidget::setPitch(int pitch)
|
||||||
m_pitch->blockSignals(false);
|
m_pitch->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::fileLoaded(QString file)
|
void AudioLayerWidget::setMediaFile(QString file)
|
||||||
{
|
{
|
||||||
QStringList list = file.split("/");
|
QStringList list = file.split("/");
|
||||||
int size = list.size();
|
int size = list.size();
|
||||||
|
@ -131,41 +172,36 @@ void AudioLayerWidget::fileLoaded(QString file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::setPlaybackStatus(Status status)
|
void AudioLayerWidget::setPlaybackStatus(Status s)
|
||||||
{
|
{
|
||||||
m_status = status;
|
Status status = static_cast<Status>(s);
|
||||||
if (status == Status::Stopped)
|
|
||||||
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0));
|
|
||||||
m_statusValue->blockSignals(true);
|
|
||||||
m_suspendResumeButton->blockSignals(true);
|
m_suspendResumeButton->blockSignals(true);
|
||||||
m_statusValue->setText(StatusStr[status]);
|
m_status = status;
|
||||||
m_suspendResumeButton->setText(StatusStr[status]);
|
m_suspendResumeButton->setText(StatusStr[status]);
|
||||||
switch (m_status) {
|
|
||||||
case Status::Paused:
|
|
||||||
m_statusValue->setStyleSheet("QLabel { color : red; }");
|
|
||||||
break;
|
|
||||||
case Status::PlayingLoop:
|
|
||||||
case Status::PlayingOnce:
|
|
||||||
m_statusValue->setStyleSheet("QLabel { color : green; }");
|
|
||||||
break;
|
|
||||||
case Status::Stopped:
|
|
||||||
m_statusValue->setStyleSheet("QLabel { color : red; }");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
m_statusValue->blockSignals(false);
|
|
||||||
m_suspendResumeButton->blockSignals(false);
|
m_suspendResumeButton->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::durationChanged(float dur)
|
void AudioLayerWidget::setDuration(float dur)
|
||||||
{
|
{
|
||||||
dur *= 1000;
|
m_progress->blockSignals(true);
|
||||||
m_progressSlider->setMaximum(dur);
|
m_progressTime->blockSignals(true);
|
||||||
|
m_totalTimeValue->blockSignals(true);
|
||||||
|
m_progress->setRange(0, dur);
|
||||||
|
m_progress->setValue(0);
|
||||||
|
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0));
|
||||||
m_totalTimeValue->setTime(QTime::fromMSecsSinceStartOfDay(dur));
|
m_totalTimeValue->setTime(QTime::fromMSecsSinceStartOfDay(dur));
|
||||||
|
m_progress->blockSignals(false);
|
||||||
|
m_progressTime->blockSignals(false);
|
||||||
|
m_totalTimeValue->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::refreshUi(float progress)
|
void AudioLayerWidget::setCurrentTime(float progress)
|
||||||
{
|
{
|
||||||
progress *= 1000;
|
progress *= 1000;
|
||||||
m_progressSlider->setValue(progress);
|
m_progress->blockSignals(true);
|
||||||
|
m_progressTime->blockSignals(true);
|
||||||
|
m_progress->setValue(progress);
|
||||||
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress));
|
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress));
|
||||||
|
m_progress->blockSignals(false);
|
||||||
|
m_progressTime->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,53 +3,57 @@
|
||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTimeEdit>
|
#include <QTimeEdit>
|
||||||
#include <QLabel>
|
#include <QFileDialog>
|
||||||
|
#include <QProgressBar>
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "slidergroup.h"
|
#include "slidergroup.h"
|
||||||
|
#include "clickablelabel.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
class AudioLayerWidget : public QGroupBox
|
class AudioLayerWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer", int layer = 0);
|
explicit AudioLayerWidget(QWidget *parent = 0, int layer = 0);
|
||||||
~AudioLayerWidget();
|
~AudioLayerWidget();
|
||||||
void setVol(float vol);
|
|
||||||
void resume();
|
|
||||||
void setPan(int pan);
|
|
||||||
void setPitch(int pitch);
|
|
||||||
void setLoop(bool on);
|
|
||||||
void setPlaybackStatus(Status status);
|
|
||||||
inline Status getPlaybackStatus() { return m_status; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Status m_status;
|
Status m_status;
|
||||||
int m_layer;
|
int m_layer;
|
||||||
QPushButton *m_suspendResumeButton;
|
QPushButton *m_suspendResumeButton;
|
||||||
QLabel * m_statusValue;
|
ClickableLabel *m_fileValue;
|
||||||
QLabel *m_fileValue;
|
ClickableLabel * m_folderValue;
|
||||||
QLabel * m_folderValue;
|
|
||||||
SliderGroup *m_volume;
|
SliderGroup *m_volume;
|
||||||
SliderGroup *m_pan;
|
SliderGroup *m_pan;
|
||||||
SliderGroup *m_pitch;
|
SliderGroup *m_pitch;
|
||||||
QSlider *m_progressSlider;
|
|
||||||
QTimeEdit *m_progressTime;
|
QTimeEdit *m_progressTime;
|
||||||
QTimeEdit *m_totalTimeValue;
|
QTimeEdit *m_totalTimeValue;
|
||||||
|
QProgressBar *m_progress;
|
||||||
|
|
||||||
|
// From DMX
|
||||||
public slots:
|
public slots:
|
||||||
|
void setMediaFile(QString file);
|
||||||
|
void setDuration(float dur);
|
||||||
|
void setCurrentTime(float progress);
|
||||||
|
void setPlaybackStatus(Status status);
|
||||||
|
void setVol(float vol);
|
||||||
|
void setPan(int pan);
|
||||||
|
void setPitch(int pitch);
|
||||||
|
|
||||||
|
// From Ui
|
||||||
|
private slots:
|
||||||
|
void openMediaDialog();
|
||||||
void toggleSuspendResume();
|
void toggleSuspendResume();
|
||||||
void volumeChanged(float vol);
|
void volumeChanged(int vol);
|
||||||
void panChanged(float pan);
|
void panChanged(int pan);
|
||||||
void pitchChanged(float pitch);
|
void pitchChanged(int pitch);
|
||||||
void fileLoaded(QString file);
|
|
||||||
void durationChanged(float dur);
|
|
||||||
void refreshUi(float progress);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void uiPlaybackChanged(int layer, Status s);
|
void uiPlaybackChanged(int layer, Status s);
|
||||||
void uiSliderChanged(int layer, Slider s, int value);
|
void uiSliderChanged(int layer, Slider s, int value);
|
||||||
|
void uiLoadMedia(int layer, QString s);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIOLAYERWIDGET_H
|
#endif // AUDIOLAYERWIDGET_H
|
||||||
|
|
|
@ -1,121 +1,100 @@
|
||||||
#include "audiowidget.h"
|
#include "audiowidget.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
AudioWidget::AudioWidget(QWidget *parent) :
|
||||||
AudioWidget::AudioWidget() :
|
QWidget(parent)
|
||||||
m_layout(new QHBoxLayout())
|
, m_layout(new QHBoxLayout())
|
||||||
, m_refreshUi(new QTimer(this))
|
|
||||||
{
|
{
|
||||||
for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) {
|
for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) {
|
||||||
AudioLayerWidget *alw = new AudioLayerWidget(this, tr("Layer %1").arg(i + 1), i);
|
AudioLayerWidget *alw = new AudioLayerWidget(this, i);
|
||||||
m_layout->insertWidget(i, alw);
|
m_layout->insertWidget(i, alw);
|
||||||
connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderAction(int, Slider, int)));
|
connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SIGNAL(uiSliderChanged(int, Slider, int)));
|
||||||
connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiChangePlaybackStatus(int, Status)));
|
connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SIGNAL(uiPlaybackChanged(int, Status)));
|
||||||
|
connect(alw, SIGNAL(uiLoadMedia(int, QString)), this, SIGNAL(uiLoadMedia(int, QString)));
|
||||||
|
m_layerUpdate[i].status = Status::Iddle;
|
||||||
|
m_layerUpdate[i].duration = 0;
|
||||||
|
m_layerUpdate[i].media = "";
|
||||||
|
m_layerUpdate[i].vol = 0;
|
||||||
|
m_layerUpdate[i].pan = 128;
|
||||||
|
m_layerUpdate[i].pitch = 128;
|
||||||
|
m_layerUpdate[i].cursor = 0;
|
||||||
}
|
}
|
||||||
|
m_layout->setSpacing(0);
|
||||||
|
m_layout->setContentsMargins(1, 1, 1, 1);
|
||||||
setLayout(m_layout);
|
setLayout(m_layout);
|
||||||
|
m_refreshUi = new QTimer(this);
|
||||||
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
|
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
|
||||||
m_refreshUi->start(UI_REFRESH_TIME);
|
m_refreshUi->start(UI_REFRESH_TIME * 1.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioWidget::startEngine(int id)
|
void AudioWidget::mediaLoaded(int layer, QString file, float duration)
|
||||||
{
|
{
|
||||||
return (m_mae.startEngine(id));
|
m_layerUpdate[layer].media = file;
|
||||||
}
|
m_layerUpdate[layer].duration = duration;
|
||||||
|
m_layerUpdate[layer].updated = true;
|
||||||
bool AudioWidget::startEngine()
|
|
||||||
{
|
|
||||||
return (m_mae.startEngine(Settings::getInstance()->getAudioDeviceId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioWidget::stopEngine()
|
|
||||||
{
|
|
||||||
m_mae.stopEngine();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioWidget::mediaLoaded(int layer, QString file)
|
|
||||||
{
|
|
||||||
ma_result result;
|
|
||||||
|
|
||||||
if (m_currentMedia[layer].compare(file) == 0 ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!QFile::exists(file)) {
|
|
||||||
qWarning("Can not access to file %s", file.toLatin1().constData());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result = m_mae.loadMedia(layer, file.toLatin1().data());
|
|
||||||
if (result != MA_SUCCESS) {
|
|
||||||
qWarning("can not open file %s", file.toLatin1().constData());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_currentMedia[layer] = file;
|
|
||||||
float pLength = m_mae.getDuration(layer);
|
|
||||||
qInfo("File loaded: %s - Duration: %f secs", file.toLatin1().constData(), pLength);
|
|
||||||
m_mae.printFormatInfo(layer);
|
|
||||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
|
||||||
dynamic_cast<AudioLayerWidget *>(item->widget())->fileLoaded(file);
|
|
||||||
dynamic_cast<AudioLayerWidget *>(item->widget())->durationChanged(pLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::volChanged(int layer, float vol) {
|
void AudioWidget::volChanged(int layer, float vol) {
|
||||||
m_mae.volChanged(layer, vol);
|
m_layerUpdate[layer].vol = vol;
|
||||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
m_layerUpdate[layer].updated = true;
|
||||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setVol(vol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::panChanged(int layer, int pan) {
|
void AudioWidget::panChanged(int layer, int pan) {
|
||||||
m_mae.panChanged(layer, pan);
|
m_layerUpdate[layer].pan = pan;
|
||||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
m_layerUpdate[layer].updated = true;
|
||||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPan(pan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::pitchChanged(int layer, int pitch) {
|
void AudioWidget::pitchChanged(int layer, int pitch) {
|
||||||
m_mae.pitchChanged(layer, pitch);
|
|
||||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
m_layerUpdate[layer].pitch = pitch;
|
||||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPitch(pitch);
|
m_layerUpdate[layer].updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::playbackChanged(int layer, Status status)
|
void AudioWidget::playbackChanged(int layer, Status status)
|
||||||
{
|
{
|
||||||
m_mae.playbackChanged(layer, status);
|
m_layerUpdate[layer].status = status;
|
||||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
m_layerUpdate[layer].updated = true;
|
||||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPlaybackStatus(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::entryPointChanged(int layer, int cursor)
|
void AudioWidget::cursorChanged(int layer, float cursor)
|
||||||
{
|
{
|
||||||
m_mae.setCursor(layer, cursor);
|
m_layerUpdate[layer].cursor = cursor;
|
||||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
m_layerUpdate[layer].updated = true;
|
||||||
AudioLayerWidget *aw = dynamic_cast<AudioLayerWidget *>(item->widget());
|
|
||||||
aw->refreshUi(m_mae.getCursor(layer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::refreshUi() {
|
void AudioWidget::refreshUi()
|
||||||
for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) {
|
{
|
||||||
QLayoutItem * const item = m_layout->itemAt(i);
|
for (int i = 0; i < MAX_LAYERS; i++)
|
||||||
AudioLayerWidget *aw = dynamic_cast<AudioLayerWidget *>(item->widget());
|
{
|
||||||
Status s = aw->getPlaybackStatus();
|
if (m_layerUpdate[i].updated) {
|
||||||
if (s == Status::PlayingOnce || s == Status::PlayingLoop) {
|
QLayoutItem * const item = m_layout->itemAt(i);
|
||||||
aw->refreshUi(m_mae.getCursor(i));
|
AudioLayerWidget *alw = dynamic_cast<AudioLayerWidget *>(item->widget());
|
||||||
|
if (m_layerUpdate[i].vol > -1) {
|
||||||
|
alw->setVol(m_layerUpdate[i].vol);
|
||||||
|
m_layerUpdate[i].vol = -1;
|
||||||
|
}
|
||||||
|
if (m_layerUpdate[i].cursor > -1) {
|
||||||
|
alw->setCurrentTime(m_layerUpdate[i].cursor);
|
||||||
|
m_layerUpdate[i].cursor = -1;
|
||||||
|
}
|
||||||
|
if (m_layerUpdate[i].pan > -1) {
|
||||||
|
alw->setPan(m_layerUpdate[i].pan);
|
||||||
|
m_layerUpdate[i].pan = -1;
|
||||||
|
}
|
||||||
|
if (m_layerUpdate[i].pitch > -1) {
|
||||||
|
alw->setPitch(m_layerUpdate[i].pitch);
|
||||||
|
m_layerUpdate[i].pitch = -1;
|
||||||
|
}
|
||||||
|
if (m_layerUpdate[i].status != Status::Iddle) {
|
||||||
|
alw->setPlaybackStatus(m_layerUpdate[i].status);
|
||||||
|
m_layerUpdate[i].status = Status::Iddle;
|
||||||
|
}
|
||||||
|
if (m_layerUpdate[i].duration > -1) {
|
||||||
|
alw->setMediaFile(m_layerUpdate[i].media);
|
||||||
|
alw->setDuration(m_layerUpdate[i].duration);
|
||||||
|
m_layerUpdate[i].duration = -1;
|
||||||
|
}
|
||||||
|
m_layerUpdate[i].updated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::uiSliderAction(int layer, Slider s, int value)
|
|
||||||
{
|
|
||||||
switch (s){
|
|
||||||
case Slider::Volume:
|
|
||||||
m_mae.volChanged(layer, value);
|
|
||||||
break;
|
|
||||||
case Slider::Pan:
|
|
||||||
m_mae.panChanged(layer, value);
|
|
||||||
break;
|
|
||||||
case Slider::Pitch:
|
|
||||||
m_mae.pitchChanged(layer, value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioWidget::uiChangePlaybackStatus(int layer, Status s) {
|
|
||||||
m_mae.playbackChanged(layer, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include "audiolayerwidget.h"
|
#include "audiolayerwidget.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "miniaudioengine.h"
|
|
||||||
#include "defines.h" // MAX_LAYERS
|
#include "defines.h" // MAX_LAYERS
|
||||||
|
|
||||||
class AudioWidget : public QWidget
|
class AudioWidget : public QWidget
|
||||||
|
@ -13,29 +12,27 @@ class AudioWidget : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioWidget();
|
AudioWidget(QWidget *parent = nullptr);
|
||||||
bool startEngine();
|
|
||||||
bool startEngine(int id);
|
|
||||||
void stopEngine();
|
|
||||||
void mediaLoaded(int layer, QString media );
|
|
||||||
void volChanged(int layer, float vol);
|
|
||||||
void panChanged(int layer, int pan);
|
|
||||||
void pitchChanged(int layer, int pitch);
|
|
||||||
void playbackChanged(int layer, Status status);
|
|
||||||
void entryPointChanged(int layer, int cursor);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MiniAudioEngine m_mae;
|
|
||||||
QString m_currentMedia[MAX_LAYERS];
|
|
||||||
QHBoxLayout *m_layout;
|
QHBoxLayout *m_layout;
|
||||||
|
layerData m_layerUpdate[MAX_LAYERS];
|
||||||
QTimer *m_refreshUi;
|
QTimer *m_refreshUi;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void uiSliderAction(int layer, Slider s, int value);
|
void volChanged(int layer, float vol);
|
||||||
void uiChangePlaybackStatus(int layer, Status s);
|
void panChanged(int layer, int pan);
|
||||||
|
void pitchChanged(int layer, int pitch);
|
||||||
|
void cursorChanged(int layer, float cursor);
|
||||||
|
void mediaLoaded(int layer, QString media, float duration);
|
||||||
|
void playbackChanged(int layer, Status status);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void refreshUi();
|
void refreshUi();
|
||||||
|
signals:
|
||||||
|
void uiPlaybackChanged(int layer, Status s);
|
||||||
|
void uiSliderChanged(int layer, Slider s, int vol);
|
||||||
|
void uiLoadMedia(int layer, QString s);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIOWIDGET_H
|
#endif // AUDIOWIDGET_H
|
||||||
|
|
14
src/clickablelabel.cpp
Normal file
14
src/clickablelabel.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "clickablelabel.h"
|
||||||
|
|
||||||
|
ClickableLabel::ClickableLabel(QWidget *parent, Qt::WindowFlags f)
|
||||||
|
: QLabel{parent}
|
||||||
|
{
|
||||||
|
Q_UNUSED(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClickableLabel::~ClickableLabel() {}
|
||||||
|
|
||||||
|
void ClickableLabel::mousePressEvent(QMouseEvent* event) {
|
||||||
|
Q_UNUSED(event);
|
||||||
|
emit clicked();
|
||||||
|
}
|
22
src/clickablelabel.h
Normal file
22
src/clickablelabel.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef CLICKABLELABEL_H
|
||||||
|
#define CLICKABLELABEL_H
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <Qt>
|
||||||
|
|
||||||
|
class ClickableLabel : public QLabel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ClickableLabel(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
||||||
|
~ClickableLabel();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void clicked();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CLICKABLELABEL_H
|
|
@ -1,15 +1,15 @@
|
||||||
#ifndef DEFINES_H
|
#ifndef DEFINES_H
|
||||||
#define DEFINES_H
|
#define DEFINES_H
|
||||||
|
|
||||||
//#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release"
|
#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release"
|
||||||
#define VERSION "Kike Substitutor - No AI required - v0.2.0"
|
|
||||||
#define COPYRIGHT "(C) 2014-2024 Santi Noreña <lms@criptomart.net>"
|
#define COPYRIGHT "(C) 2014-2024 Santi Noreña <lms@criptomart.net>"
|
||||||
#define LICENSE "GPL 3 Licensed. See LICENSE.txt.\nSound guys are not allowed to use this software."
|
#define LICENSE "GPL 3 Licensed. See LICENSE.txt."
|
||||||
#define DEFAULT_FILE "lms-audio.xlm"
|
#define DEFAULT_FILE "lms-audio.xlm"
|
||||||
#define MAX_LAYERS 16
|
#define MAX_LAYERS 4
|
||||||
#define UI_REFRESH_TIME 200
|
#define MAX_AUDIODEVICES 8
|
||||||
|
#define UI_REFRESH_TIME 66
|
||||||
|
#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks
|
||||||
|
|
||||||
// struct where save the DMX settings for each layer
|
|
||||||
struct dmxSetting {
|
struct dmxSetting {
|
||||||
int address;
|
int address;
|
||||||
unsigned int universe;
|
unsigned int universe;
|
||||||
|
@ -22,6 +22,10 @@ enum Status
|
||||||
Paused,
|
Paused,
|
||||||
PlayingOnce,
|
PlayingOnce,
|
||||||
PlayingLoop,
|
PlayingLoop,
|
||||||
|
Iddle,
|
||||||
|
PlayingFolder,
|
||||||
|
PlayingFolderLoop,
|
||||||
|
PlayingFolderRandom
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* StatusStr[] =
|
static const char* StatusStr[] =
|
||||||
|
@ -29,7 +33,11 @@ static const char* StatusStr[] =
|
||||||
"Stop",
|
"Stop",
|
||||||
"Pause",
|
"Pause",
|
||||||
"Playing One",
|
"Playing One",
|
||||||
"Playing Loop",
|
"Playing One Loop",
|
||||||
|
"Iddle",
|
||||||
|
"Playing Folder",
|
||||||
|
"Playing Folder Loop",
|
||||||
|
"Playing Folder Random",
|
||||||
0x0
|
0x0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,5 +48,18 @@ enum Slider
|
||||||
Pitch,
|
Pitch,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
struct layerData {
|
||||||
|
QString media;
|
||||||
|
Status status;
|
||||||
|
bool updated;
|
||||||
|
float vol;
|
||||||
|
float cursor;
|
||||||
|
int pan;
|
||||||
|
int pitch;
|
||||||
|
float duration;
|
||||||
|
int address;
|
||||||
|
unsigned int universe;
|
||||||
|
int device;
|
||||||
|
};
|
||||||
#endif // DEFINES_H
|
#endif // DEFINES_H
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,15 @@
|
||||||
#ifndef DMXPERSONALITY_H
|
#ifndef DMXPERSONALITY_H
|
||||||
#define DMXPERSONALITY_H
|
#define DMXPERSONALITY_H
|
||||||
|
|
||||||
/** Define the DMX personality to avoid dealing with
|
#define VOLUME_COARSE 3
|
||||||
* numbers and change it easyly in case
|
#define PAN 6
|
||||||
*
|
#define DMX_FOLDER 0
|
||||||
1 - Volumen Coarse
|
#define DMX_FILE 1
|
||||||
2 - Pan
|
#define PLAYBACK 8
|
||||||
3 - Folder
|
#define VOLUME_FINE 2
|
||||||
4 - File
|
#define ENTRY_POINT_COARSE 5
|
||||||
5 - Playback
|
#define ENTRY_POINT_FINE 4
|
||||||
0-24 : Play once.
|
#define PITCH 7
|
||||||
25-49: Stop. Returns to start of file.
|
#define LAYER_CHANNELS 9
|
||||||
50-74: Pause. It keeps the time of reproductions.
|
|
||||||
75-99: Play loop.
|
|
||||||
6 - Control - Reservado, sin uso en este momento.
|
|
||||||
7 - Volume Fine
|
|
||||||
8 - Entry Point Coarse - Punto de entrada de reproducción.
|
|
||||||
9 - Entry Point Fine - El valor de estos dos canales en centésimas de segundo.
|
|
||||||
10 - Pan
|
|
||||||
11 - Pitch
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ToDo: Mejor inicializacion, primero folder, file, después params, ultimo playback.7
|
|
||||||
// quitar CONTROL no usado
|
|
||||||
#define VOLUME_COARSE 0
|
|
||||||
#define PAN 1
|
|
||||||
#define DMX_FOLDER 2
|
|
||||||
#define DMX_FILE 3
|
|
||||||
#define PLAYBACK 4
|
|
||||||
#define CONTROL 5
|
|
||||||
#define VOLUME_FINE 6
|
|
||||||
#define ENTRY_POINT_COARSE 7
|
|
||||||
#define ENTRY_POINT_FINE 8
|
|
||||||
#define PITCH 9
|
|
||||||
|
|
||||||
#define LAYER_CHANNELS 10
|
|
||||||
|
|
||||||
#endif // DMXPERSONALITY_H
|
#endif // DMXPERSONALITY_H
|
||||||
|
|
|
@ -9,6 +9,8 @@ dmxWidget::dmxWidget(QWidget *parent) :
|
||||||
QVBoxLayout *vbox = new QVBoxLayout;
|
QVBoxLayout *vbox = new QVBoxLayout;
|
||||||
m_receiveDMX->setText("DMX Signal");
|
m_receiveDMX->setText("DMX Signal");
|
||||||
vbox->addWidget(m_receiveDMX);
|
vbox->addWidget(m_receiveDMX);
|
||||||
|
vbox->setSpacing(1);
|
||||||
|
vbox->setContentsMargins(1, 1, 1, 1);
|
||||||
this->setLayout(vbox);
|
this->setLayout(vbox);
|
||||||
connect(m_watchDMX, SIGNAL(timeout()),
|
connect(m_watchDMX, SIGNAL(timeout()),
|
||||||
this, SLOT(watchDMXExpired()));
|
this, SLOT(watchDMXExpired()));
|
||||||
|
|
56
src/libremediaserver-audio-gui.cpp
Normal file
56
src/libremediaserver-audio-gui.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Libre Media Server Audio - An Open source Media Server for arts and performing.
|
||||||
|
(c) Criptomart - Santiago Noreña 2012-2024 <lms@criptomart.net>
|
||||||
|
https://git.criptomart.net/libremediaserver
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libremediaserver-audio-gui.h"
|
||||||
|
|
||||||
|
|
||||||
|
libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent)
|
||||||
|
: QMainWindow(parent)
|
||||||
|
{
|
||||||
|
ui.setupUi(this);
|
||||||
|
this->setWindowTitle(VERSION);
|
||||||
|
m_aw = new AudioWidget(this);
|
||||||
|
setCentralWidget(m_aw);
|
||||||
|
m_dmxWidget = new dmxWidget(this);
|
||||||
|
QDockWidget *topWidget = new QDockWidget(tr("Master"), this);
|
||||||
|
topWidget->setAllowedAreas(Qt::TopDockWidgetArea);
|
||||||
|
topWidget->setWidget(m_dmxWidget);
|
||||||
|
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->setStyleSheet(
|
||||||
|
"color: white;"
|
||||||
|
"background-color: #4f4048;"
|
||||||
|
"selection-color: blue;"
|
||||||
|
"selection-background-color: green"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
libreMediaServerAudioUi::~libreMediaServerAudioUi()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void libreMediaServerAudioUi::olasetup()
|
||||||
|
{
|
||||||
|
QWebView *view = new QWebView();
|
||||||
|
view->load(QUrl("http://localhost:9090/ola.html"));
|
||||||
|
view->show();
|
||||||
|
}
|
48
src/libremediaserver-audio-gui.h
Normal file
48
src/libremediaserver-audio-gui.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
Libre Media Server Audio - An Open source Media Server for arts and performing.
|
||||||
|
(c) Criptomart - Santiago Noreña 2012-2024 <lms@criptomart.net>
|
||||||
|
https://git.criptomart.net/libremediaserver
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBREMEDIASERVERAUDIOUI_H
|
||||||
|
#define LIBREMEDIASERVERAUDIOUI_H
|
||||||
|
|
||||||
|
#include <QDockWidget>
|
||||||
|
#include <QWebView>
|
||||||
|
|
||||||
|
#include "audiowidget.h"
|
||||||
|
#include "dmxwidget.h"
|
||||||
|
#include "defines.h"
|
||||||
|
#include "ui_libremediaserver-audio-gui.h"
|
||||||
|
|
||||||
|
class libreMediaServerAudioUi : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
libreMediaServerAudioUi(QWidget *parent = 0);
|
||||||
|
virtual ~libreMediaServerAudioUi();
|
||||||
|
AudioWidget *m_aw;
|
||||||
|
dmxWidget *m_dmxWidget;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::LibreMediaServerAudio ui;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void olasetup();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LIBREMEDIASERVERAUDIOUI_H
|
55
src/libremediaserver-audio-gui.ui
Normal file
55
src/libremediaserver-audio-gui.ui
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<author>Santi Noreña lms@criptomart.net</author>
|
||||||
|
<class>LibreMediaServerAudio</class>
|
||||||
|
<widget class="QMainWindow" name="LibreMediaServerAudio">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>400</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Unifont</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>LibreMediaServer</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>../../../../criptomart/artwork/logo_v2_criptomart.net.png</normaloff>../../../../criptomart/artwork/logo_v2_criptomart.net.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget"/>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionLaunch_OLA_Setup"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionLaunch_OLA_Setup">
|
||||||
|
<property name="text">
|
||||||
|
<string>OLA Setup</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -21,106 +21,239 @@
|
||||||
#include "libremediaserver-audio.h"
|
#include "libremediaserver-audio.h"
|
||||||
|
|
||||||
|
|
||||||
libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
libreMediaServerAudio::libreMediaServerAudio()
|
||||||
: QMainWindow(parent)
|
|
||||||
{
|
{
|
||||||
Q_UNUSED(args);
|
m_settings = Settings::getInstance();
|
||||||
qDebug() << VERSION;
|
m_settings->readFile();
|
||||||
qDebug() << COPYRIGHT;
|
m_ui = m_settings->getShowUi();
|
||||||
qDebug() << LICENSE;
|
|
||||||
ui.setupUi(this);
|
|
||||||
this->setWindowTitle(VERSION);
|
|
||||||
Settings *set = Settings::getInstance();
|
|
||||||
set->readFile();
|
|
||||||
m_mediaLibrary = new MediaLibrary;
|
m_mediaLibrary = new MediaLibrary;
|
||||||
m_mediaLibrary->initMediaLibrary();
|
m_mediaLibrary->initMediaLibrary();
|
||||||
m_aw = new AudioWidget;
|
for (int i = 0; i < MAX_LAYERS; i++) {
|
||||||
setCentralWidget(m_aw);
|
m_currentMedia[i] = "";
|
||||||
m_dmxWidget = new dmxWidget(this);
|
m_currentStatus[i] = Status::Iddle;
|
||||||
QDockWidget *topWidget = new QDockWidget(tr("Master"), this);
|
#ifdef NOGUI
|
||||||
topWidget->setAllowedAreas(Qt::TopDockWidgetArea);
|
m_updateUi[i][0] = -1;
|
||||||
topWidget->setWidget(m_dmxWidget);
|
m_updateUi[i][1] = -1;
|
||||||
addDockWidget(Qt::TopDockWidgetArea, topWidget);
|
m_updateUi[i][2] = -1;
|
||||||
m_ola = new olaThread(this, set->getLayersNumber());
|
m_updateUi[i][3] = -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
m_ola = new olaThread(this, m_settings->getLayersNumber());
|
||||||
Q_CHECK_PTR(m_ola);
|
Q_CHECK_PTR(m_ola);
|
||||||
m_ola->blockSignals(true);
|
m_ola->blockSignals(true);
|
||||||
connect(m_ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int)));
|
|
||||||
connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int)));
|
|
||||||
m_ola->registerUniverse();
|
m_ola->registerUniverse();
|
||||||
connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup()));
|
m_mae.startEngine(m_settings->getAudioDeviceId());
|
||||||
m_aw->startEngine();
|
qDebug("Core init Complete. Start reading DMX.");
|
||||||
qDebug("Init Complete.");
|
|
||||||
m_ola->blockSignals(false);
|
m_ola->blockSignals(false);
|
||||||
|
#ifdef NOGUI
|
||||||
m_ola->start(QThread::TimeCriticalPriority );
|
m_ola->start(QThread::TimeCriticalPriority );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
libreMediaServerAudio::~libreMediaServerAudio()
|
libreMediaServerAudio::~libreMediaServerAudio()
|
||||||
{
|
{
|
||||||
m_ola->stop();
|
m_ola->stop();
|
||||||
m_aw->stopEngine();
|
m_mae.stopEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void libreMediaServerAudio::olasetup()
|
void libreMediaServerAudio::loadMedia(int layer, int folder, int file)
|
||||||
{
|
{
|
||||||
QWebView *view = new QWebView();
|
QString mediaFile = m_mediaLibrary->requestNewFile(folder, file);
|
||||||
view->load(QUrl("http://localhost:9090/ola.html"));
|
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
|
||||||
view->show();
|
return;
|
||||||
|
if (QFile::exists(mediaFile)){
|
||||||
|
m_mae.loadMedia(layer, mediaFile.toLatin1().data());
|
||||||
|
m_currentMedia[layer] = mediaFile;
|
||||||
|
#ifndef NOGUI
|
||||||
|
if (m_ui)
|
||||||
|
m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer));
|
||||||
|
#endif
|
||||||
|
m_mae.printFormatInfo(layer);
|
||||||
|
}
|
||||||
|
if (m_currentStatus[layer] == Status::PlayingFolder \
|
||||||
|
|| (m_currentStatus[layer] == Status::PlayingFolderLoop)\
|
||||||
|
|| (m_currentStatus[layer] == Status::PlayingFolderRandom)) {
|
||||||
|
m_played.append(file);
|
||||||
|
} else if (m_currentStatus[layer] == Status::PlayingOnce \
|
||||||
|
|| m_currentStatus[layer] == Status::PlayingLoop) {
|
||||||
|
m_played.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
||||||
{
|
{
|
||||||
if (layer > LAYER_CHANNELS)
|
if (layer >= MAX_LAYERS || channel >= LAYER_CHANNELS)
|
||||||
return;
|
return;
|
||||||
QString mediaFile = NULL;
|
QString mediaFile = NULL;
|
||||||
int aux;
|
int aux;
|
||||||
switch(channel){
|
if (channel == VOLUME_COARSE || channel == VOLUME_FINE) {
|
||||||
case DMX_FOLDER:
|
float tmp = value / 65025.0f;
|
||||||
aux = m_ola->getValue(layer, DMX_FILE);
|
m_mae.volChanged(layer, tmp);
|
||||||
mediaFile = m_mediaLibrary->requestNewFile(value, aux);
|
m_updateUi[layer][0] = tmp * 100.0f;
|
||||||
if (QFile::exists(mediaFile))
|
} else if (channel == PAN) {
|
||||||
m_aw->mediaLoaded(layer, mediaFile);
|
m_mae.panChanged(layer, value);
|
||||||
break;
|
m_updateUi[layer][1] = value;
|
||||||
case DMX_FILE:
|
} else if (channel == PITCH) {
|
||||||
aux = m_ola->getValue(layer, DMX_FOLDER);
|
m_mae.pitchChanged(layer, value);
|
||||||
mediaFile = m_mediaLibrary->requestNewFile(aux, value);
|
m_updateUi[layer][2] = value;
|
||||||
if (QFile::exists(mediaFile))
|
} else if (channel == ENTRY_POINT_COARSE || channel == ENTRY_POINT_FINE) {
|
||||||
m_aw->mediaLoaded(layer, mediaFile);
|
m_mae.setCursor(layer, value);
|
||||||
break;
|
m_updateUi[layer][3] = value;
|
||||||
case VOLUME_COARSE:
|
} else if (channel == PLAYBACK && value > 0) {
|
||||||
case VOLUME_FINE:
|
|
||||||
m_aw->volChanged(layer, (value / 65025.0f));
|
|
||||||
break;
|
|
||||||
case PAN:
|
|
||||||
m_aw->panChanged(layer, value);
|
|
||||||
break;
|
|
||||||
case PITCH:
|
|
||||||
m_aw->pitchChanged(layer, value);
|
|
||||||
break;
|
|
||||||
case ENTRY_POINT_COARSE:
|
|
||||||
case ENTRY_POINT_FINE:
|
|
||||||
m_aw->entryPointChanged(layer, value);
|
|
||||||
break;
|
|
||||||
case PLAYBACK:
|
|
||||||
if (value == 0)
|
|
||||||
break;
|
|
||||||
aux = value / 25;
|
aux = value / 25;
|
||||||
switch (aux) {
|
Status s = m_currentStatus[layer];
|
||||||
case 0 :
|
if (aux == 0)
|
||||||
m_aw->playbackChanged(layer, PlayingOnce);
|
s = Status::PlayingOnce;
|
||||||
break;
|
else if (aux == 1)
|
||||||
case 1 :
|
s = Status::Stopped;
|
||||||
m_aw->playbackChanged(layer, Stopped);
|
else if (aux == 2)
|
||||||
break;
|
s = Status::Paused;
|
||||||
case 2 :
|
else if (aux == 3)
|
||||||
m_aw->playbackChanged(layer, Paused);
|
s = Status::PlayingLoop;
|
||||||
break;
|
else if (aux == 4)
|
||||||
case 3 :
|
s = Status::PlayingFolder;
|
||||||
m_aw->playbackChanged(layer, PlayingLoop);
|
else if (aux == 5)
|
||||||
break;
|
s = Status::PlayingFolderLoop;
|
||||||
default :
|
else if (aux == 6)
|
||||||
break;
|
s = Status::PlayingFolderRandom;
|
||||||
|
m_mae.playbackChanged(layer, s);
|
||||||
|
m_currentStatus[layer] = s;
|
||||||
|
qInfo() << "Layer" << layer << StatusStr[s];
|
||||||
|
#ifndef NOGUI
|
||||||
|
if (m_ui) {
|
||||||
|
m_lmsUi->m_aw->playbackChanged(layer, s);
|
||||||
|
//m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer));
|
||||||
}
|
}
|
||||||
default:
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef NOGUI
|
||||||
|
void libreMediaServerAudio::refreshUi() {
|
||||||
|
if (!m_ui) return;
|
||||||
|
for (int i= 0; i < m_settings->getLayersNumber(); i++ ) {
|
||||||
|
if (m_updateUi[i][0] >= 0) {
|
||||||
|
m_lmsUi->m_aw->volChanged(i, m_updateUi[i][0]);
|
||||||
|
m_updateUi[i][0] = -1;
|
||||||
|
}
|
||||||
|
if (m_updateUi[i][1] >= 0) {
|
||||||
|
m_lmsUi->m_aw->panChanged(i, m_updateUi[i][1]);
|
||||||
|
m_updateUi[i][1] = -1;
|
||||||
|
}
|
||||||
|
if (m_updateUi[i][2] >= 0) {
|
||||||
|
m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]);
|
||||||
|
m_updateUi[i][2] = -1;
|
||||||
|
}
|
||||||
|
if (m_updateUi[i][3] >= 0 \
|
||||||
|
|| m_currentStatus[i] == Status::PlayingOnce\
|
||||||
|
|| m_currentStatus[i] == Status::PlayingLoop\
|
||||||
|
|| m_currentStatus[i] == Status::PlayingFolder\
|
||||||
|
|| m_currentStatus[i] == Status::PlayingFolderLoop
|
||||||
|
|| m_currentStatus[i] == Status::PlayingFolderRandom) {
|
||||||
|
m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i));
|
||||||
|
m_updateUi[i][3] = -1;
|
||||||
|
}
|
||||||
|
if (m_mae.getAtEnd(i)) {
|
||||||
|
if (m_played.isEmpty())
|
||||||
|
m_played.append(m_ola->getValue(i, DMX_FILE));
|
||||||
|
if (m_currentStatus[i] == Status::PlayingOnce) {
|
||||||
|
m_currentStatus[i] = Status::Stopped;
|
||||||
|
}
|
||||||
|
if (m_currentStatus[i] == Status::PlayingFolder) {
|
||||||
|
uint last = m_played.last();
|
||||||
|
int folder = m_ola->getValue(i, DMX_FOLDER);
|
||||||
|
last++;
|
||||||
|
if (last < m_mediaLibrary->getMediaFolderCount(folder)) {
|
||||||
|
this->loadMedia(i, folder, last);
|
||||||
|
m_mae.playbackChanged(i, Status::PlayingFolder);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_currentStatus[i] = Status::Stopped;
|
||||||
|
m_lmsUi->m_aw->playbackChanged(i, Status::Stopped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_currentStatus[i] == Status::PlayingFolderLoop) {
|
||||||
|
uint last = m_played.last();
|
||||||
|
int folder = m_ola->getValue(i, DMX_FOLDER);
|
||||||
|
last++;
|
||||||
|
if (last >= m_mediaLibrary->getMediaFolderCount(folder)) {
|
||||||
|
this->loadMedia(i, folder, 0);
|
||||||
|
m_mae.playbackChanged(i, Status::PlayingFolderLoop);
|
||||||
|
} else {
|
||||||
|
this->loadMedia(i, folder, last);
|
||||||
|
m_mae.playbackChanged(i, Status::PlayingFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_currentStatus[i] == Status::PlayingFolderRandom) {
|
||||||
|
int last = -1;
|
||||||
|
int folder = m_ola->getValue(i, DMX_FOLDER);
|
||||||
|
if (uint(abs(m_played.size())) >= m_mediaLibrary->getMediaFolderCount(folder))
|
||||||
|
m_played.clear();
|
||||||
|
while (last == -1) {
|
||||||
|
last = rand() % m_mediaLibrary->getMediaFolderCount(folder);
|
||||||
|
if (m_played.contains(last))
|
||||||
|
last = -1;
|
||||||
|
}
|
||||||
|
this->loadMedia(i, folder, last);
|
||||||
|
m_mae.playbackChanged(i, Status::PlayingFolderRandom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi)
|
||||||
|
{
|
||||||
|
m_lmsUi = lmsUi;
|
||||||
|
m_ui = true;
|
||||||
|
connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int)));
|
||||||
|
connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int)));
|
||||||
|
connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status)));
|
||||||
|
connect(m_lmsUi->m_aw, SIGNAL(uiLoadMedia(int, QString)), this, SLOT(uiLoadMedia(int, QString)));
|
||||||
|
m_refreshUi = new QTimer(this);
|
||||||
|
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
|
||||||
|
m_refreshUi->start(UI_REFRESH_TIME);
|
||||||
|
m_ola->start(QThread::TimeCriticalPriority );
|
||||||
|
};
|
||||||
|
|
||||||
|
// From Ui widgets
|
||||||
|
void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
|
||||||
|
{
|
||||||
|
switch (s){
|
||||||
|
case Slider::Volume:
|
||||||
|
m_mae.volChanged(layer, float((value / 100.0f)));
|
||||||
|
break;
|
||||||
|
case Slider::Pan:
|
||||||
|
m_mae.panChanged(layer, value);
|
||||||
|
break;
|
||||||
|
case Slider::Pitch:
|
||||||
|
m_mae.pitchChanged(layer, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s)
|
||||||
|
{
|
||||||
|
ma_result result;
|
||||||
|
|
||||||
|
result = m_mae.playbackChanged(layer, s);
|
||||||
|
if (result == MA_SUCCESS) {
|
||||||
|
m_currentStatus[layer] = s;
|
||||||
|
} else {
|
||||||
|
qWarning() << "ui playback change error" << result << "status" << s << "layer" << layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile)
|
||||||
|
{
|
||||||
|
ma_result result;
|
||||||
|
|
||||||
|
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
|
||||||
|
return;
|
||||||
|
result = m_mae.loadMedia(layer, mediaFile.toLatin1().data());
|
||||||
|
if (result == MA_SUCCESS) {
|
||||||
|
m_currentMedia[layer] = mediaFile;
|
||||||
|
m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer));
|
||||||
|
} else {
|
||||||
|
qWarning() << "ui load media error" << result << "file" << mediaFile << "layer" << layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -20,35 +20,51 @@
|
||||||
#ifndef LIBREMEDIASERVERAUDIO_H
|
#ifndef LIBREMEDIASERVERAUDIO_H
|
||||||
#define LIBREMEDIASERVERAUDIO_H
|
#define LIBREMEDIASERVERAUDIO_H
|
||||||
|
|
||||||
#include <QDockWidget>
|
|
||||||
#include <QWebView>
|
|
||||||
|
|
||||||
#include "audiowidget.h"
|
|
||||||
#include "medialibrary.h"
|
#include "medialibrary.h"
|
||||||
|
#include "miniaudioengine.h"
|
||||||
#include "olathread.h"
|
#include "olathread.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "dmxwidget.h"
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "ui_libremediaserver-audio.h"
|
#ifndef NOGUI
|
||||||
|
#include "libremediaserver-audio-gui.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class libreMediaServerAudio : public QMainWindow
|
class libreMediaServerAudio : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
libreMediaServerAudio (QStringList args, QWidget *parent = 0);
|
libreMediaServerAudio();
|
||||||
virtual ~libreMediaServerAudio();
|
virtual ~libreMediaServerAudio();
|
||||||
Ui::LibreMediaServerAudio ui;
|
void dmxInput(int layer, int channel, int value);
|
||||||
|
void loadMedia(int layer, int folder, int file);
|
||||||
|
#ifndef NOGUI
|
||||||
|
void setUi(libreMediaServerAudioUi *lmsUi);
|
||||||
|
bool inline getShowUi() { return m_settings->getShowUi(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioWidget *m_aw;
|
|
||||||
dmxWidget *m_dmxWidget;
|
|
||||||
olaThread *m_ola;
|
olaThread *m_ola;
|
||||||
MediaLibrary *m_mediaLibrary;
|
MediaLibrary *m_mediaLibrary;
|
||||||
|
MiniAudioEngine m_mae;
|
||||||
|
Settings *m_settings;
|
||||||
|
QString m_currentMedia[MAX_LAYERS];
|
||||||
|
Status m_currentStatus[MAX_LAYERS];
|
||||||
|
QList<dmxSetting> m_dmxSettings;
|
||||||
|
bool m_ui;
|
||||||
|
QList<int> m_played;
|
||||||
|
#ifndef NOGUI
|
||||||
|
QTimer *m_refreshUi;
|
||||||
|
libreMediaServerAudioUi *m_lmsUi;
|
||||||
|
float m_updateUi[MAX_LAYERS][4];
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void olasetup();
|
void refreshUi();
|
||||||
void dmxInput(int layer, int channel, int value);
|
void uiSliderChanged(int layer, Slider s, int value);
|
||||||
|
void uiPlaybackChanged(int layer, Status s);
|
||||||
|
void uiLoadMedia(int layer, QString s);
|
||||||
|
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LIBREMEDIASERVERAUDIO_H
|
#endif // LIBREMEDIASERVERAUDIO_H
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<author>Santi Noreña belfegor@gmail.com</author>
|
|
||||||
<class>LibreMediaServerAudio</class>
|
|
||||||
<widget class="QMainWindow" name="LibreMediaServerAudio">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>114</width>
|
|
||||||
<height>218</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>LibreMediaServer</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralwidget"/>
|
|
||||||
<widget class="QMenuBar" name="menuBar">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>114</width>
|
|
||||||
<height>22</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<widget class="QMenu" name="menuFile">
|
|
||||||
<property name="title">
|
|
||||||
<string>File</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="actionLaunch_OLA_Setup"/>
|
|
||||||
</widget>
|
|
||||||
<addaction name="menuFile"/>
|
|
||||||
</widget>
|
|
||||||
<action name="actionExit">
|
|
||||||
<property name="text">
|
|
||||||
<string>Exit</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionOpen_conf">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open Configuration...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionSave_conf">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save Configuration...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_Settings">
|
|
||||||
<property name="text">
|
|
||||||
<string>Settings...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionInitMSEX">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Init</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionIP_Address">
|
|
||||||
<property name="text">
|
|
||||||
<string>IP Address</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionMake_Thumbs">
|
|
||||||
<property name="text">
|
|
||||||
<string>Make Thumbs</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionLaunch_OLA_Setup">
|
|
||||||
<property name="text">
|
|
||||||
<string>OLA Setup...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
38
src/main.cpp
38
src/main.cpp
|
@ -18,34 +18,28 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libremediaserver-audio.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
bool hasUi(int &argc, char *argv[])
|
||||||
|
{
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (!strcmp(argv[i], "--gui"))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QStringList args = app.arguments();
|
libreMediaServerAudio lms;
|
||||||
if (args.size() > 1)
|
#ifndef NOGUI
|
||||||
|
if (hasUi(argc, argv) || lms.getShowUi())
|
||||||
{
|
{
|
||||||
if (args.contains("-v"))
|
libreMediaServerAudioUi *lmsUi = new libreMediaServerAudioUi();
|
||||||
{
|
lms.setUi(lmsUi);
|
||||||
qDebug() << VERSION;
|
lmsUi->show();
|
||||||
qDebug() << COPYRIGHT;
|
|
||||||
qDebug() << LICENSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (args.contains("-h"))
|
|
||||||
{
|
|
||||||
qDebug() << VERSION;
|
|
||||||
qDebug() << COPYRIGHT;
|
|
||||||
qDebug() << LICENSE;
|
|
||||||
qDebug() << "Help for command line options:";
|
|
||||||
qDebug() << "-v show the version and exits";
|
|
||||||
qDebug() << "-h this help";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
libreMediaServerAudio libreMediaServerAudio(args);
|
#endif
|
||||||
libreMediaServerAudio.show();
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
20
src/main.h
Normal file
20
src/main.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "medialibrary.h"
|
||||||
|
#include "olathread.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "libremediaserver-audio.h"
|
||||||
|
#include "libremediaserver-audio-gui.h"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
olaThread *m_ola;
|
||||||
|
MediaLibrary *m_mediaLibrary;
|
||||||
|
|
||||||
|
// slots
|
||||||
|
void dmxInput(int layer, int channel, int value);
|
||||||
|
|
||||||
|
#endif // MAIN_H
|
|
@ -27,14 +27,11 @@ class MediaLibrary : public QObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MediaLibrary(QObject *parent = 0);
|
MediaLibrary(QObject *parent = 0);
|
||||||
/**
|
|
||||||
* @brief request a new file from the media library
|
|
||||||
* @param int folder - the folder required
|
|
||||||
* @param int layer - file required
|
|
||||||
* @return QString the file required with full path
|
|
||||||
*/
|
|
||||||
QString requestNewFile(int folder, int layer);
|
QString requestNewFile(int folder, int layer);
|
||||||
void initMediaLibrary();
|
void initMediaLibrary();
|
||||||
|
inline uint getMediaFolderCount(int folder) {
|
||||||
|
return m_media->at(folder).m_ElementCount;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<MediaFolder> *m_media;
|
QList<MediaFolder> *m_media;
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
#include "miniaudioengine.h"
|
#include "miniaudioengine.h"
|
||||||
|
#include <iostream> //enum macro
|
||||||
MiniAudioEngine::MiniAudioEngine()
|
MiniAudioEngine::MiniAudioEngine()
|
||||||
{
|
{
|
||||||
|
for (int i =0; i < MAX_LAYERS; i++) {
|
||||||
|
m_mediaLoaded[i] = false;
|
||||||
|
m_currentLayerValues[i].status = Status::Iddle;
|
||||||
|
m_currentLayerValues[i].pan = 128;
|
||||||
|
m_currentLayerValues[i].pitch = 128;
|
||||||
|
m_currentLayerValues[i].vol = 0;
|
||||||
|
m_currentLayerValues[i].cursor = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
||||||
|
@ -20,25 +27,26 @@ void MiniAudioEngine::stopEngine()
|
||||||
ma_resource_manager_uninit(&resourceManager);
|
ma_resource_manager_uninit(&resourceManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MiniAudioEngine::startEngine(int n)
|
bool MiniAudioEngine::startEngine(uint n)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
|
|
||||||
result = this->startContext();
|
result = this->startContext();
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) return result;
|
||||||
return result;
|
result = this->getAllAudioDevices();
|
||||||
}
|
if (result != MA_SUCCESS) return result;
|
||||||
this->getAllAudioDevices();
|
|
||||||
result = this->startDevice(n);
|
result = this->startDevice(n);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_result MiniAudioEngine::startDevice(int id)
|
ma_result MiniAudioEngine::startDevice(uint id)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
ma_device_config deviceConfig;
|
ma_device_config deviceConfig;
|
||||||
ma_engine_config engineConfig;
|
ma_engine_config engineConfig;
|
||||||
|
|
||||||
|
if (id >= playbackDeviceCount)
|
||||||
|
id = playbackDeviceCount - 1;
|
||||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||||
deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id;
|
deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id;
|
||||||
deviceConfig.playback.format = resourceManager.config.decodedFormat;
|
deviceConfig.playback.format = resourceManager.config.decodedFormat;
|
||||||
|
@ -66,7 +74,7 @@ ma_result MiniAudioEngine::startDevice(int id)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
iChosenDevice = id;
|
iChosenDevice = id;
|
||||||
qInfo("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name);
|
qInfo("Initialized audio device %d : %s", id, pPlaybackDeviceInfos[id].name);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +85,8 @@ ma_result MiniAudioEngine::startContext()
|
||||||
resourceManagerConfig = ma_resource_manager_config_init();
|
resourceManagerConfig = ma_resource_manager_config_init();
|
||||||
resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */
|
resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */
|
||||||
resourceManagerConfig.decodedChannels = 0;
|
resourceManagerConfig.decodedChannels = 0;
|
||||||
resourceManagerConfig.decodedSampleRate = 0;
|
resourceManagerConfig.decodedSampleRate = ma_standard_sample_rate_48000;
|
||||||
resourceManagerConfig.jobThreadCount = 0;
|
resourceManagerConfig.jobThreadCount = 4;
|
||||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
qCritical("Failed to initialize audio resource manager.");
|
qCritical("Failed to initialize audio resource manager.");
|
||||||
|
@ -102,7 +110,7 @@ ma_result MiniAudioEngine::getAllAudioDevices()
|
||||||
ma_context_uninit(&context);
|
ma_context_uninit(&context);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
printf("Audio devices detected in system:\n");
|
printf("Audio devices available:\n");
|
||||||
for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) {
|
for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) {
|
||||||
qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name);
|
qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name);
|
||||||
}
|
}
|
||||||
|
@ -115,21 +123,20 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file)
|
||||||
|
|
||||||
if (m_mediaLoaded[layer] == true)
|
if (m_mediaLoaded[layer] == true)
|
||||||
{
|
{
|
||||||
qInfo("removing sound %i", layer);
|
|
||||||
ma_sound_uninit(&m_currentSound[layer]);
|
ma_sound_uninit(&m_currentSound[layer]);
|
||||||
m_mediaLoaded[layer] = false;
|
m_mediaLoaded[layer] = false;
|
||||||
}
|
}
|
||||||
result = ma_sound_init_from_file(&engine, file, \
|
result = ma_sound_init_from_file(&engine, file, \
|
||||||
MA_SOUND_FLAG_NO_SPATIALIZATION \
|
MA_SOUND_FLAG_NO_SPATIALIZATION \
|
||||||
/*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE \
|
| MA_SOUND_FLAG_DECODE \
|
||||||
| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC \
|
/*| MA_SOUND_FLAG_NO_PITCH \*/
|
||||||
| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM \*/
|
|
||||||
, NULL, NULL, &m_currentSound[layer]);
|
, NULL, NULL, &m_currentSound[layer]);
|
||||||
if (result != MA_SUCCESS)
|
if (result != MA_SUCCESS)
|
||||||
qWarning("Failed to load file %s", file);
|
qWarning("Failed to load file %s", file);
|
||||||
else {
|
else {
|
||||||
m_mediaLoaded[layer] = true;
|
m_mediaLoaded[layer] = true;
|
||||||
this->volChanged(layer, 0);
|
this->refreshValues(layer);
|
||||||
|
m_currentLayerValues[layer].media = file;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -137,16 +144,21 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file)
|
||||||
float MiniAudioEngine::getDuration(int layer)
|
float MiniAudioEngine::getDuration(int layer)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
float ret = 0;
|
ma_uint64 lengthInPCMFrames;
|
||||||
|
ma_uint32 sampleRate;
|
||||||
|
float ret;
|
||||||
|
|
||||||
if (m_mediaLoaded[layer] == false)
|
if (m_mediaLoaded[layer] == false)
|
||||||
return MA_DOES_NOT_EXIST;
|
return MA_DOES_NOT_EXIST;
|
||||||
result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret);
|
result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &lengthInPCMFrames);
|
||||||
if (result != MA_SUCCESS)
|
if (result != MA_SUCCESS) {
|
||||||
{
|
return result;
|
||||||
qWarning("Can not get duration %i", layer);
|
|
||||||
ret = 0;
|
|
||||||
}
|
}
|
||||||
|
result = ma_sound_get_data_format(&m_currentSound[layer], NULL, NULL, &sampleRate, NULL, 0);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
return MA_ERROR;
|
||||||
|
}
|
||||||
|
ret = 1000.0f * (lengthInPCMFrames / float(sampleRate));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,8 +172,8 @@ float MiniAudioEngine::getCursor(int layer)
|
||||||
result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret);
|
result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret);
|
||||||
if (result != MA_SUCCESS)
|
if (result != MA_SUCCESS)
|
||||||
{
|
{
|
||||||
qWarning("Can not get cursor %i", layer);
|
qWarning("%i can not get cursor error %i", layer, result);
|
||||||
ret = 0;
|
ret = MA_ERROR;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -175,11 +187,10 @@ ma_result MiniAudioEngine::printFormatInfo(int layer)
|
||||||
if (m_mediaLoaded[layer] == false)
|
if (m_mediaLoaded[layer] == false)
|
||||||
return MA_DOES_NOT_EXIST;
|
return MA_DOES_NOT_EXIST;
|
||||||
ma_result result = ma_sound_get_data_format(&m_currentSound[layer], &format, &channels, &sampleRate, NULL, 0);
|
ma_result result = ma_sound_get_data_format(&m_currentSound[layer], &format, &channels, &sampleRate, NULL, 0);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS)
|
||||||
qWarning("Failed to get data format %i\n", layer);
|
qWarning("%i failed to get data format %i\n", layer, result);
|
||||||
return MA_INVALID_DATA;
|
else
|
||||||
}
|
qInfo() << "Layer:" << layer << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels;
|
||||||
qInfo("samples/sec: %u format: %u channels: %u", sampleRate, format, channels);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +199,10 @@ void MiniAudioEngine::volChanged(int layer, float vol)
|
||||||
{
|
{
|
||||||
if (m_mediaLoaded[layer] == false)
|
if (m_mediaLoaded[layer] == false)
|
||||||
return;
|
return;
|
||||||
ma_sound_group_set_volume(&m_currentSound[layer], vol);
|
if (vol >= 1)
|
||||||
|
vol = 0.99f;
|
||||||
|
ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, vol, FADE_TIME);
|
||||||
|
m_currentLayerValues[layer].vol = vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiniAudioEngine::panChanged(int layer, float value)
|
void MiniAudioEngine::panChanged(int layer, float value)
|
||||||
|
@ -199,48 +213,90 @@ void MiniAudioEngine::panChanged(int layer, float value)
|
||||||
return;
|
return;
|
||||||
result = (value / 128.0) - 1.0;
|
result = (value / 128.0) - 1.0;
|
||||||
ma_sound_group_set_pan(&m_currentSound[layer], result);
|
ma_sound_group_set_pan(&m_currentSound[layer], result);
|
||||||
|
m_currentLayerValues[layer].pan = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiniAudioEngine::pitchChanged(int layer, float value)
|
void MiniAudioEngine::pitchChanged(int layer, float value)
|
||||||
{
|
{
|
||||||
float result;
|
float pitch;
|
||||||
|
|
||||||
if (m_mediaLoaded[layer] == false)
|
if (m_mediaLoaded[layer] == false)
|
||||||
return;
|
return;
|
||||||
result = value / 128.0;
|
pitch = value / 128.0;
|
||||||
ma_sound_group_set_pitch(&m_currentSound[layer], result);
|
ma_sound_group_set_pitch(&m_currentSound[layer], pitch);
|
||||||
|
m_currentLayerValues[layer].pitch = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiniAudioEngine::playbackChanged(int layer, Status status)
|
ma_result MiniAudioEngine::playbackChanged(int layer, Status status)
|
||||||
{
|
{
|
||||||
|
ma_result result = MA_SUCCESS;
|
||||||
|
|
||||||
if (m_mediaLoaded[layer] == false)
|
if (m_mediaLoaded[layer] == false)
|
||||||
return;
|
return MA_DOES_NOT_EXIST;
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case Status::Paused:
|
case Status::Paused:
|
||||||
ma_sound_stop(&m_currentSound[layer]);
|
result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME);
|
||||||
break;
|
break;
|
||||||
case Status::Stopped:
|
case Status::Stopped:
|
||||||
ma_sound_stop(&m_currentSound[layer]);
|
result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME);
|
||||||
ma_sound_seek_to_pcm_frame(&m_currentSound[layer], 0);
|
result = this->seekToCursor(layer, m_currentLayerValues[layer].cursor);
|
||||||
break;
|
break;
|
||||||
case Status::PlayingLoop:
|
case Status::PlayingLoop:
|
||||||
|
ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0);
|
||||||
ma_sound_set_looping(&m_currentSound[layer], true);
|
ma_sound_set_looping(&m_currentSound[layer], true);
|
||||||
ma_sound_start(&m_currentSound[layer]);
|
result = ma_sound_start(&m_currentSound[layer]);
|
||||||
break;
|
break;
|
||||||
case Status::PlayingOnce:
|
case Status::PlayingOnce:
|
||||||
|
case Status::PlayingFolder:
|
||||||
|
case Status::PlayingFolderLoop:
|
||||||
|
case Status::PlayingFolderRandom:
|
||||||
|
ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0);
|
||||||
ma_sound_set_looping(&m_currentSound[layer], false);
|
ma_sound_set_looping(&m_currentSound[layer], false);
|
||||||
ma_sound_start(&m_currentSound[layer]);
|
result = ma_sound_start(&m_currentSound[layer]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (result == MA_SUCCESS)
|
||||||
|
m_currentLayerValues[layer].status = status;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiniAudioEngine::setCursor(int layer, int cursor)
|
ma_result MiniAudioEngine::seekToCursor(int layer, int cursor)
|
||||||
{
|
{
|
||||||
ma_uint64 f;
|
ma_result result = MA_SUCCESS;
|
||||||
|
ma_uint64 end, start;
|
||||||
|
|
||||||
if (m_mediaLoaded[layer] == false)
|
if (m_mediaLoaded[layer] == false)
|
||||||
return;
|
return MA_DOES_NOT_EXIST;
|
||||||
ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &f);
|
result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end);
|
||||||
f = (cursor * f) / 65025;
|
if (result != MA_SUCCESS) { return result; }
|
||||||
ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f);
|
start = (cursor * end) / 65025;
|
||||||
|
result = ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start);
|
||||||
|
//if (result != MA_SUCCESS) { return result; }
|
||||||
|
//result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end);
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_result MiniAudioEngine::setCursor(int layer, int cursor)
|
||||||
|
{
|
||||||
|
ma_result result = MA_SUCCESS;
|
||||||
|
|
||||||
|
m_currentLayerValues[layer].cursor = cursor;
|
||||||
|
result = this->seekToCursor(layer, cursor);
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status MiniAudioEngine::getStatus(int layer)
|
||||||
|
{
|
||||||
|
return m_currentLayerValues[layer].status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiniAudioEngine::refreshValues(int layer)
|
||||||
|
{
|
||||||
|
this->seekToCursor(layer, m_currentLayerValues[layer].cursor);
|
||||||
|
this->panChanged(layer, m_currentLayerValues[layer].pan);
|
||||||
|
this->volChanged(layer, m_currentLayerValues[layer].vol);
|
||||||
|
this->pitchChanged(layer, m_currentLayerValues[layer].pitch);
|
||||||
|
this->playbackChanged(layer, m_currentLayerValues[layer].status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,16 @@
|
||||||
#include "miniaudio.h"
|
#include "miniaudio.h"
|
||||||
#include "defines.h" // MAX_LAYERS
|
#include "defines.h" // MAX_LAYERS
|
||||||
#include <QDebug> // prints messages
|
#include <QDebug> // prints messages
|
||||||
|
#define MA_DEBUG_OUTPUT
|
||||||
|
|
||||||
class MiniAudioEngine
|
class MiniAudioEngine
|
||||||
{
|
{
|
||||||
friend class AudioWidget;
|
friend class libreMediaServerAudio;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MiniAudioEngine();
|
MiniAudioEngine();
|
||||||
void stopEngine();
|
void stopEngine();
|
||||||
bool startEngine(int id);
|
bool startEngine(uint id);
|
||||||
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
|
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -21,11 +22,15 @@ protected:
|
||||||
void volChanged(int layer, float vol);
|
void volChanged(int layer, float vol);
|
||||||
void panChanged(int layer, float pan);
|
void panChanged(int layer, float pan);
|
||||||
void pitchChanged(int layer, float pitch);
|
void pitchChanged(int layer, float pitch);
|
||||||
void playbackChanged(int layer, Status status);
|
ma_result playbackChanged(int layer, Status status);
|
||||||
|
ma_result setCursor(int layer, int cursor);
|
||||||
|
ma_result printFormatInfo(int layer);
|
||||||
float getDuration(int layer);
|
float getDuration(int layer);
|
||||||
float getCursor(int layer);
|
float getCursor(int layer);
|
||||||
void setCursor(int layer, int cursor);
|
Status getStatus(int layer);
|
||||||
ma_result printFormatInfo(int layer);
|
inline float getVol(int layer) {
|
||||||
|
return ma_sound_get_volume(&m_currentSound[layer]); }
|
||||||
|
inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ma_resource_manager_config resourceManagerConfig;
|
ma_resource_manager_config resourceManagerConfig;
|
||||||
|
@ -38,10 +43,13 @@ private:
|
||||||
ma_context context;
|
ma_context context;
|
||||||
ma_sound m_currentSound[MAX_LAYERS];
|
ma_sound m_currentSound[MAX_LAYERS];
|
||||||
ma_bool8 m_mediaLoaded[MAX_LAYERS];
|
ma_bool8 m_mediaLoaded[MAX_LAYERS];
|
||||||
|
layerData m_currentLayerValues[MAX_LAYERS];
|
||||||
|
|
||||||
ma_result getAllAudioDevices();
|
ma_result getAllAudioDevices();
|
||||||
ma_result startDevice(int id);
|
ma_result startDevice(uint id);
|
||||||
ma_result startContext();
|
ma_result startContext();
|
||||||
|
void refreshValues(int layer);
|
||||||
|
ma_result seekToCursor(int layer, int cursor);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MINIAUDIOENGINE_H
|
#endif // MINIAUDIOENGINE_H
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
#include "olathread.h"
|
#include "libremediaserver-audio.h"
|
||||||
|
|
||||||
|
|
||||||
olaThread::olaThread(QObject *parent, int layers) :
|
olaThread::olaThread(QObject *parent, int layers) :
|
||||||
m_counter(0)
|
m_counter(0)
|
||||||
, m_layers(layers)
|
, m_layers(layers)
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
this->setParent(parent);
|
||||||
gettimeofday(&m_last_data, NULL);
|
gettimeofday(&m_last_data, NULL);
|
||||||
for (int i=0; i < MAX_LAYERS; i++)
|
for (int i=0; i < MAX_LAYERS; i++)
|
||||||
{
|
{
|
||||||
|
@ -63,42 +62,65 @@ void olaThread::stop()
|
||||||
void olaThread::NewDmx(const ola::client::DMXMetadata &data,
|
void olaThread::NewDmx(const ola::client::DMXMetadata &data,
|
||||||
const ola::DmxBuffer &buffer)
|
const ola::DmxBuffer &buffer)
|
||||||
{
|
{
|
||||||
bool volSent = false;
|
|
||||||
bool entrySent = false;
|
|
||||||
|
|
||||||
foreach (const dmxSetting &i, m_dmxSettings) {
|
foreach (const dmxSetting &i, m_dmxSettings) {
|
||||||
if(i.universe == data.universe && i.address > -1) {
|
if(i.universe == data.universe && i.address > -1) {
|
||||||
|
bool volSent = false;
|
||||||
|
bool entrySent = false;
|
||||||
|
bool fileSent = false;
|
||||||
|
int aux;
|
||||||
for (int j = 0; j < LAYER_CHANNELS; j++){
|
for (int j = 0; j < LAYER_CHANNELS; j++){
|
||||||
int value = buffer.Get((i.address) + j);
|
int value = buffer.Get((i.address) + j);
|
||||||
if (m_dmx[i.layer][j] != value) {
|
if (m_dmx[i.layer][j] != value) {
|
||||||
m_dmx[i.layer][j] = value;
|
m_dmx[i.layer][j] = value;
|
||||||
switch (j) {
|
switch (j) {
|
||||||
case VOLUME_COARSE:
|
case DMX_FOLDER:
|
||||||
value = (value * 0x100) + buffer.Get(i.address + VOLUME_FINE);
|
aux = buffer.Get(i.address + DMX_FILE);
|
||||||
emit dmxOutput(i.layer,j,value);
|
qobject_cast<libreMediaServerAudio *>(parent())->loadMedia(i.layer, value, aux);
|
||||||
volSent = true;
|
m_dmx[i.layer][DMX_FILE] = aux;
|
||||||
|
fileSent = true;
|
||||||
break;
|
break;
|
||||||
case ENTRY_POINT_COARSE:
|
case DMX_FILE:
|
||||||
value = (value * 0x100) + buffer.Get(i.address + ENTRY_POINT_FINE);
|
if (fileSent)
|
||||||
emit dmxOutput(i.layer,j,value);
|
break;
|
||||||
entrySent = true;
|
aux = buffer.Get(i.address + DMX_FOLDER);
|
||||||
|
qobject_cast<libreMediaServerAudio *>(parent())->loadMedia(i.layer, aux, value);
|
||||||
|
m_dmx[i.layer][DMX_FOLDER] = aux;
|
||||||
|
fileSent = true;
|
||||||
break;
|
break;
|
||||||
case VOLUME_FINE:
|
case VOLUME_FINE:
|
||||||
if (volSent == false)
|
aux = buffer.Get(i.address + VOLUME_COARSE);
|
||||||
{
|
value += (aux * 0x100);
|
||||||
value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value;
|
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
|
||||||
emit dmxOutput(i.layer,j,value);
|
m_dmx[i.layer][VOLUME_COARSE] = aux;
|
||||||
}
|
volSent = true;
|
||||||
|
break;
|
||||||
|
case VOLUME_COARSE:
|
||||||
|
if (volSent)
|
||||||
|
break;
|
||||||
|
value = (value * 0x100) + buffer.Get(i.address + VOLUME_FINE);
|
||||||
|
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
|
||||||
|
m_dmx[i.layer][VOLUME_FINE] = buffer.Get(i.address + VOLUME_FINE);
|
||||||
|
volSent = true;
|
||||||
|
break;
|
||||||
|
case PLAYBACK:
|
||||||
|
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
|
||||||
break;
|
break;
|
||||||
case ENTRY_POINT_FINE:
|
case ENTRY_POINT_FINE:
|
||||||
if (entrySent == false)
|
value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value;
|
||||||
{
|
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
|
||||||
value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value;
|
m_dmx[i.layer][ENTRY_POINT_COARSE] = buffer.Get(i.address + ENTRY_POINT_COARSE);
|
||||||
emit dmxOutput(i.layer,j,value);
|
entrySent = true;
|
||||||
}
|
break;
|
||||||
|
case ENTRY_POINT_COARSE:
|
||||||
|
if (entrySent)
|
||||||
|
break;
|
||||||
|
value = (value * 0x100) + buffer.Get(i.address + ENTRY_POINT_FINE);
|
||||||
|
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
|
||||||
|
m_dmx[i.layer][ENTRY_POINT_FINE] = buffer.Get(i.address + ENTRY_POINT_FINE);
|
||||||
|
entrySent = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
emit dmxOutput(i.layer,j,value);
|
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +149,7 @@ bool olaThread::CheckDataLoss() {
|
||||||
|
|
||||||
void olaThread::socketClosed()
|
void olaThread::socketClosed()
|
||||||
{
|
{
|
||||||
qWarning("ola closed connection. Try reopening it... ");
|
qWarning("ola daemon closed connection, reopening it... ");
|
||||||
m_clientWrapper->GetSelectServer()->Terminate();
|
m_clientWrapper->GetSelectServer()->Terminate();
|
||||||
m_client = NULL;
|
m_client = NULL;
|
||||||
m_clientWrapper = NULL;
|
m_clientWrapper = NULL;
|
||||||
|
|
|
@ -20,10 +20,17 @@ class olaThread : public QThread
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
QList<dmxSetting> m_dmxSettings;
|
||||||
|
int m_dmx[MAX_LAYERS][LAYER_CHANNELS];
|
||||||
|
ola::client::OlaClientWrapper *m_clientWrapper;
|
||||||
|
ola::client::OlaClient *m_client;
|
||||||
|
unsigned int m_counter;
|
||||||
|
struct timeval m_last_data; // Last DMX frame received
|
||||||
|
int m_layers;
|
||||||
|
|
||||||
olaThread(QObject *parent = 0, int layers = 0);
|
olaThread(QObject *parent = 0, int layers = 0);
|
||||||
virtual ~olaThread();
|
virtual ~olaThread();
|
||||||
|
void run ();
|
||||||
/** Retorna el valor de un canal
|
/** Retorna el valor de un canal
|
||||||
*@param int layer the layer for we want the channel
|
*@param int layer the layer for we want the channel
|
||||||
*@param int channel the channel for the value wanted
|
*@param int channel the channel for the value wanted
|
||||||
|
@ -35,14 +42,6 @@ public:
|
||||||
void resendDmx();
|
void resendDmx();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void run ();
|
|
||||||
ola::client::OlaClientWrapper *m_clientWrapper;
|
|
||||||
ola::client::OlaClient *m_client;
|
|
||||||
unsigned int m_counter;
|
|
||||||
struct timeval m_last_data; // Last DMX frame received
|
|
||||||
int m_layers;
|
|
||||||
int m_dmx[MAX_LAYERS][LAYER_CHANNELS];
|
|
||||||
QList<dmxSetting> m_dmxSettings;
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback from ola. Control de errores en el registro de Universos en OLA
|
* @brief Callback from ola. Control de errores en el registro de Universos en OLA
|
||||||
* typedef SingleUseCallback1<void, const Result&> ola::client::SetCallback
|
* typedef SingleUseCallback1<void, const Result&> ola::client::SetCallback
|
||||||
|
@ -53,7 +52,7 @@ private:
|
||||||
if (error.Success()) {
|
if (error.Success()) {
|
||||||
qDebug("Register Universe success");
|
qDebug("Register Universe success");
|
||||||
} else {
|
} else {
|
||||||
qWarning("Register command failed: %s", error.Error().c_str());
|
qCritical("Register command failed: %s", error.Error().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -67,7 +66,7 @@ private:
|
||||||
* This is called one for second if there is not updated in the DMX frame.
|
* This is called one for second if there is not updated in the DMX frame.
|
||||||
* emit only the channels that has been changed.
|
* emit only the channels that has been changed.
|
||||||
*/
|
*/
|
||||||
void NewDmx(const ola::client::DMXMetadata &dmx_meta, const ola::DmxBuffer &buffer); //
|
void NewDmx(const ola::client::DMXMetadata &dmx_meta, const ola::DmxBuffer &buffer);
|
||||||
/**
|
/**
|
||||||
* @brief Sometimes the ola server closes the connection. This is a callback to handle this event an reconect to ola
|
* @brief Sometimes the ola server closes the connection. This is a callback to handle this event an reconect to ola
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,6 +15,7 @@ Settings::Settings(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
m_layersNumber = 0;
|
m_layersNumber = 0;
|
||||||
|
m_ui = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the dmx settings for dmx.xml At the moment we need:
|
// Read the dmx settings for dmx.xml At the moment we need:
|
||||||
|
@ -23,6 +24,7 @@ Settings::Settings(QObject *parent) :
|
||||||
// - The first DMX channel of each source/layer
|
// - The first DMX channel of each source/layer
|
||||||
// - The universe to bind in OLA
|
// - The universe to bind in OLA
|
||||||
// - Audio device id
|
// - Audio device id
|
||||||
|
// - Show the Ui or not
|
||||||
void Settings::readFromFile(QString file) {
|
void Settings::readFromFile(QString file) {
|
||||||
QFile* xmlFile = new QFile(file);
|
QFile* xmlFile = new QFile(file);
|
||||||
if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
@ -34,53 +36,56 @@ void Settings::readFromFile(QString file) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile);
|
QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile);
|
||||||
int counter = 0;
|
while(!xmlReader->atEnd() && !xmlReader->hasError()) {
|
||||||
//Parse the XML until we reach end of it
|
|
||||||
while(!xmlReader->atEnd() && !xmlReader->hasError() && counter < MAX_LAYERS) {
|
|
||||||
// Read next element
|
|
||||||
QXmlStreamReader::TokenType token = xmlReader->readNext();
|
QXmlStreamReader::TokenType token = xmlReader->readNext();
|
||||||
//If token is just StartDocument - go to next
|
|
||||||
if(token == QXmlStreamReader::StartDocument) {
|
if(token == QXmlStreamReader::StartDocument) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//If token is StartElement - read it
|
|
||||||
if(token == QXmlStreamReader::StartElement) {
|
if(token == QXmlStreamReader::StartElement) {
|
||||||
if(xmlReader->name() == "dmxSettings") {
|
if(xmlReader->name() == "lmsAudio") {
|
||||||
int version = xmlReader->attributes().value("fileVersion").toLocal8Bit().toInt();
|
m_ui = xmlReader->attributes().value("ui").toLocal8Bit().toInt();
|
||||||
if(version == 1) {
|
m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt();
|
||||||
m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt();
|
m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit();
|
||||||
m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(xmlReader->name() == "audioDevice") {
|
|
||||||
m_audioDeviceId = xmlReader->attributes().value("id").toLocal8Bit().toInt();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QString add = "layer";
|
if(xmlReader->name() == "audioDevice") {
|
||||||
add.append(QString("%1").arg(counter));
|
m_audioDeviceQty = xmlReader->attributes().value("devicesNumber").toLocal8Bit().toInt();
|
||||||
if((xmlReader->name() == add)) {
|
for (uint i = 0; i < m_audioDeviceQty; i++)
|
||||||
|
{
|
||||||
|
m_audioDeviceId[i] = xmlReader->attributes().value(QString("id%1").arg(i)).toLocal8Bit().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(xmlReader->name() == "layer") {
|
||||||
dmxSetting temp;
|
dmxSetting temp;
|
||||||
temp.address = xmlReader->attributes().value("dmx").toLocal8Bit().toInt() - 1;
|
temp.address = xmlReader->attributes().value("dmx").toLocal8Bit().toInt() - 1;
|
||||||
temp.universe = xmlReader->attributes().value("universe").toLocal8Bit().toInt();
|
temp.universe = xmlReader->attributes().value("universe").toLocal8Bit().toInt();
|
||||||
temp.layer = counter;
|
temp.layer = xmlReader->attributes().value("id").toLocal8Bit().toInt();
|
||||||
m_settings.append(temp);
|
m_settings.append(temp);
|
||||||
if (!m_universe.contains(temp.universe)) {
|
if (!m_universe.contains(temp.universe)) {
|
||||||
m_universe.insert(temp.universe);
|
m_universe.insert(temp.universe);
|
||||||
}
|
}
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(xmlReader->hasError()) {
|
if(xmlReader->hasError()) {
|
||||||
QMessageBox::critical(NULL,"File xml Parse Error ", xmlReader->errorString(), QMessageBox::Ok);
|
QMessageBox::critical(NULL,"File xml Parse Error ", xmlReader->errorString(), QMessageBox::Ok);
|
||||||
qWarning("File xml Parse Error %s", xmlReader->errorString().toLatin1().constData());
|
qWarning("File xml Parse Error %s", xmlReader->errorString().toLatin1().constData());
|
||||||
return;
|
// ToDo: manage this, open a dialog to load a new file.
|
||||||
}
|
}
|
||||||
xmlReader->clear();
|
xmlReader->clear();
|
||||||
xmlFile->close();
|
xmlFile->close();
|
||||||
delete xmlReader;
|
delete xmlReader;
|
||||||
delete xmlFile;
|
delete xmlFile;
|
||||||
|
this->printSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::printSettings() {
|
||||||
|
qInfo() << "Settings readed:\nShow Ui:" << m_ui << "Layers:" << m_layersNumber << "Path:" << m_pathmedia <<"Audio Device qty:" << m_audioDeviceQty;
|
||||||
|
for (uint i = 0; i < m_audioDeviceQty; i++)
|
||||||
|
qInfo() << "Audio device internal id:" << i << "system id:" << m_audioDeviceId[i];
|
||||||
|
for (int i = 0; i < m_layersNumber; i++)
|
||||||
|
qInfo() << "Layer:" << m_settings[i].layer << "Address:" << m_settings[i].address << "Universe:" << m_settings[i].universe;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::readFile() {
|
void Settings::readFile() {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "medialibrary.h"
|
#include "medialibrary.h"
|
||||||
#include "audiowidget.h"
|
#include "audiowidget.h"
|
||||||
|
@ -15,25 +16,27 @@ class Settings : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Settings(QObject *parent = 0);
|
||||||
static Settings *getInstance();
|
static Settings *getInstance();
|
||||||
inline QSet<int> getUniverses() { return m_universe; }
|
inline QSet<int> getUniverses() { return m_universe; }
|
||||||
inline QString getPathMedia() { return m_pathmedia; }
|
inline QString getPathMedia() { return m_pathmedia; }
|
||||||
inline QList<dmxSetting> getDmxSettings() { return m_settings; }
|
inline QList<dmxSetting> getDmxSettings() { return m_settings; }
|
||||||
inline int getLayersNumber() { return m_layersNumber; }
|
inline int getLayersNumber() { return m_layersNumber; }
|
||||||
|
inline int getAudioDeviceId() { return m_audioDeviceId[0]; }
|
||||||
|
inline bool getShowUi() { return m_ui; }
|
||||||
void readFile();
|
void readFile();
|
||||||
inline int getAudioDeviceId() { return m_audioDeviceId; }
|
void readFromFile(QString file);
|
||||||
|
void printSettings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Settings *_instance;
|
static Settings *_instance;
|
||||||
QList<dmxSetting> m_settings;
|
QList<dmxSetting> m_settings;
|
||||||
QString m_pathmedia;
|
QString m_pathmedia;
|
||||||
uint m_audioDeviceId;
|
uint m_audioDeviceId[MAX_AUDIODEVICES];
|
||||||
|
uint m_audioDeviceQty;
|
||||||
QSet<int> m_universe;
|
QSet<int> m_universe;
|
||||||
int m_layersNumber;
|
int m_layersNumber;
|
||||||
|
bool m_ui;
|
||||||
explicit Settings(QObject *parent = 0);
|
|
||||||
void readFromFile(QString file);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|
|
@ -1,45 +1,81 @@
|
||||||
#include "slidergroup.h"
|
#include "slidergroup.h"
|
||||||
|
#include <QCursor>
|
||||||
SliderGroup::SliderGroup(const QString &title, \
|
SliderGroup::SliderGroup(QString name,
|
||||||
int min,
|
int min,
|
||||||
int max,
|
int max,
|
||||||
int decimals,
|
int decimals,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QGroupBox(title, parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
this->setFlat(true);
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
this->setTitle(title);
|
layout->setAlignment(Qt::AlignHCenter);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
//this->setMaximumWidth(40);
|
||||||
slider = new QSlider(Qt::Orientation::Vertical);
|
slider = new QSlider(Qt::Orientation::Vertical);
|
||||||
slider->setFocusPolicy(Qt::StrongFocus);
|
slider->setFocusPolicy(Qt::StrongFocus);
|
||||||
slider->setTickPosition(QSlider::TicksBothSides);
|
slider->setTickPosition(QSlider::TicksBothSides);
|
||||||
slider->setTickInterval((max - min) / 11);
|
slider->setTickInterval((max - min) / 11);
|
||||||
|
slider->setMinimumHeight(0);
|
||||||
slider->setSingleStep(1);
|
slider->setSingleStep(1);
|
||||||
slider->setRange(min, max);
|
slider->setRange(min, max);
|
||||||
|
slider->setValue(0);
|
||||||
|
slider->setMinimumWidth(50);
|
||||||
|
slider->setToolTip(name);
|
||||||
|
slider->setStyleSheet("QSlider {"
|
||||||
|
"border: 1px solid #5a4855;"
|
||||||
|
"margin: 0px;"
|
||||||
|
"height: 200px;"
|
||||||
|
"width: 50px;}"
|
||||||
|
);
|
||||||
|
slider->setContentsMargins(0, 0, 0, 0);
|
||||||
valueBox = new QDoubleSpinBox();
|
valueBox = new QDoubleSpinBox();
|
||||||
valueBox->setFocusPolicy(Qt::NoFocus);
|
valueBox->setFocusPolicy(Qt::NoFocus);
|
||||||
valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||||||
valueBox->setMaximumWidth(45);
|
valueBox->setMinimumWidth(50);
|
||||||
valueBox->setRange(min, max);
|
valueBox->setRange(min, max);
|
||||||
|
valueBox->setValue(0);
|
||||||
valueBox->setDecimals(decimals);
|
valueBox->setDecimals(decimals);
|
||||||
|
valueBox->setObjectName(name);
|
||||||
|
valueBox->setToolTip(name);
|
||||||
|
valueBox->setAlignment(Qt::AlignHCenter);
|
||||||
|
valueBox->setContentsMargins(0, 0, 0, 0);
|
||||||
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int)));
|
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int)));
|
||||||
QVBoxLayout *slidersLayout = new QVBoxLayout();
|
//connect(slider, SIGNAL(mousePressEvent(QMouseEvent)), this, SLOT(mousePressEvent(QMouseEvent *)));
|
||||||
slidersLayout->addWidget(valueBox);
|
layout->addWidget(slider);
|
||||||
slidersLayout->addWidget(slider);
|
layout->addWidget(valueBox);
|
||||||
setLayout(slidersLayout);
|
this->setStyleSheet("border: 1px solid #5a4855;"
|
||||||
|
"width: 50px;"
|
||||||
|
"margin: 0px;"
|
||||||
|
"background-color: #383034;"
|
||||||
|
);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
this->setLayout(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SliderGroup::sliderValueChanged(int value)
|
void SliderGroup::sliderValueChanged(int value)
|
||||||
{
|
{
|
||||||
if (valueBox->decimals() > 1)
|
valueBox->blockSignals(true);
|
||||||
value /= 100.0f;
|
|
||||||
emit valueChanged(value);
|
|
||||||
valueBox->setValue(value);
|
valueBox->setValue(value);
|
||||||
|
valueBox->blockSignals(false);
|
||||||
|
emit valueChanged(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
void SliderGroup::setValue(float value)
|
void SliderGroup::setValue(float value)
|
||||||
{
|
{
|
||||||
if (valueBox->decimals() > 1)
|
slider->blockSignals(true);
|
||||||
value *= 100.0f;
|
valueBox->blockSignals(true);
|
||||||
slider->setValue(value);
|
if (int(value) != slider->value())
|
||||||
|
slider->setValue(value);
|
||||||
valueBox->setValue(value);
|
valueBox->setValue(value);
|
||||||
|
slider->blockSignals(false);
|
||||||
|
valueBox->blockSignals(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliderGroup::mousePressEvent(QMouseEvent* event) {
|
||||||
|
Q_UNUSED(event);
|
||||||
|
if (slider->isEnabled())
|
||||||
|
slider->setDisabled(true);
|
||||||
|
else
|
||||||
|
slider->setDisabled(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
|
|
||||||
class SliderGroup : public QGroupBox
|
class SliderGroup : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SliderGroup(const QString &title,
|
SliderGroup(QString name,
|
||||||
int min,
|
int min,
|
||||||
int max,
|
int max,
|
||||||
int decimals,
|
int decimals,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void valueChanged(float value);
|
void valueChanged(int value);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setValue(float value);
|
void setValue(float value);
|
||||||
|
@ -27,6 +27,8 @@ public slots:
|
||||||
private:
|
private:
|
||||||
QSlider *slider;
|
QSlider *slider;
|
||||||
QDoubleSpinBox *valueBox;
|
QDoubleSpinBox *valueBox;
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue