From bfb042482b4742a945db951e69b1bdf545eb12f2 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Thu, 1 Aug 2024 12:56:25 -0400 Subject: [PATCH 1/6] Add some message decoding to SDK and console app --- ...indows.Devices.Midi2.Endpoints.Virtual.dll | Bin 258560 -> 258560 bytes ...dows.Devices.Midi2.Endpoints.Virtual.winmd | Bin 8704 -> 8704 bytes ...crosoft.Windows.Devices.Midi2.Messages.dll | Bin 247296 -> 223232 bytes ...osoft.Windows.Devices.Midi2.Messages.winmd | Bin 16896 -> 16384 bytes build/staging/version/BundleInfo.wxi | 2 +- src/app-sdk/MyMidiApp.exe.manifest | 4 + src/app-sdk/midiusbinfo/main.cpp | 10 +- .../winrt-messages/MidiMessageHelper.cpp | 123 ++------ .../winrt-messages/MidiMessageHelper.h | 29 +- .../winrt-messages/MidiMessageHelper.idl | 19 +- src/app-sdk/winrt-messages/Resources.rc | Bin 20054 -> 20246 bytes src/app-sdk/winrt-messages/resource.h | 6 + ...dows.Devices.Midi2.Utilities.SysEx.vcxproj | 15 +- ...ices.Midi2.Utilities.SysEx.vcxproj.filters | 12 + .../MidiSystemExclusiveMessageHelper.cpp | 110 ++++++++ .../MidiSystemExclusiveMessageHelper.h | 48 ++++ .../MidiSystemExclusiveMessageHelper.idl | 30 ++ src/app-sdk/winrt-utilities-sysex/pch.h | 2 + .../Endpoint/EndpointMonitorCommand.cs | 5 +- .../Midi/CustomTable/MidiMessageTable.cs | 262 ++++++++++++++---- src/user-tools/midi-console/Midi/Midi.csproj | 2 +- .../midi-console/Midi/midi.exe.manifest | 12 + 22 files changed, 500 insertions(+), 191 deletions(-) create mode 100644 src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.cpp create mode 100644 src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.h create mode 100644 src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.idl diff --git a/build/staging/app-sdk/Arm64EC/Microsoft.Windows.Devices.Midi2.Endpoints.Virtual.dll b/build/staging/app-sdk/Arm64EC/Microsoft.Windows.Devices.Midi2.Endpoints.Virtual.dll index e7de8f5b174c886b10b01a57879fcc868e09f7ac..dc0e87a219c3d917ca27d76b6e306b5e3e207162 100644 GIT binary patch delta 236 zcmZp8!r$2i|81*;La-Pq^Xt>$R zgPn=dWV4f(vnr5k%RkQuq{0ffGcp=Z<|~c|s>my5X9Q|1E9qteYGW#A22pI4%YkN1 zURN6rB>C#z0~P$MJIx5RAt(&oKg*DJsX$(NX1jGk{ xc*Suhh86QcJO&1s91oB!0>n8dm>6;vz~#38H)h(K%_z~ncRthhz4Mu!g8-FqNjm@l delta 238 zcmZp8!r$gg~!F*@N>W$uKWdzolGf#}Zc))MgInzvo%-+Dw8nQQ703@vsd;kCd delta 36 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≀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 literal 247296 zcmdRX3w%`7wf8qICjVF$pN8Z4%Hrfwn$C1w}I< z_qGFgTaM6r#kK_T*37hiMZvbI?IlPbp|O>R+FNZ)5VgV7uTaEhikR>J-{+i}Gn1Jl zpuPQl_>1SvIeV|Y_ImBL)_$BDKC?kMg%BzD8yFDc$GGyJCjURo{}ds{6#Qh2*y;LB z(T|nue^XTFYg%4-=iPVQes|-S3YRo~`O9~#C|rD7;obLqxv=TWh1c9zTll3rZoTc2 z(W5iYH$mSpC-*z9sVjeD{Z07611~E0J>dtdUlh1j)~e#Fe%u-Nc$FrM_tsSuf|4XA{y9a%IIEIb7f%f!)`jKx zq~UFcXyf(I4)GovIOY^>lZ2Re$SLyhGxBe2inuIY2>;a%Q5ShQ_(q%U5Sm2Pe0MB@ z|KP%Sa>LzO`{h zqY%C59LU-uTgTN z|1`pDoH>2v-Cq)geB6Wg1ofQ+&#D=jBp^tTF;Q}$X&m%-#r?dXm(+~W2@U&Ct)_Wc0E_W!h+~p{H>^dbl z&?q(uarMjW_+Oowp<@FB#|TF_3SPB{ar%K>63#JDd29yXRRH$x_6Ef$Q;?$ltx=&U zABF@dnQR+v?sR-mAE?4_=Lcg0+Xn__^f;ZRe3v5p2b}nO!>NQkxb{P`EF9Qo6kcO2 zywxLv_hwRfMTz099vZ)W@$l40e}THP-qznP^mje_+hz7Ql&HVoR|faD1@u!^zY*wh zIwXy@gMLoXuUR;jHG-cCaNH0_!y`^dh%_t$4WF{%SOEMaybs>!0z8R>39k$A`XoHy zXu^x&XouHo!!Zi)iCB26>qiXljzsWQ4*_rW(D*H~!TZ7_E%+w-`4(u=>r4wBb*6_> zKKO$73zJ0fkWl-2MD;&<&fT(^yqE{Nrfh2N+9J~W+QfDLAT1pKc3Ib*pzW>MB50Mf z%cCOv;};DKoNMU=e=m#u{m28h-=tR&^}&C*pKac0=t7qQn(vc5G-R=#FIbS zC$IROdhEeRzWYIaSLe692h+v*>;5d9zlMFAd66P!{8>2Gli$6oSMF&4z}20T5!`J`AEko4zC9nUN)sKAlTg_cPZNJ<&3iv;)82En? z_&=-|_)}g3pSxwp+6Qmh(f(wq?8nkbKOQ#vVZrGf2F~nxfHQA+I6cF_nd}7|Z*n-~ zi_pUHe7QZ2FGsSUsh9Fsk3Kdi*Zt%0X{(<${t<2*{|3P|`FF-}{cv#n!@zm40dN|IhtoC; z9NLf5XJtQP=}h@MeOC4(77pd@^bq#L(zC+YenD8UNjc80OgW zOZ$$MZP;Ak7}r;2#!F*=yW)|{)3p5+h<_>^WBaxa49GZYpi1mFVka$pe97hA$J0gF zvWJ`tqDVInW(F$4+VTe zOfQ6gi4Z?q!uCwmdmF^29*5Z3i+D8GrG;Ms-q|Vj{aGIz>N){m`v_v*6U`#%fIm#1 zxF2*@CyCmERB_i~@WluIhNjHcGf}q_v22esE7YLynjL!i^uTk-%+!!~>wwS6MU}wO z6FmLE9?7S>HWTmXBY20GIfJK)Mffz@yjSAy*#8gQUk2aalP|*aE)`*af!LXwqIKk` zTKLxwH6QdUIqU0xuN)6Mb3*Ssb3>kUL|uWB)5m+{I_mn+ujRY*^kuIpy2~Z@FH_X+ zi<*|Ly!fs9m0OhbWn0mQi(NwBf;t|^Xewyq0?x>6WFG}B%22lizt@fu(|eo~LsyLw zn<#^tQw!tyfu{7%zj==+dhK;0?7b*GSYIZ>Dtxfa30fF5-Iou#bU~&vie~E#&Wcwn zTNT}d@}yB+nHGLoh@D=*>bgSgB>WXlv1t!umlXejM)3WFQ-rb%{_Jx#UZ4}E>M7Qn z9}>Z)DM}E0gd9%P88`eMyy1IS(G=ZH+@_FkB0CHBzDl7tJH+u5&cJ3_XX`{=dr1Vf zb4B>8kO8Yt7VdVOJy&XB;%(u)6LO(JNAEK0ZA2e5@c3HbPB`q3cbd^34bQ%g{exLbTyi;e#L z63=ozBA?qXGWh(u+1>|`T`4P#fxE_`F(NxpKIrTmeHS2;n_FPpO2#FBG2IeBC|b2K-rSlF30i4v4&lb z=z7a|eQAb6+H@~;eH3_I3SF;P3|^N)*XwP%u9`NT@|1KU7m-%Bih7o9Ua zzgwdG9(R`fKK1!neSZnKTlyYw8vXe-o=y0O{O(Z=ejhU1*-i5cYg{HY>b z=>$&~sU?+o-<~RNsjm{@swI$>;`CtA6n{;N*nYRRN6{?_`z^$yN(<)*t%JB} zPKUk@&oqov8h(Ej`1d$-N;%d-b~*;C9QvnE4?KFRSPO@jRlz5-{GMM(zsH02ZXIjT zl=qNrNnhT7-gdvpyswAP$NV07@W&UQ4~j=|0qz z&mp6?ukl~i>l9(qv~h~idy7SR__Jb@QE#j)OFxi)-zdO5k*T5G7b3p7{tZP~ZK(ey z`rr7h;X^lWK!0j6KVr_2SY?Pq1KJ@D?>UvySJ4&-GE;H-53rq+w~+o>A=$UuXbdop z@ND$4;931TiX1m#vJZttLiX!d3HlLFvko{kXA1Wj3+~}4ed6IZ0xofM6^+viRFmF^ zGj#QQ5hTAnXVLD)NV^#kzQnhC^lN9{p9cXqLUWrukuE0@(=i^QAD^>YJGcX~*xRf< zTacR7SL_sZIpEjge>5LNJW=z`&0JN5*7WXzpXY1-F13PfO$YQC1-s> zxmd-x;UxS(OMZJGUpo;e_z+tuh?DsH--s8kbMV}Y*he{hwS4{%o?G(};r~#CE5-27 z)y8ppg(8j@jtj`#F!k#ABe8P$9^`K$^k^gS1kU3d77P8IFyf#TaTD5@K^%L~5BjU@ z(+#-aV(FSGkAZ=KnP0NuaQcCtM&lmDHl$TK{JMcwWq%m=jCm;cm%&bT!N<>>T@@~a z&h=Tb0OE?PE24gLkMq1xAz}*p=nW3hLEg|F6*{#rVCtoS9fsYE+M=IJeeB2F!r$@t zKK_V1ZEV>vc%CEi6cW#q(8t4=FCxD06JPM2_LuhXgwq+i47N++@2QgZBO7=x10Am} zkht&5@Hq4%z}=77u`vy{%As|TL#();KgyPmpTqQWB}i} zxOSQGp~XMyXVgBMaXn%s%E)%Ka}u!HVCP{ALv4@;!m(fupkH%s{U=PmQ;NnTo-+D> z0y05*9!5VQW8p*K_j1{9p}!2hX&<9OezHRW$kDghUKVuD7Pog`@Uz=#$|>#gEY;vO z<5B8KQJjuQn+<=L^bJ5qBKE`75fwV}Bw}7mPnCx)yJXD0Q^tBR@4X%JaKxEf`j#`j zbO&Ub<68BK^QOJwOeuBG&nhy_Z*8X8`3Dm%d61N z=_GlGI`n^FkBH3)G5m6A#Q#T?Rg;YVP`7nm{xiU_^7x0YYw3e#I_xvJ90^v z>0aRL1&`|Yh;lP8usz4%`v&F(+90EzJwoUFGUc-~wSSh^;jgLxl_-yg;|A{t12Pk> z`zzL+AnO*Upza>6{Aj9we3erxf5VwydhIr?Lu(cKHIHi@s^S99TG)Bdd1c;TY2_^UB77W?t}|^y)%iq+gQ>zXmwwfgVZy8qoWaF=CSk*Nbtr z_*gOoeLwg|EPWR)*TVB4>+gfl9>^wXdF=BkxlFITO=jD}MbEMLs)sm`mtr%m^Dl8n=oth( zDR0*ldsbar!mU@2EhCN8u?8)vpWZUhs$21#v`)qE6*k&LWRAWxX!F1@ zw9!r4tb$!irpJrp=(6xWElk~|9={KIRHciKQ=rK;&}}JS#Z~3h*J|)@err{EowKUE z*5dUNgQwNtc@BBK&6I&7rVLa;R``5LW%K1K-8Lt?20eqp{S~g*j%%bm> zO=u&Hq1Ubqe@#`o)*I;jrAM4u zrISEk#t&Z84pRO|+w+H_?GmAX(k6EkzLK228FBQb%wha5eczc9qW)6ePCC;=yI@a9 zhkD4C*J-nnUll<+E$Am$`pYrguD^wreS9ho2Kd>9G2Ct+W!ZqDJX<9buYvD{S;3Z7jKh9SfZVZQcWI!jLQK>`3H_ za~zgjb;ik+HiTUH;>KNBSISksG47glTSK}*t_+#VkI0k@GS!ZEv<0Nw0qB*~M^m;e zeT26@q--rPWvk9czmheipDmuiJPLiq3rM@xsP7VXD)3XB&_iPkfLw)W`z764p-Y)I zeXKI%CaKJ{MrEec0o&B7m9y`M;fFAHqbifo_q;OpnPVmU{0*zmprz$o(06tM&)7VP z5u135g+9^NPu)M*AEYnX>vT|8;Kz&b;_JnD$LLXI^!-+u?G5GoQT~oLD+2N6{sM%4 zJ(wT)0sMVF-yiq<7v}R0JePSB%(s!w-Tk05@+Ni|rcb_|Hl2R@38y18cU)BV=#v~q zUHW^y80Xv$Ec|$I^}zsq?o8x^5yORh5aakAA`h_jpP&uH2RHI4taBJT=RlnwAfCnw z-0Ur=OB#^2tn+kS9m?Ank?s#a6zjiRcyn%uKKZq&ViRKC(w7n2BFA&UmnOo?5wk6Y zZS93m%RbFbjqOVj+GJh!2eCt`%rTgL{aV@He+N%y()Tvjzq&Mo-m2n1kfW^K+y>YU zO8<`-OJt`A{V?JW#?y!+L%%vX@MwX^>I3`h_#O-Mf2j619~6y3&U@v*Kk%qX5#!kA zN$B2*T7yOw9`QqmUC(T1I-yCTqFWD3i5=E z*CR2EnFC>dPSJ#)`bgRErTc4oEqlCsqJ9{B>4nVpvS;_j8_2d8&Wu~Aoc?c#%X`XA9>oArFB^OH3R=>yu`XEfWKWH&6rch50pdlj5!0! z4SiAzo;^k)-FB}A-AukwPk{fq$=Xu|#^Ic(yjV7u?QI4AY?Ec6b73E3b_e)I8DreY z{K_NXIrA&3nO_OiM)NBtYe*+!jn_3CQ!u>v0#_NT$a>Lrk1VkDrgLW9jkbz~3H+TfDLKxEAvAaq98z``KQc z9v6;Wk6(FjXgw|g&(B1UF9$xBJ)vF7Xqk*TJT2^1FgHKC^EDNJ6^hzd1iMj!e4iIK z%l;g(e;sm1HKaMND#J)gEP)x}B_D z#Rf+;`PK_PcB7xJc|s4^`ua=aVCyUOW%tS`-fT0o@jOXyANpJhTD$O9uekb1O9eD9 z1w z31fF*LKu{vM18U3hc=V41G>*(F7yV>yI8!g2W=Y^k!Ss;Oi`8u^4(vGqcQc`p$Y%O z`=WHV$}WzR39v(4j&f2T7r_rP$5rNFJ11%#$jc%p=Ll(vn2vF*RKfVz3A>6hwe&|P zq#iCSG{)1?Lad{Q?;!mK;(2nB2f1lu4DCdoaVWWd1LO2zjM22`3iwWY!**r@-^loD zgJ&OKv%qi2a+viR?iP9p>d@w6%$>oppbL3@E0;LNd}oaZm;#e|#CtIo5NB(w@*;=0 zaX~a!5^t|KrZ+Ip3||AdhH|8@kpo{NTh1|kU(zO9`Wk#6?`sGfAMAbw^WBnmHvdDv zC(1|aO9tfYquM9-pE4vG4BzJuz&A!up>sp=i+r+V@%V};ep1c=vy1RdU&_is??pNL zI3sBY9+PkFC=Y+_CgjQGJO~Ex85_Yn`#fX?asxil+=m=9=kcz@Z;O9v;GZQYCrp3w zz0(6Tr`UK{ZKER`5bD!T*~igwws!Z`gKVu|M0L*^H^a7m$H0SsPCi9!_Xyzylfg6m zpEHKH5W;Wia}0jQnzAUo1Y=7x?TxL^^!HuK;7yL}ZvuFU=+|*~68wtJ4xYfj`1OnT zVytCMMI9VKTuOUJ-Y6|8x`6IKe3P+;Vq>~oySPE!TA&{;hQEzy@*-q`v=Tw)d{nfh=a-mgH6RR`Px4*1O&Guv&r zK|iE@6zdR_V0f7$c#89l z=6=Rr&?gh)FYOY?agG_(Z)-ePq2nVRi;uzvm@%T1(Yer1s~_}%toRTyZJ0K=FwL;R z3T!a#0&Vd1f8*Gc-Pf5a>d1SHO+UN{{g!@$XR=Nofxd#>rx=l+;Ecl!vOg4VnmIn$ zal638tq1;#g_}JNU4{3w#oxE^g+F?>_y#k?jC(<&dzJnl9>iQZVIJqJ5*pRahHeFJ&c!%pPHfa5dA$;;e6#6WfQOWH*LkF)_}PCtws z(MiN%S%~AUzLlWO9>_BL_deE*uz&1lZ>G`51?VI3$7-hJ|%F+=@ zAM^Qj7EjVnL9XzdDQT-O4tbcen$Q+)_%mseU$$IY!&S?b6aMfFyYw5 z7`P4d)PBe_^@{d|dgTZInB%!o%1IXXmKymT>bzaAw&6YXD&D_hUHYE1k6q|*{CnCx z)fUTJ{tOo&*q`q;^8tsA=Q6%xe#0ui7tcw@45cXIzh%NMGFGu-OxmDCF(&M%jCXu9 z*30++?Z&{Da6M7DX9W{}8)L#K&i(_$eH`$%`)v)#MKKqI1s{)+f9v3L&%qv{-yyfs zh52Sxh>jO=Pr2Z_2h!8>$%v;5YvC`PtUb;5pPDS5zHqYV=}%2oaIM7E@$^L#I%i)u z!9Ux5m)7CEOLVx8cCPXs6|3T5ty-!GFX-Y%dxWdD6zT31>Wm`yPcOuK^4p?+HGXUG zY53cr34b|$+xsQ`QS?OtPx2ru^hY;APvT>U)5nbX0^_FiRV^R%wi^fgpl-wwEue)p zhaDeBkbabB#u2o$St(*a*HgR!d8Ax_1#K0GoW4%1cj9}-5tgkZp0D9O@tlq^lfN1N z95wNyjuZEG?*A~?QvB9@*BgiXOdIa8@krL7c*OVNz|8AyeR6%7bcSD3XXLxXUxHrX zw-p(EI^Kb4d zXVBd$^kS^LtiW^kQ%cY$T5F1y2;GhOKi1E|UI1Plo(uIE@Y@P825^0JA@Z6%Y5lXN z7i-~)i!cWLskLUtL5x4B7oeYnF`V`2-?d|n3v(^><%){277R9lu@2{S3NHemkW0r{ z5#}Cj)zwlXaRD6mmu+Sm_Avs3a23U^PXXQ%4(2%A&TE1`!0>}Ug=oVCJ)(_V!Qa3+ z6~Cz)ppE`pj8BQy195)jE#%i(kN0ob?hoPKlDE@I)}w3(+ySSuUwyGMc=)SI@G$bb zb?CzYXv@5^I#vs(Dp=2Pz9;w=^3D@+f2I7b1#{8IuKSUXo@&sYYg2l`Q_`{=WpWq~ z9O0O%_I1J*`|#X{zOhfgMUI{H>&1LkA7ng@ut1|otki-vl%V%p;8`zd_Gi@Tb&Bwt zm}foWoLKq>=2;KJH?a89ru5G`j5Q{`;4SsuEiku=dVcgT>D=lzp?}k)Q6jl)GHC-p zM#_`g;?|2m7v^m#m(y`ix!h}$%l9#M+2xXQ>PEc5zNwH)+{=DCJb<-?b6yid2a(?? z#QaMG)-RU<|1$LRL@Hul(2KArOE%g_nIdiYOo9JFnIcUoS8mjIqYh}bvk=c$fX>wW z9LyE8!;ZA!kMBSHt08M#TSq&?d69*9)&segcEU4J-&%>aa!wJZ|MM*LoVJL*0O!8H zXw4M>-cu$l+87o30NzB(EjG)!ofhvWgl+^*OyuX6ZD{O$#sDn8aUKWW5)ZNN{lo?T)-1MVLn zPGdQPo(}!z7_Z{j*9rVfs{bg@Io-opU%@~1i=Lp=f81w5_c1>drp~M9oBG}geYfP9 z`VM(!Un2SrnNFnd2Y@H_z01_`TOkkaw6VyEQ2!~N z=y#eavv&P%{J+Wd`zOeo+4XycO}~GDdX%w5`n@!Pe%}n7Ed4G7jT4Pq)bCj)Zw&d2 z)$a@`mr7K>FSP4-M#(Px-u0E#U~moew$jw?8r)AYbenqJ{sQ!x`V87c_1PKRW%kFH zK%ZyY^!YB7v-J7PxVQBAOT*~%x#)kqK99#Usn0gu9c?|k(9~z(uA0vz{aO`$AN;gL z`b<3%Ef?z#U2phWR(=n5pZi^&vvRTpsoHTYhp7|arcbZ-1#y4qdgQTK4z|pN=Y>Zf zctrJc--oeIxCiT)Uqu<~cM;_GZ;1abU&2+d2)6IqeX-nEzyDr)WLf zhdiRsBl0jVmF{w=%UGX#b{D~yDuVCM-=gSZ-67Us&fkCFMU>|=W%pEl&s?#o4ZKsY z_SXck9sqRcc$<45O<%MRxN*;~cErdj!ls0+cAo_tws{Zcj9_Ow{s;9u+Z4TimN5^r z6z|iq|Hh3v*Jb%g8Kr^QNln;Y+P*?hto%Vhk=& zGWrTH5p|jGVoxugwP3%ts$_I$pZ09rk|v(fJ|XJ1II{Xw^p$Yyriw6Oy8*jk)%2AM z&?e^NvLAP3b-SHe-OWz5uPd(X43vEyV|rU!*80T{6x4#}HHQ#m`J7qncir!nFg^_! zeSdF$)~9537by9Cdw|or4DH!^C9|&=@O-HYyDI=YfO~iP!u9o-gU-2p-R4jlcq5KI z!rv-z^@2~370D;;H^@E-m~Qw(@%#!-6?K1ttQAg8%&*_!9r;y_{?*-_8f2fjzlMHa z31s*^r%U>Ge}zo3Z=JTjwX<)I{Pl;>H+MQ>Xy8F$lAJLmqhp%-gS zy7RZU2s|_oD@(&W}De;LHK)Ne=X+&88=-@D4g0qFmM1rUq94Z|XPk zA`j@JuSM>YanAC9QKqSD`JAZKU;s zfECC$U=hZA(AImY7OuuS%T5(c7RTGxU|kh#ZEf+jLE?Guc(MNw^urBW@x2##v(5tW zKy6tI9hte3GPD@&ybc|4LB5-vE=k+?^4Ta)S@PRtDaX{4Es!O`nFl!3lP18afS$DG zh`L{cU*1gYr!{q@Db))da!FlLQ@v7GCO}t8AdA!$@~k~8%Cl_nj4^yT3D2s>i@Ge( zs&kydvuyCpZ{yi0ykq>qbB!g7RVK8Wm;rD7`7%-rZT-U$oNxW zeSjBbeBh;qdM_hRV_Op;H;;ZeaBi&=x`+21qpULBC_{N8&6+R{kp>#*X3=3A=;-nr zbWnvWLI*eIbaE)evw$<~Dq+vZzLH^XH>Z4l;O$Y(rE+M`4;G3M6wz`m^jZ8-ka zw~AHu7=OHIL*ly)`*&rZkeAt`=sx&`$>NXy0uP?V-+tun_i_F~=I@Ptx0i@p#TW74 zF(eK5f5yn0z0zl`e>2uJc9BV}i|9MAnjhFWXIi(#Ih$6SWoR*X>i@isH960e*wZ zAB~oOa3tmLsfzUfu91|#D_Z`xk(7ToiqFE4lyA8vf)D0~2JvH1e~(Audqz_JWVHN@ zk(3Wd%a@F#{OM@<$s;MRTp#H#?BwwMO^udEK4Vb%Wd8Zr-Zkoksr31zo1^ z>Vj>nhc7-A*C6D*)Xed|h&nCU(^xtLHd?Q5sSQo`Nb^`_=~U`YY{iD zg?(d;_ASJzY?JXG&l=#Ex+(I0VrY~3J{$SG4y=7@W6TLVl|N4Akas=|oMrz^-Rr|# zCv(omJe08qk9#vaRg6E-SKG z9Qyi2;CCr-1`Q7owwEy>;7>&zJAFJhx)45df}JS46ZkK{Z`hpDu1}S%&w~A5fc!TO zJ=*VoyMEXm{~L%?CB$%k^_O zl6xoZ;!eP0yfF*oNG-}?ZS=YH+m9oT`5|Pg0DZFNx3Y21GTkWSJvA^>#c#&R#(a{o zXT6>Kt+8L3G-B@fduW3^quu=wb-|l`*1l!h-WJRQ`Q^T4>>Dz9)iqY+A+NTK@$PQ; z1sT8{yo&5oe+{^Gonw?ajQ8{#zl1qVS*9pO#>x9xW=w3EhpjSOQ)QVhmKhye=Id4& zt}93TyI5vaY?()_GFw$y=7%hUd3NG#;qwivOi_j`^EAs~KHXmCKdmxbGi8}4S;iGx z=5eb`(P&xbah6eI%Y4TwvvrIt^9akN$ClY@l_?r4%dBOYwAeCFT4lD5lV$uYlNwv* zDXUCTmMn80%cR7X30Y;fX3H{PW*HnkZ}0olR+*w)S>`sBIRZW+KVSN+^{(Yy`R?<0 zM>*qqtW^AsQ53(T3IENw&xA5NaL;o+>hOoS+K>J0{?Yi$!{4t`(*4Qo@Wp>I^TDtM zl-2ieW$t%A?8pG_bFcRVkq-{5&By~g<-Eo|Iqw4BM&@5=7HZ@BJ?+5OSz|x``)P2v{!!2@o>I~b~gYR)N>X1Cew4| zuJ!YfD>CxGiO+>Q*2n%Dc_HGY?*4@Cfz5y4oa0%5`x5A25OX}a)xQ*nl18 zTu=SfSleERTo21|j;9hZ=#P;O-l_DVjX56r*r$-|rH#qPxq<=AIr#Ahe8T^J)W|tT zbHJFp>4lAi4P$wMIi41brR)psaye|5l}{qg?=y3ugm;Mvs|>hai1DJm#v{+BV>|5^ zYQcQPkO?p52qhiOed<2&cM4>JbAjGs_|A}t%39IU2^$r_JD)j@{u+JYSnkEx$oT*# z;I*4_K{`}|cGse>*nbLr$cIcAwCIFPFrMf_U2Tb?{}^x>-|~!#7VtKiYVlKO`7&#vBkoY_Y*?1rC zRq&U;pTY0SV$NYr3|$6USO7fU18sZpo4O4-ikZ{p{NcTz1?RC~oZuf#4AtQo^WMZc zz;POQ+-N-mZt~d@MW16nBVWn8@k8+rIJqPIian?D1NaWG3;U73(%ZLUEhS>WF3^Xx zB)_=6sOtq0r(7V{KQ8uF_vvY~)@$$G|5; zJ;wgBJowU1+MDIAHS8MXa|Qa{iF)JEN7}5{fn)sIO6GJ&zhw6L=j`7eV-F_# zklRwB*CUV3zMVqf7GQtws!>?i2VO0NE?T&;EOWgUj(+rsXGGARw2kSXH6QD>2nRXU z@I6?=qk1zmj-x9Y}m#3kLz6k$9l(Z=-G4Vk}+s*A$EvcX<#S%mE#} zsn}P~ebfrB*t6<&X>yNs>Fm5RnLl@lySTn9QQ6YZ<<&BV;CZMm&@Y}%20oN$%pO~- zDb8u&y*?K*kj$=8R~sQmv~Tse^7rS=>!KL>vhD8$-?_K&6Q=HPK9urw8DxQR82tdw zmte1N=vAD*Y1ojQP!ViGmnl~bpj*W`Sjz(6HeP=sygz)UK4po)2RFuXH_EHnyWh#W z*e~ohWhe`}T4wQaLM$(eT8;XC@UaN6IA7QPAkG*>iHYn%q(86+R(}csvk>(-HpsRwh{GE)!uILIP=46< zXtZs`E3aZKNHkB%+~K>}7s_j&c|D3N$0~t;iRQJR2Q1paq4;>KjgLQoEp0&mEnc!8 zJ-|`+BQ>@k?88Up*R=W&>P*+hPTFSOs@kI0Xg zv1ajK#gB>+@}uSRd9}&-@sB?b&5yArKgO8+7-i$f!mE<=;}3uvuP0nfLOsDbDe}Cc ze3Kt`K4hDEQFn%Vfvs~fe5kYO1=njN@?VD13(or|mTe>ct-sqgi^vc9ZEv zW5w7(d}ufI;y;Js!~enFPU^+?d4*nta5ds|<2(!%u}-g%bJ(tW%3{vLC_=pD#@Zgm zJP$*^&d8Znf0F!*J=3B>i11phLx&G3&%+ptx{1!ipxt(%KJC^&WB&%=Zphd@BeE}~ z#h9cktN1HBP)h&NRXF& zzj~uem3p z3b_{Qq^!@l96HK-nU_Q#IId2|nqug1M;qgC|A{P)a>0st1H^{ss z+OT3{=6Jj)3);&(&nu8C{O8$)6mFyxRUGA2K$1c_tCfHPQvez=bay#%>N(m4zHMXqyow>p9ixTc!4xtIM0eMp;%eCVMi z6QB$3+QwTp_iaPc0YPeEDogyU=*aw9X4 zub2V8vHh*!=?U;m1z-64+xR`DnEAvBp-S+u4D>w-+tQ2QYGOe>z83}(d9qjs5I8paoyUh*t-bYZg(jvb$h$I zHBH~kZ?DMvRK06F?3B50wg^7teW05gdVskp>gIOtBRNzmIu1SL3?7<7{uyU~a=h=V z6#60Vam9W^AD;K3K6COx$Uqb5<;I#%dA&9r<>1_1FZ=>q#Z;Zep^M( zbC*K~X5u~9bE5qX6R+-u4r83E zEFK-yoKAhiwPI6cI(68o*ZbU8TmTr=qqt^I?W;yk4R8){t#dZu{TJGAxCnU++gdxW z^}^V8pkkpo&b532tmX3|hTz&gu07;h$!(yCwO+d90#WyWF}KS#0XpC@AIA2H)BGjW z{T$2%j1Dd}@!GX?$`#%_xDL*#U;Dh)VbO@RDVU8uE#aEoD2-CE?(L)|Hhrq#Q%`@Y zApPl+SLJ=0eJ0Q9mZP7oPJP$a;`leQmXYfW76Dg3az8HD>zmzM^YNu7|A7LWH$EkG z?dCO;#LhXjTDdP>jIS=!R&|3{tH8TD$Q;MWTC8v87~yr|9MbPOO6E_+JUw!~htkCH zM)djUK+AX+XaISrJKEebo_R>f+In^1Zpt_iE)H@S*^D*RANA*Lh8O8E`5pR58CUWg2JNWPvUzx^JoP3anKahx6Y{ z*=9T1_C78;UI8tiTXUH{zc!j*wzntajGX>igu{AGfH8kAbO@-Q$USAf9%GRe)6~}|@k6(PL78yAR)iX)w{3-QGD4H=}kf7}zjAveRoY64OZAGk2nf8L_uo>`ig#Il&!$Mm4 z6S;lc-WsT@19|L2J zeiO#;q<#eK%kAcV(GKX^YW%Ie2J3k7M;tv%6usVj&wT)&#l7bU=An5lcIdb8y2PO` zz}1MS63>sjfx|#mT4dZy#~uO=J*nkbyI)g_GWErI z!L4|w?Mc;y8m^xh)l|KoiHC4hWd>V4F#M1%$eV6hbQOEik#&GWYt=~a8l6WC* zfsg%l6BgvkvJZqsyp^q4$U_-0JA;^W+W|Rp=1(II`8eNnK5(P0TliJLbSfR~7_$fU z3-u#$$5ZgxTdyt8!nfoqi*E^5I*svjF=S4THP2%l!np|5doV8z9&k;zSEyX0RgU?k za(tX2I}_t%lj7(;x)oyw%Fcl=IcK!7_W*pUbKyP5)N1sTW8%3SAIvq@iQaR5%UXBs z!n$iW*7CA0Xz?89S9vezz~c6h1ivlnIx4VM?Ayk89ly@{S-hhUTsc(>R)cNYfJr; zGfn=bkBomACjV}*^KYZrNnSI~DFy$kDGOK=9|RBWK2f%ffAR06T{YLtXM=Z^Z^RfZ z5zky3MBVkEPtVs4o@HTee1mOm{Iz(;`LOCt#$u4g+C1zn&03$BS6QJ&q%F#ANfYIB zw*8`Qz?g4}h1HR|idA-7z$;3Li3gHCz4IcvZ6Mf1g*?_lUZCL7&2V67%Yg1iTtb zum1fkdF8&#;ML`Eyt->BUco=-xV7;1p?T%M(-^zTtg&l^w$HM=wKm)5`l2y*(e}-O z-TRk}U$j$b=W-qnM5C35^qXcHS28+w+7@#~;^W@DGt?iF_aeLk^{HDT;x9PhG?S=KY= zA}l|HW0fC1_Aaa~wZ<9^zJW2`2x-Ii#`y*sXu7M)uwlqC$+3pxgf-qI8*2i$7Z8Wrv94^nr361neGzPYvIpvjh)?>LrfXt%lRDY zdc^P2m%A!L&#dmXwPGjBN&himn#F&0aj z!ly@GX+7UF4&wNbh_*hHwibTa&lMbww(U0x^iO*wG7{w+S?^25m^=82aKJ$Jb=^9SgdUrWSo!c3ApW z8ub0yRZ;qWh`c2EXu%mIzpW;HuN#`a!h^M>h($gsZG*EvKHAPsKwB05C+R*EZ971d zGo@|UEQ7XRu+jFZB(&{9o<+tB%T3x=fVP(>x3@hrOxcCK{mAsiceH66J`UM^D{HXq zj)cCAXG7nM4f>9;(f7vT=)1(E@2sKe+gAGV+1?=X%^w$i|04l?rR^O?eqCon-y(y) zKfE$(8~%=bcOu&mk>6UAzLyS7--d#Z&-Mn9hAb^ykGu@_ZgjL`PC@1yAC1WoM)|PK$menX z+`H}Ca^GhLW@yNB<^ooIvm^M@Kd|Q=bD|62&oKvQ&6RPEjAOeO`6|v0alVXaAaIWP zugGJZ!dm7BjI&(A*uRzCgS}9*-xzrGEnK;F?R<>)#(Z0L$eM3EjC!ju=ZEhwO22`* zXZi%piB*_qa3tFEUa0#w`%v~rpR{t%Y5KE&N}hZED`FYaE+6Zc|APBJVm&3#k=TR% zm!2v`-_2{QqVM8$kD~vKSEoaNUcPte9rC?H|B-y}(4Uj-YL)d^}71Yinoj;ThnXF;6f7b3)jYmE)4*wUmQ4)d6>ancX%AB}ywxr;hkgZxd;PVWh zFxQCx8+gt+Dz3kg^8zS87x*Vzv%1)%0q5B3O&VbNOwx6omq}X0<@e7;e*Xt%e*fHP zexK{unBV6<4d(WDo4Ngszi;IDvykJj1$>$32d}l4 zG$YS{CGz~sl#WH)2J5hdW9qOUIeG6gBhO#78M$QCkL3A(1pM+Pe*0vef1?RYiSm=M z(AQ%!&u_vk{4VnRKZ1>MAkPmR_#HFMSIF;;GS~0Lyl6XQW6^rZ24pK>%7%rPm4|HG zX5f~K_+{o9=8JR97;$bSMs#%VMV?*ei_x$Dt$guOr1kLRE z;z*1M9WrwJS)rF;@4P7YO~&ttVMY?a_kP0|D^{Z|E5@W={S>eWhcK8YCU3|u?AO9d)(ApQq85U3cDv4`A1w2!CET`Lldz{)p8ke~|n7Som}Azkol> zaV`k?b9Z9?tVzHhD`%gGKmQ4uo~dn9?=bjtZ5)68JsE$xP5vw!nm?UiPB8Y2Kz}&b zoKSz7{ssK`f~YGZe{M_6pNVJ4pUcjMKZ_0i{Bc&S{!C8BpXW{fEE$?V{>J`U3o!P) zid=kcE%V0Na@@h1ARX(a!i+H(du+ja6s`ea{Acl{96mt?a=>1kspkHi5&ukb=_PGW<6uxIFMGio@?)TUL^OLVr?1EsM&FJkP7m|%S( zTCO!|Y1!oA^1@y-?>-B(wB|Hc0)|z85FH;k=~x?~;|9hv@jk1}xx=5%g~>QWplpvT4`% zb~D%hQE9s5ENI$;Jnot3yZZ`*reCws^d$pEa(#cmq-oXAH1*FsGy9p0p6;@b$9|r3 z7W91h4C&ea34@-Ww9)f{B=nT|UfR!PCOxkNJujE`GojvhPL0~nk1C@9_s2uipNvkd z_cGs`WK5cMhBQ@ihAh{Ny)`4M_ZKFiDPv2<{Rc4@RJ%xYEGiqCragrQO}Um*fj!+k zN^G)V)XqiysYBOqJMZJO8~DbD%oBf9yD|SPcya(a-ZQZqJ~Qv`xAA1R0b`Keh{*Ys zrkocKP1DXS2&Ja96<%gVK1Y@_FwOnO>% zEq_7g+V=>(_K#++9r-jL^Y6&peHzbv%(Wv2SYMS^?wxAp*0{F!@t8ba)W(==dV82_ zuliKE`g!Eqk$1cju<8et;9r<)KNo9{hRn53kh%68nQPApWh3W}bvdOtqetdkja++n z>Eb^y*PdO9JbdU@nQNbby)8MBTzeYoJ@657?SGh#ScL1mThsL4{ZH~-dp2?*%xQC< z_c+`;aP=G!dN1}VdWseOZC;n)Tr6I3e$-dAe#!*)hwa}Bn)5l%DX8Qkr!OkOcg;%hU9*K+ z*t-yO4juTuS%>I|hrRW*5I)QkxzRq`QSn_Gw{2f+3*LwDe6BJ{cVm8HsiK8l*e~qG zA7e6{OC-OWU6KO5OVwh&Rn9#*8rB4PXRP}SV9&^id`E7b{7xO)%fx=d62SEVZlZn2 z!@`X0L$<+eNer_H{7Zx<_a*UsCC-7&0j}upj10f^eL4d!&RLM(r@QL|@)dF?zh51@ zznlAJabDH&UC>$8FZLhB{!`%FcI|1#q~T~CyMZN>=Rgl=YGgM z&I0=pbErz>TZOry^8tt7wCq7Y`K~bTTZJpFb`FoyF@G8+9hf8ZVV@u7h>mlgUptJ<#C|)B49ExQAkUxU9y5Nsaqc+iF7|WCm=JSf$k)rcv0m&mc00s$@!;x%0i4VB z7IdlsxTEjS`5ht;u=P!7<3z0ox@mkboOKQ(f9yb=wTMrh=>Hbf<@^}?%sO9T&`0w$S#!jC0N1q$&1SF2|m%%R&G5^0Ai`vUddIHgxH@n(99w&@c7@bB?92rDA>u{2_11!!YIm z4Ouk4AxymX_9vf@90guNUT}_<1Lux8L#j!?_ksWKp_lp4*T*nkyaxU1#lB<8!~IyB z2zz#bdzg1QCdxCKjlJTS=g$zERP4Y9n;3 z(%7rIQzZ-@8E~o zAL^}ZE50`YJY1L)mTNH4Hy3Oz`=X*RY{#t___;9#Sl_Q)3pmF3^}N(e&QotcmwP-N zl3vh{Fm=2SZ7f9_>(E9M+URv=h7z@7wNW9|WiKE%htK;Q_rWF-hpdH-{k2h@ko&=@ z6FzINCHEql`hYnai8F1KVTXPZ{odz)_-ooBJMFL)Tu-re3C?GP?6vI?`g|97g!4!h zoD0m~Pa!7dSiSZA%8!JfCc-5wGp6!Cie5(Z_=QCfZy~9Y_4xsg7-jv zxc`f~HWRu;`Sp$8ve~s8dD3kdQ}Er0LX1PDMOqNwCc(F4u$FwABj|Qv{e%nm#Y)hN z`tBR2uV>wRP*+tZbpH@Ckp)?3p90<~x!o?@H#=N?)frsB{J|s4#|H95T_CL*->oqG z_kE{uz6YiSHopqrs0}iB$RYX~fX5=_N9lidnLbh{d?f#C1CJhZ>iA6>u63?g*o*;B`Sl`znnU2_#hg_ zY<}BuD}0w^`&Yk%aUv6EDrDgAb;Ob!vwx2(^*;PJ+P5*iY2A*{V9vlM@G@N6l{1OS`kCgEO%GM3zR;>>)?oijoIyBw&lr{G*2`174>aPDz>bo}A(bdy#^#|G2sO^h3qg9x3{M38%1$>f>sm7WxANs8p;fxCOo8!d`z`NlE?9+uD zNBW(CeuMA70B-Sor|-Y;uk6R*^Io4}U%+#$Cp6A`#hNVkp~7kKoPF8(gm|Xi}Quo$kdm>WP4i`yw_yE3^x+y72oDV8H&sSHyY~lr2EL#t#ST*nSDx zUQfBP$#ppvO*6p&gks*E1tmIEXFxMc(@B=r~+DJt}na*GWqKvWzsn3$A?%} z$|T~YS%6=*$QitMgmq`~JO$|gmM1ELb~qbh|71=Gyk3s`P59e_v5346M0lSa(!d|e z0_6vO2Cg}ME#Nuf@+_oX=$D2%?I;rf4e0BYp$^|OUf@|q?WjlJ9&=*y{Gh3L&w0-& z;FA$IWQFc_M)j+(*pP#FVdoRcf%{R&L9tB^0LKk~ys#MGpG~vL0e&AVi^{?7zQl6S zjdrZ>q02L$pqG>dshh=7d;AUPre%-qy7@#Jbu%aQAmm^d^i7trbhFsh&0@ng7s6il zA?B(8TRf@hT35|WGxL_@qdgZwJP!9F-Zkm^QR3al04Hg@3;0{mKJosz-Iyc7c})W-Z{?-m z!#(kd&mFhJuTYh2J#Dh~G~Zu1Sv;LK*@GOkf@>wN4qU5nb>eyrt|_=)i)-rB@vtTU zFWLpSk%vZqV)M}9w}oJP8OVz=U+h(4^Tk$f*Ngbho=0YGR|Q;-QMis*X9Q#}8Zsm0 zkU1+O=V9b`b+luT3r@ktQom0-h0c6g564U7LP#s-L- zD^SKWAmdGyxKCleXDwoRjBC&f7jnPoLkD8@Wrtx)Wu3(+hg{bL)>$L;8Hk}&nI|&q zDLFEag!pmU!D)es@8g?2%bj9+0D7Z9ZyJy*e*ShP$atRX=(k|pYKt4&)`HJ%u(5u~ zb0_Sq3R+rmG1t~m*Dx;Xui{%;h()I}pT)Dup1<7_bORsipn5|Y{4eA&okE`TX60c{ zVO}gg7w2w@LX=E_Q@EF zjXt#sy&bZ^yizc(PovE~mB0DX`{S|t1KcSWlr5`ol&xyY7XFB{y$|+W*>L!;io^ep zGUmJb~4|=@mOaX^m5ia|6&p z&KEHUZJocwvCjt`w#Gec&rSnq+lH9lZ_e+~4n^m8vO?egt&!93feiCq{QQo1$?$>V z=PQkTI?p@J4qbqG(fIc<@!T?}<^(rnnioEwVPQywOQcB?=;`s%cKKARtTJ!17X{3abcO`BJ0<^na-<{=&!Wb;6m zQWyFgURH&9j7sEcIA`?pcIr?I?2}rkNnevT)C;)NUKu#o7)!u^FvC9oOTI97oQdyM zVj!NW;Ji-C>xqkvu{GYWDFXa>`Qeze5%E3k(#W_+T5 z)+vk^1DAP4q7k$eLU4eEw6U@s6lGqpfyqx4$x~HG~K2iHqW1ef7BX}yG z{(|Kbi_jPG-7@NV26E`9pcn0qQQZ@eyLT(2x-*%>$NFb&40woj2=`+jrHbdw?R!&= zJid1{z9TL3_Y?cn3)XMu_vG70iMrh54<5w$EYCaRUYkS6qgO%hJ7pd{w{I=t^oKy3 z!b~HN9(&eVZs8*?TC<@rr^+IW^Ljg&KF)d$;FQf$Q5EL#F!Cj_0{1)VKzn$b@` zgmE`v-h<~k(18a~XBXxvX!qx2^G%2US<; zJCpLtx^WFI_LTFi&|;hg+N6w|2HCjFr>vdmnvL&!IR3k43eI~q_cLRDI4ATdbhZF_ z{5H_1!6yG)BVg(6F7RqDecea@ z$Hu$umLCM(Vcs@5@9N_EIw?tC1^zAk{b2s7AF;o|B>nvhe5xU2^{o4w7uVk&jE{+A zmHplQyIA}48PDktT!B~{W<>X(Cx4dwk6v^ZiBM7*lgzsv_pQ_+dBO~tc}~6KtB8?%_8>gYQw(y zVB5TTd1Y*~75C2ays|D_+wtrut}gs;hwV$jclz34_s(CKS4Ml6!QW4K%1bBYmGK*X z?JvLvqHHSeFF=_}$P;bDXa7m^6Tp0m-PX+;LVg~T@)K+C>5ox{BJ`LB{};A_cJB?R zv-CyW_u-FpStpd*P@Y;wJ5jCVO`8MTUag!vZ3}+S#Xae<6n3Kmzn3ZNCI%}#6wkF>0Cv;{x9;!8`jnkn>NXjVF#at|YV>_sU>9^8RmP>0+nJ5oZe4I~lgq>X*Gg zhp{g7pJ6LT$MxqG;F!!-Fy7;MuDXox-Ehpr{^XeN-Q0%w0(O3b^}U-{K4JLy3lAE0 zhV`v{O@$EQ-(c<(IdJ*Cn>y4@_Pv`4s82hep%g{(dzpwg?72LJeqjn^EiT80m{6`W z_03qHFt^8kWVED2;GPxChQ#^8#sjf&O`&S!Q~UPC=2O21I$8PDHrzA*pbpyOKK5U2 z89$yd;5XY)#b=q|N7FhD|qI#27lSuZ<^cPu3{Y@_dT3r>@{^G z#`UHy?5=RCeO-X%PG2bZIK+RaA&YSf&X3-MGLi2zAWzHrar;@v7nIm|B zxz+j2H5mbi=tf+%zu-Y}oOr+GHuh2CyX~P1QJ-~L?;ca862&PKA$QloZf4+*ae2g# z$GJ7s+h4wD*)Js|1lKJxRz}PPJPILG7o%V7s~dkVyr;b8!e{fD=ZOqpebiL=-CSR_ z5$_tGI8T40*zmXC!}_2$z(d><_QP-Af*kpYbGJ+!C+UgrzN0QOnU^+OJZbcK{xX8QkJ^X7D!pj!ailJ^VNZ){N_g@ zSz3#AEp}PTLOYLur)~U3x9wXZmMpEuJIc~ypH_m0u=fVvF~Pc^oRAB0v{A}YR_Mt~ z#HQWm9vkW`<)CEnHk&bSG`=XoaaQ=iE5Y&U|#$r;`*D4$LNxPn1@=w*Z5u!i^^x}InR{x zw2qN_*@JU6Y7ctC<^I;1g@7l|ZQ3@b+y|J?<7_Iz!M?)|o=Fu`f7=+ju8q1~cz^#a z^i!VSR15v)xlP_}pDy>^C#LhvonGLGZ;y4-NbQo=W(P6hVzEC*eezmTt2AHla32nV^Q z>TTx)eYo-)Mc0GY^v!6mcOvg3zyAdqd2!}b0MB^lQx@{x-q$_s<4z4Qet?+L!ms{y z1>g9}3Q4*h@`S5e$LN(PLmMyqzr24|d1k>h(ogdEaK7HxHSlO1=;{IwiO-+$yYh%r z=NV`ZV^2Z3vtSy(|G_%-#h@Ab!}bGa`(H=<#Mz7XW$d{4~_33`->`WJ#*A; z0uEeHN}iIR-UpP91$!v3hOGHG$7`Nj=8-fq_CaXNaQ+s)jk@T0;EjE)636)Vz;}zL z{-*v}KJ5Lghb(#*DIJ8rUFmgM!Vkk6@d?8LX_75xH}C)$!R`nwL1&9-fFxqW$Myj+fr$mMq- z6Lz^&F;_*o_C9XP<-x&n=|X!xlg5MO5;)l9vY~-;ImwdC?V>SXzm{_OQdBNIl*{52 zo%;h{$Q7H)os*{3U24kZrI1VX$1ayg5l_X-<(uX+DVJF&pYP~kKh8)lfxE?f4ftuO zKdf9XGUXC=_W*|&xy*EQEXY)bm&=7XPp<`X=>*=VMj)3sgF7OZeWqNV8b&VXLuOzP z1D_VtBYN|?S@#6$!uD7^l{RKiRHps4Xm1Vh>w|oDoA_N2SKg*Koj2L=d){p0$k6!p z+-T|zXr5GWZ2a+nKb|sEZ(avp-y2?U8hEyLnW;Ceihi>xGX;rs=7q^|wtQSfXMX>y zSe@xwYwFC@|Ht0Dz(-Y_{o`jhglrNnfrM}qvLPaypvWyiRAe_nOvG!zJ4!;JZUnij z1YcnTUKUZCBdCD3B;X~9qCr4OwVHr!gV?@++G>4U6YvtmT2!6=^5-Z4Sn+inJk4rl0ct%)h={-0c5QWU0yTBl;$~^ z=EkgJ%I*mu2mdiS|(a*H=Oy#>v=8@HQ z`JAI<`39THH(jPZzwPpA@IT^$tlv0{vLefOj-@^(p1X&e$~Ru-F|h6O0=8sc5drs(F0urdf+d=57h&Xg;Eb35WKnZ zu9kY>Jmht}dO$medLZ7U2YTsuAWyR%n2T^G?z;0X{Zjae&WMN~I&qBD17lk1fnKt% zWV5e4n&2;UUV`ts~=mGe^ys-e~eiiEv z&H>w))0Or&$>ejGD|1eFW7}g>O^PYa6Ee+&w$s!ni+ix82Wb;D@{s z-|D*YRmk)72vMiD^Z-RgP0L;sU{-sjMFs^^qw zy$;Wwf@uBsgzKaAHwpJe>)QxZV)Pm#K1P4th>y`Q(A_U#z}CJ*RZgEAi|p=%AMquJ52fL%6Sl{uE(KM}3{~K0+@wU`PGeMtn#8 zNx}lVzQ%ZO*H;rnjPvI$c*}) zJNIDd>*2~IVQZp2YGI17H}QU;AM5$(vNLIGs&aTzl&uNR{gkb#MA@1Sz8PX`s&XU` zZ((bquL#%v{r&BnS0 z{W5!?(1ARkM<3RlbNOg*LcgO;lWSr^vAlVVHd)E?^>?eaj)yfcxfAgzQ_h$ z+7XyGGs0%rs%qdjo&DHL8wu!*gWb+c8v)X0$BKNfjupDsoSrrpm3JQdF7AGLk2I(A zo9yYJLAwd>g8vD9lJ|kp2Kx6H+gt0u9`yAthD>OBXTkza?+B>ui~;*J>hpbf+CWWb zdJyIv{GOM_O+fpm#bbX3_pWkRi*w+{{ok^9e1jI>qV<6xalk_5<# zGs{*{k35a?M~1dB<)RMj@EW8UlLEUY>|#t854jr_CFKI^g=~{tBrg?v6B^`#>HI$I zn<3qp0a|q+4dgE*%?gpm30@^fj7{yA1%D#&M_-Qgus5W64W4wXe9_=Zd>ZPcFF@VG z-RYwL{9hXTqdhAh3gJ)q`$RXBM_ECC1l$j}68xhrnRhsr^b=?L4ypc~pDOyd&806B zw&W^@ZGi3^JrAa)e#5-{qmsv?2Q;UxwWn zy5<_iYw!*4jdsg6@!Ydd@UIl#T%LgYavV2FgME-`y`VW^0Qw-t&X9DbKBz^DK3E4? zWk06B1@^&Q@SHkm0>a;;eAF%R&@Gcek94V1ZcM@Wj6M`juhigM%%#9{qc7LDA!pQY z%=dD%yIG$MMgCr;PtXUM=QXfpbDf%P=7Fg$^-`bIL7(uOA<3X&=o8dox1mqE8T#b2 z-?gDnAY(^yzmVnnUcx3oPnM?t3sC8maQ$uv=&F9lzQ%p9!6-9jir-rPN3vziFv*nM zpD<)f?oR|{szAz=*CbQc{R#7!K^gObUw+68zk7jmt6|%K_N^1`>rA8idS1lw^>rhS z?CU;Tu&=NFk-9DcKGigR33%69zg}&$L(j^`P5c-8RY9LoY5#M^geugN`xJ()GDVxX zBSq|0RG9WE(k3NLnA}C1?ddz+JiKUf4M66TlA$ez;6I+0db{2p#czAy%TID zt8)JVm<)(3rU@QElqn$}5LdYpiUDziJ)sN``;ZB>fDM2RfH(@CVAEIS{tYl0@Iyck zAdX%o;0XG@24$uSmd%%3a zHvx+Qw*i&`)&SN5z7E&`_!^+W-;Uq~_6>9T2>NFJ7MHKeeTnG-tC$|}1*Qjl9?({? zDi<5(f=-4uCmTFn)?1d-#8carRk@|WO9uQkpa<|tzBc2({| zrUP8SbbvTpp3nd|AJDdKRqkBCWWd>g9>AG=|EE>CGXRVKx+?cphCf@C>t*_16T}rF<=?sMSupqA?Q136Zn=f_5t^sWT&|Q>fG~*510X1 z3pf(60WclVcGl|LVSveiLjXO1=K|&f@;*y3;6T7Kz*N9mzyW{_fc*h&16Jpz044(_ zGdzBEF76*Bq)m;RFgXYNli7 z6JRo62S5*C3}7vw1F!+GJ)rIS)ww)B&`_}2@Y`lX|K~h*W=D1BWLx<+@(#l_SeM+2 z-=p}wfL{%MpW^oeem~-;;SXc026`H3Ysg1Ko*HKm7jT8^I=)cKb6j!CwXx)b@M;);KL=4tb9`aJ+^Ai znx4;xo+GQr8ClNhuE&~=WAX#ImwO5B<@P)?c#fDmxjBf zwo~UHlKI8r97HPUdO1jfX~Umxjo^>(V&?ho~F7(Y^9kGddKS@ z@~TR<uq1m7Iuw$l{7nIX{GZ5{^9K*M@XD;BIs*?sh$h`F9M~0Q;ri zFGH?SN8T^Q-NEtdULoenhOYbq`0`%ic-|?Tj5~!BaHlXDWp#w!DICxHg!pa};)C}I zH{t$*&6B)*$|CnW^|;d=1zX9AfRDl2!2QuV<(hUj#wb~cg9-y^Yh^u$`p6dV~u-Cbx7;#!E*zS@!2@LnF=~l zvg{7f!QHz(DvtMj(}0U}R=H`mnDMw1X7~s6YFdW6f4Jk>lkx*N-i5qLV;R!Z&J;M$ zi#3y~^9lGsKs!06(_i&ulfOTf+mVw$3iZsOESc|CH%cFVe#)E0hu_q1n;&mPKTtjm zUdDP?t!+MdhH}-?pO-p|44Xp0Zy(0r5Z_vtLcVeK>#GOgD<~%!K9q3hm^uV=!6sK$ z`f|oSia1PQ3_pD3{m>rp!ME0KJ5Yf$q5Qrz&n9L^<2ll^lRlUVk)CJzIR3iYdEkF9 z;lK*|-^1BA+KAdZmzIq)hV*wfqpue5pEpmQ(di6&i>1%JJmaok{DBIbC0q(zpFD@! z@?2efc2@Z*ihzhdg1z~Ld)-vWjFh9d+CkV<%~Qtp9PN&&@=TxtjiT$`kR~&-#lLF zH;ZReajp__lTf(|`K+Z63dFgfLyi6xsqJ<_o`dZY^qWb)WxV4a=yO=xDt`v|9}4Yr zAHW{KK3BM&^;P%VgZ4@GvnrHx3%*II%4+7p9La-aC|h!w@K;s?*}_~qgJtD8QkIkb zW*y4mtkv{C!S79|Ol=SGyN&VrUHEM^mB++0=q;8>mBq?8-Z4+|q#uaJJe<7CLHXuG z7kkk^SO$(A)W5XJXrA=tUdX-;dfRTZ?OX(2Fs%4X|7m9aev7@FZzf0|!|>xJZLux% z+8_&$eUir-{%ojMIJ?b_82g(ef_~NDyD5!!n-Tl849pt?^(F7kKAc2-haFgN_|@xH z*%9@<9rg8X6MnoBSWnd1kNU@ZhAodNbyv^_gAZ#*`e~{~TfrYwh6DF7*j89qHBo2e zP`+&LjDGmW6VIe)TX5Vq`_7@L7yLP8kgxsr(GOO9<+Y}^bxL1oXQOW6>?(#2EZFIl zoF=D0R$xDILQeknO;Ao5K3DRvwp7Z6;jh~y7vL4;f_yucZ0wNzYTN6gUm1N4V>;VC zF(-XgNShn?f<>FtpHyr8YNM&V^cxZ(%i9IzHRcymfBd)3FACS5l;5Sm{2~?UTg)$H zo&Qtwi%TtS@@r>sd@6#$#_Z1leZ*LweFZxw*JsP5-=vL5QwQ6#1M{e7@Z8G!3^r4H zoA-RIYr3Xig{;G{2N!y;=L5t)fVt85e5}t-{W`2FHaYTCufwWh8^oO~>)P&AtiyJ| zuy(TRu)$}vxehCFB%fof!=U31a*wq9w{m?{cJ5DFhn)vHZLPx|R{7Kp{>kgGrYFE3 zj$b;_fE=(X^{<#GWC2uSdhj3+G=B>3{t?_`AsqtcilQBaTzogPvL+@Sefh zSjTmi>$o(G>y4Pta!vF(#!{@&4IeJ_Wl@ju1ZPI8$7r#}n#j=wdEz~NH*igt20iPr z#lY`X=8A0eDbhmUN{Gf7l}cJR_^Oq0Tx*d&*ND{3!pBTzz<;{ev_7hU!Bv&_#Qer( zu5igU66>80IxX~Ao|w0ufF3jI(CS+0`uwe|yLp`98cnU0P_Kj5wNg*au^X|5QfsB@ zuq|-jwsAH4MR1)Y_LqZu5}doyPmS_%&h|I^o3%j(xgM&-{H?`WY5Z_wt+a)6(tywM zOq0*@Ov7h+D%Ll>wZo4rhK~+E{Fi&9f+jrOfM-*{_9JpL99)`XnIdnBS@O3BNyYmh+9^7v+2h zHc*1=lc0PX>l4fww?N0KvYOW?IVcgTY<6w87weI?l(nR^Jh_z8|5! z<;MCXq4JYgMSbayn&XGD4ukIJ`Yb*=G3@%}Y8&$4`UGtiSf5b7FwU6PCm}dopTwYE zxIbHMtWPi}=lW!s*+=g%_~60&cBosc>yrrV`%8UHz2L%`1}AvA1wJ*DoH86Gd6*2z z3C>eYa)G|o*4o4@8{6diWDR)5b$`hEq$qu>dE796vq!B@RC&vm2K&`AQ+c^Q`LK`Z zS94Yb=l%aLjPteFI92lYQ^xrs&}lKwpZI#^l#laCmUfyW+i8cc^t13q=9cS~-@(>t zUa#B>e6?O#i05$Y6+=FXFKBbU;>gE$m-1VFU(ADYxS$(dn7{aG(=Ce#**{7~Jm1GO zL>TLfY|h{CZ83-ZzL;7IWLx%mxF>^o5LKJYMCo(R0O zVofi`c@{BG6@EssFM;p*i1{e)i1&g`cleY=i{AMH>kU6}_e0-s9C1WPFZW}gWfOE! zNZ&P$Dax;^H_Y76|4*fBgkM$CS9bD^zqH6P^bF^C(N5?}>93aaen%VrYERg&D)g`y zcaAv+I3B;MfjXJ=(F9AKUXgWbc$oDG^+|f7^~r~A%SeOy59dB@`6BfJ7cyGSc5;Qx z$$xM7g;f4U!_}dmr4IL@4$8l13w)d}a|Q5)f6;}ecHI9^X#aM~{{2VT^UVGGA*50L zdkLOf?cbgY+wR}BHASx4mixo`C`U;DE=IXw6RgJ`7}qEs#QWL5Yi&Pk|Nh{?pRa!x zAAkSGUR?Ba)wj7{@-5a3eskZp{j|OfXUuXQA^JAyvu}T}{6EmI>GRl%Ni6_3NPle9^D(k##owL}HH2J=X%vfCl{Cj_fXUka@3*>4!j%Tm5epxOS*`mubhV?FE>ETau&R5pre-{ix|^l_pEZ4~se+lcaghkNqo@;zoLpHG$# zWe)ngmHvW1Lt56!%s-a-Unp}wl-Fh|b6b9u3j4V$c)pkZZRnRa7IrkuWe$7*n~EFz z*vcPmG~O#;v^iL3Bmln#a|28}zWx+tDUAyCSHry^<*zmY{%YrA-kZq6 zfp5L-#~SaS#u?{?%6CAE=h?jx?u=?i!v8O9oznlW7j`YhPv!r& z4)&}>*u!u}vsM4UJeRNt^>RylRtx{Xh~qo~{H|Ud!+rb&^1GV+e#64=b>MeafZyFJ zo$=&%x1ASCeq-O+;J4#A`zU#yj{N;GK_9zylJAu3a6F%myjFqdsgmdW@4>tS=cki! zZnq4w!E?fV=3FEPVFzF~?7h^5oQG5sA9rTV?=<{x{jmJnVHcf8$%Zrnx)wO=Z3& z`#Zmdx;M&Jk%_!6X)`aokyiuqsxQ#=b1eBNJ+@=1tXG)t6!Uu(w8!wru%{qgh-N4Vpv{zxzPQpD$oV{oY@YJ-|3jOdd`MP^aC|?^uhyInx zFWB{($g|hE&u8*?%=S@y(~;gh4i{JR&JDg3NgA-_G^8j$&G1)FI=IWm@_0cTc>3MI zH;=m>3%%Rgpcg}%y@g((h2B@is(!&U7ge|?M){$iRq~AWEJZyh{^R)ls;&;u6}D2= z*WefE?O{D3zp9>Qe&r*b3ul?LF+?(+eU0sq!}l|Kwdij{@ZRco&PATURv7r+9li_5 zJ8tZ+l+U_#S_Xc49quhr_Tp>L(7pX|j|jgy#DDyxA5pe79Ek4Sd z19!miEPV1{PNQTHWe)V=+I8-XZA;|cB;3h)55DP1e;H_V%;EEWcqR_VoU82G%J+~T z{id@BrIylE*dwhpB9u}b) z<>wulVbr@Q1HWmi>cV>~oF7mhvA<+vFM15l;^3S_fEPS7VWa~u%;|VXMy2IFN7qt! z2K=eb@j{<2o7ti3aE~Jm^TEv=8~+76H0i%9_XBw!=5>@koLw|I1^54OPm*;XvKYD# z=O@R2ZX@X8OmkdzPQ|Ef>6eT8o4mB@?;nmF`QgY9@(&OD7eT(D^HKf`v)t`A-nZ2A z)p+kQ;Z_h2_Ykb<^&s79Gu`7vviBA=d#Mwp%scoAbToB=Swd9kfRH-Zb}_ufP8K(4oWp4@Ee9`0!Py zA|K4-j+M`TTv+9KTff)VfD3Epb-6oAoXcANn@~IGc<@QtLE)dXH9KgDqqgnu*+uoN89kt< zZ?t0$_B-aZ-0!#wBUbMXrY2WI? z^0}KB&-IX+Q(4EKzan1DP5E6qHBaC?N77uZRqVysOPX6q6MjnQ51;wK?`zstyu+G1 z?G3v&X9MjL$a6IKwrJ## zc0ZmO&oSJXKVmMzdGRYKt94EkGXIg^mwMW$leps!{_S!UN9pvjh&hn)-Mxu;=3SS< z$eORSv)WZ;Z`X95Rhf+U+0WXsPFb3pm1WbjvA>V>CG?9*AD*OTPX?{^oa6MW?2Nng zZmfN^4!DOt(DB}PrlAU-HrRv$p1XFWw>u=c~Ug}D(O?zQ=sXW zt7p6)k7qSU4ksUdtn%TB4l5t2CnFyXj(~jJkGtJJmwdRCd|*CkmXDWY+nD8}V;l1E zi!k!RIpj}~kIUMSk8re4R6h1&t*7MUCCp1(laC$nD@r+~eEeQLLq4|SIjns27IyPT zL6hqz>Wc>SIr?=w1bDT^Gl)_rpx-oNEuVO)yP_F!<&g27knzSWuALnRYOpS0y}ZU+ zC%*DEl$p8=;S$<^Y7ys>I^h7;LbL(xLpizM!#-{FJM;_M7+6<7(sF%t2kVRPM+Nnu z_4y5>PF}f(z1I%3w2;0u7kfH%6@4qbR+!bOn^QjPEXW*6Lg#x^(RfUZsfN^ ziDT$S;GK;5P8WL*-u4vw(tyu-z|_XpZO zp>j0JOB;ksws$`C@d4VLQD5?sWl(jkp)N#y%Yjcm4l-n2`0w}^bbqVA&=+%6Gd{B;T*2Y^}-nd)VU$_S^9C{S50ClyBG`W5ddK#fi)J zE_+!_K)&OCM)}@|wWN^mJ|Xgbei-?FY-8*4{ZH6qTa)jPk&e1i$+zLd_9W%|UX=G_ z<@*k#rM{!Tt1-ur@2k=NhCYX^=So=!C*S=o^6h|6>z^v$m!h1fLVve!L%#bQhkSpD zvDGBsB@R#8sgmy!yA8CY{=N=tzMo5fH^JU-$hW6=h@!g@l<_ZmD?*9G^L#2Gy7D`8LEjyo2x z<6{2phChd=;rCUooz~#F2KHL6`OJ3*QU0$=yG}Tgg0-^vW^Y0z`~zX#-x7B(`Xkq6 zlR<0v(dNx>*y9gOfxoup2xnvM;J~`nhi5mQt@&v9(+gog;=LA6imuk3_c*ctVfn`C zz9f9}Ov9W@e(N-~owmF2&c!eB?ljkq{Px8W+$E{Nc&fG2dL(1~M?H$VV?4e-g5P@e zgU`1YjA!fG=8^?-zeg_ zUnppG(xX1st{|<8*J>LsUTee8j$Z_R?eL4luRVTI_&M;4#xDlHSo}KR*Ac%?_;ub; zZtF23uM_M$QcBe1blO^_xXbYJVnKkuc#I_6#5S!a6Y9f@-u!$5=I)hUOK!h4pnCfdTY_g=08 zh+h^LlIH-H3;6r6b~54{LgSMd4?2N(PnVGN-I-sa;1kP{g7s1(Xkq=pH3)dnMQ8mx z0*`!WJ=d$eJYDrDyr;d~z{R)JA`qsYL_g3I(H~mV;onOCMC?xv{)azhPpt=UzQ;Kx z>ec%0T6I14Le;q{;swv|o9wSxSD~+A-_BNfANViz8txlwl{X-q4%vF{>n!?=tQ>FG zwhTwuzh_EDqg_j9*|oB+x(|5uvTin8ygm`(1Hgao>j=ZX#`G?f$-k#x#z4qGHsq7* zQx|Mq>f5Qp&Xj1ZN!eG8vk0br^U(4Kzgx}qa{|hhhqX`*)=^_##J93>UTQwVxkh~w zjB)0T4m``GRX9-&V>~g@&IaC+t{T4^p4$h{Jm2#kO5@f1nVmSUu1o@!iFV;||pUN#o%;gB{kbOmh#)C05$)FW*k<^`;~qLB>x z#(4wiZ`%H+VeZqM)ed)6w1Wv>_0#=7e&oOzz&Q-Z7x&fk4Syq8XBYRu+EX*^#x~9bIA)z~i&@UQ znllO;M?DYv9eDR2XG2qwF15LNOAH{-$2+<_fbW-MFB;|b|G3scc|=|H!KkzOo3iA4 z@-HC79khg=fGy`yIJd+;QXH>SPBE6HZ9!f6&Sp!{AHZ{7n6_ZwVSAu2rirmj*lG+} zM4wi^8vJouk0hLdd>*{U`KgI68GajMSss3MokjfH;1%+j=#}9b@X95h8*s0&zLVC2 z?OY#gA4=$xVJ{%*8~E}$A7{YoI|}?72}>n(e7!c;(fs1v7|jto8U6(wI1{!bCe&wK zUI&?1ipWb-;aEvi!g4_7t?B}MhzQHNG{ywWRxY25;X5x6&#Z%6LZ^fdiNm_oMT@jH z@W_W};^STP-8eh?d(4eLK_BCs6#G7Vq&*>x%XmD4v_o5C!s6 z_mWNDW#oMPnZE7~oVVWBSKIJRU(bg7`q}_90quZUfDs#>?N>AU{(ipE<(L!sFVUJR zFbBarddql}gYyKb|B4L#hq*QNpSU~jSwUSD+qC$d3d}p0CJkvE!89Q{lWCyO^a{*@ zh)a8`!tDV4I)nNT`t=J*KN`5tW8R1NTcGzOZimXwz?}u$&cMYPSd^v1PL|_E%#HAV zONzw(BBFEU{lL8ixc3A1GvGdG>%4O*aWe((na9Arhq&hn-2TVFy_dKb3fytPCGTVz zii|RVcd85zVqNke@b3ffUK}LS3^)e;`$-?)i)I}!HPK&!bq|KZ;Y&b&udJh@{~+i; zXp36zyWHLMpsoG#2W^q~wZkuBxgTQ}+62Ft<%zb~<&gW$Sd&%LzbJKrKi7?WM~Mff zVBNN2id|ogALoaBZbIKM@HdFL%|gsKdPA=F!gfm;_Qzmu16%GGted#^=|h?=N1GpC zR+&@b!ks3LY4KgwuF1B=8~5IO;(6ErZSy+F-eP=1^symZkptO=PZoKD(G&X=v<2oBB{#2PY+ zwixbFmUYm%#?6B+yk&{+0+g?5@uJv@$RBB2jjvq1s6)v2cDr01x*ke?q51L7PT!t* zz~*`9?j$Ym6xbiyXADwjaz2uak5==}Lt617 z_li7wgr4~WY>zmL>c_g4W!3T%^e)h&g`lr!eS&i`m^*b<`o0}>yqV@&&?LT!*AUP0 zqO8l0U|g}TYleWS*7c0w5B7y|&ew_YYwB}ytqr<&fZMDc?|qhw@!y!h1=UFRvfgsIrVK-$N)L%ks^H;QF{H%AwltHyz>k z2jQc4y=1JFv2R{kpQY(jVB@Ld-gABro#86bQG1QGn2DO}q4J}AvQAt-GVgqpg?q=8 z(RoPkm9o1GGRF8@0nh5=-Y~9@w&AQk9zYvlCZHWK3ov5CfMobqPKIyg9PB6G9bGZ` zD)@dV%c;miKXR8vSBwBZ*nYl#mm2T#`gN!nf_JJ7RJ~jJ=Mm=u*R8Nsa2~#Cg1c$` zQhP;pmK!#vsLJy3?xrf(xYLM!^HlQxHIZa?j^I1j%J_R+#l zxQh>c`9OCqF6a7}x2C}^n}a*&PFoVrjyuw-(3fbJ5Q)Ovi1yDgu< zW_Shs_Q4jDb~|VeM?Y%Ba~|k2&GSgZ`3Rpk;+bd6?pUOy`e7sGyeuDc8wb8y<82SW z)BL7&Z9n~=mAI>b@A~C+HSCa^qiyb@9P~>E`ZU(dO_xDt)~)bVKxV4fFU_oA`<3B4 zHH*)}-aKf;US-&>ckw$hQ{abj>cjSmyOuaA@~?5E-m>Jr3vRhkJIXY-B>G0*GE_Ud z6K&#xy+C~3>O?jDGlf>IayRXl5w%))wN7#HoClFtTwy^s|{~}ET zFLi9&bVdt0UbIb}<``+FN7*19FL>ub8?ZggU@K^Bez9vker(fs!DI5Cc{x0J8Fg6u z8Ts1AHXR64PwG6*fqmd9*JHes@5S7k`8V1eBaF1z3&6UQ_Wxb9|JOx;rm3ECooDC~ zmM;2zOCA+L`uIq04(#zTLz=(X;Yk6#5~`bWh3PBCa-9h4>N2$@fatQdHn*4ve`=0YF5bsWwBK_`8NJ&DGFT6MWyyRH%I z=tjudXV{~FueGMnuut(B_9;Fa;2Ztf1nuapSR3_2+D44YUckZ_U-joW!^rer>=S_Z zx%<~gRMaD$dM+CF0UPRrbC$dD(-%fkj)V4VzNhVr@-iN2K3$6QpPS^0mEJGHi_9MSGVd&*E#9<)C&51u!r z?e;IGe3X6t(};*Pvwh(c*cZN!m##GQJ*srG1um zAVrV+YDXhrXN8{TSi!M~GLa0~OlqeMNyZ#18RxZsG|qbUt$Yu(egLj{+|PFU_|1no z?c%Z*=0W#)fPXpq3(ovjCxaf=Xpn!Ny^62=9(BSPo9;;n(!{qI9{dEqzx0?f>&=VU#Ybf%=9*^D}MI9Yq*&y>tP7LPr4D$J-HJ>Pq z8_*3N;3b2GInQ07fq8fOkATdJc0clm^grM`$sb$yU>*-4kIj}mz?0$0z=;NZ)(bi~ z*N^>xN()|@EbBh%KFG*y(4tJ2TJT!i4}BPT%}aaIw!SMNa%>a!p!dwj{aAl{>~BSA zTUOiQQwn@@boS+90vI?iXs_+A@8i7D3B6v>#n>N8EpKL%J z%D(4o)E)aon9pgIk7AxW2>m1;?|s+@W?tFo-z)H4B#gyPF8GO|9f3Z`z}(GvzcL5= zTQTs3l^wlfjiVy^3EGAHonYrU`cYjSbRNdWYNVO2ji$eG*t=k3XI*I5L;dtgsAp^Y zTr4Nr2>k0-S;{tYw3|~3nM_*HV{ZP1+QcTj=Q!9C^bVjt&Cpe!&8IQfK>9vXabl`oCa|SVZHx>E52|D=3Q6OLL zRTz5?mb~|Z9%VBRzk0M+A?nV4j57#ZE;sl9dvT&R@y9V)O=Ufa)3Mpp1Edvq5OKQ^$FPClQM`NG^e(@@c=rdqTMZs@JUbKlln&E|*JFIT3eS1?j`L#N ze`mRxabBJMrZ=8rSRV8p&XcHHMxZ^y>5v=nEvM#TLWjUOoxXRw&>^2gccM=jI%EL* z6#SN%`>mlXkggth)D@kWANp@8?EKUfV?lTCJJ1y)MVbCA=}}j3Uf4J?s1q`PYo@)E zxMykUO@M|@I4h_V-sL;gi}rm(CxEBqvtRQ0uiD`en2RPTeb5ij-=pl58OqL?kejI| zBR379a$_%?z5w>M;r5e|n-5V3$V4T0zlCj|+*`EswXzOu!@mMY>!%H$i?(ejV4L)+ zybbXf2di;L)R3ioq}zx2E9-wDrfBeYLw)XzG*8e-So2@g?rucFvLT^#_<7FMT z_tSdVQbj#_qbyknuK+$|aZht|L`5&a#qHf+dz{)t>V(g;qJ#PX&tstvJ~s40J3}AD z7T$V%`T%L!wr8PTvCY@EJ^=2q^g$%r74;k*c^vJUza;aWF&LA*Kjy#F@1C{28Zk$i zhQ9X+bOUS$x%-eGb$K&{gBKY=4*oE0vBf+=x&=%jL z9lpn!%#dBsI_WxEWVb!)_&-gXv2Lih4?6H(Q{4*M2^lSu zb$d+KP3gdVDJvy-|Ae92dRO*Ao%8TL>hXYLF7M0T3i?V%7M~^fv=nKSKCDN)yA$Od ze&~^|-k}XY|HtO;pW{7v*>nWwm>QugQ_&t#m`@i%j_FHeA=ZPGOYfIjh4%sYQpB1( z3hVJGeAg)ID($yX724g7Sdqq?sTFx2(e!AX1@Nv5#Z~2a9r^iSn@``~3_abglKE@c zOYerV7;_HlemUouKwjWEz>8j@UYFrL`{Rd5TMAn9kv0*2d+q?uI*#+(o44S*n|d9_ z{Y1nueZzT}f205BA}zyZ86teSC47k`JkAo%w1h8|Vbac$&nmBx7TjT$@VS=oKudT4 z!Xqs2`pK}$qc6f-mvCQH!(VXUQrHH029k3l*cLN*K8E+&(bsY}VJ?;rzb$NoZ!ou; z*A==9@4T>Glw+L2+-Da?5B=k34Br~n<+9<(3!Iw$WS4pFssFPt^Go6XaxrqE|+y63oBlu$YV93CH zwW@bdV@+DcI~e#zLvC+=>jkoAohy1fx11-IVq91AMC$bOVJG+EoJb?)S=iso$j7rd z!zk{r@O!qj5oANpY=V7d9^x?vDaiv*-s(5nIP(~5gAEdQAR5qCTzAg{@8KIcEdk#M ze&@&LEi7|vGVBkSryWAum17-W4%-IXnYM@C=o^2>xJDkiXorD)#Y`{B8S&mO_+BNQ z#4ag%9mX=+Zt)$R={0BIoCV%%$tik1WFaX|oAXw0ZQ{Go4>ri2F|X^5I$|F#A;!0- zs4LGGYG0ih>t2X6h!br?#W?uLcZS`>u%(ux9A4O#9Pak;d5-U0VD6RBE^+~%YjN(S z5VV%{&^BKW`#RR(MKS#oo)`n)JvE>=9rRtv@X=K}dFxtR?DPtxeHQkb4w$E}wM9*@ z!MxJpvFRO>wcTrxruN6?iQaMUqF9d2panjs`_Nx*jjrpJy}{9&e0Gf1CV0nbMU6NU zn1H+npq@V1%gRA_EqqyEZ?d|4iMz-@R4XdC(E)8w1hq4)EQ44k#A;e+T3~HOit_WVXKlZQj#1_P@ao(#;0l7)clV-$mU2?u|%f2fjwOA(e}n3t-l}2h;hSz7WZa*A6Nn&Ho&IHxyd!58eM*1f*aYq$(%)qyexEI3xRwve>;r2V#xhH&kVP^#DyB_2E z7%jrsYrPTqEyfwcb>P7hOT?Zd_4zLkH9yX{d5Bw&F?}BLp>5NOAG!xsli|P^AoqHW zy;f`9+~*COKlr+GZ!rH^$I4&gA8Q{d25lnFJhZ(JGy(ZdB=2GKo`Kh3+!+rrx3I0j^#uW4`F@tqjAc{~U`FB#tscg-V)zbnK^Lj>jnqBVRakeX&qu!ru5S}6q2G-4tq=XtSl_~K%C#-OaU{XxP8Fo_4Q4-T0#PeeGz1zWa;$hz{fcG~%*F*`t zCB(xVB>_0E1aJ~6pTe_K;uPUI5A%^M*d=k+xG4`j27gv!O+GviUuuu1fe*Xsj_&cnxci^1F5x}}B?xGBozgz#_(9zuvVD3I~n9ZioZ-3F@^#{E~#f#3bNCKV>dj1{ISYzUE6rMjCs#Sjkox0L^FV2S8@Lcpm^A`Gg;yusB zKd!Bt*H1I z5;!_((I!cJ?o0CBKhUNj_ow9j`B|yHJ#`o>xL1mGs!m(zmC#+(sr36ryX~Qf_LaVV z?$pTz(M6ND+cVrL5vdn*-U8Y<4~VhFT^$WwjCn{J_iJ1>`24`RXY|Dq?$zA$RP*DL zVc){~wE8m}?v-F(7KQmaeJ4!#EV_dCIf*OxWJ=;OXK};caPiXnFSz((u@7_2wK1ua zF^8XguGVyMZ{O&P&)1F~fQ&ojJFP{y|ULtjgOz&Czz zHagfJg6j(53ypM@?LT-XGO`kPgm@k}opNd~OVIC&;F-k)^e=HP5_4GS`ozj!pwBar z);*1Q>}g;wkhTeJ+l2A)nF38OZH`DK4W?uIok&X@Q9gX1&NSy&`%G#t{R@nhFQT9R z9gzJLzQ^^?&_}r!SpjHj*+(`8@}67|tgIb;x6ocj}WwDbu?!4~%;OcSh_ z@@V~?vgYna{OhLp-v;A%s`yG%d_^#RyNd7S3DWQB5%e2I>#wT#2TbXg1=DX*@wb}d z3-R4vl=%{jOV6qJK_>d=Nct%MdKKT#6rUW7e?rBNFvX__<5#HoKb!J@FIc|iDn8AW zJ~fzrsfz!-DgEzc`q~TiyHxxyO!3o#^yjJgn@#aI1?xXu#h+)&KO>lbfr>xN6yHA> zf1`?DXrf;f%zuK4zt0qZZ!mtmihtP@zagpXN7ELkz@L!e%U0O;IA7=5#*S|(aBu4Z*r^=YH(R_Yvcijf z-R$P(63jz%*kdakHO27v2-{09yhq<~l(jSV>AbLKkj6ZmEz+>JH4WoyqgG{%%{*to zd6EO;vI}Z;(7#U(@ZotcPRp$iS4w6Ie)@*B-RFkq<*q9}ROhK99h2 zUUTziYrPh?*EYIQEv}!x!H@H{B1PA9Ch!Nu`9P~NqHAS*q`L|0&Jx-SU{f^KT)uU7 z_!*0@($UMMt(Tsr^@ccyYIm}*1L<$N6nS?A&)$?Z7O^TM1l5)2=`#Q z@s6~Z-x&y#2I(rAJD_OE2Stat3&A_iwP6dKQ;#{e8Gp3}zZUrr*9+Sm(=zYZOz*1k zjPpc>{nAY5Dhr(#f%gJ_*7EI^cmZ3m>COxH7kL(x_p@mmKNQiGnO^DCfy$3*TzAi{JIx; zm4e6Urw6qLyZ#~4QilG3dzWtT1oKscmg4suOM3EbHfYSk&&;18D5SYve4xd?8jXBh zwf2k`L4OL;n0fC&zBkEte%T(^BaBU;7X07s67QT?;Y)~zO~l1 zJi5}4{R!H$qo*h1efAJ{QPMe%Ikl)y2Q7AIb}G)l!_Ml+#~sd&?xIwj>x}Ify}TUj zg(O?-0XO6(rXy^~p0oq&(Z_LL81t`~*tMS214|KhlxaHdLU(td&w63sWxZoq@BZBL zKRklr_6W0Xlm~{TJ~Hl-se0yz(Sz~mPyfUmwgz&A{b|ADGCTGCo?*}rloP9dwc!8* z<;6U{82qly#NLsXMqk3&pjQEUTz|a-`h>dySw<_(jc2u_XUHDrCLFh5@7Tz57Xzfc zv+p?3-th>t@8#LouCdb8@OQnWtMm=-Na0(q+E?}QYi|gVf0cjW+v#e|w537s&f(q< z_s2Xa!waZ`^ebW5B7Y72MOw-?h~hQ#|Db3pjP@|?VJX>_Hl|9-L=@`JKJ16R zb1vw!?`_V~GSU%e^v7p#t|LnHeeW|`^`pQcemTmGNyEyG_`QZ7y2n9VZG=v!l||?u zh(4Qsr^I)mZyGqo3dgS30Vf;zkS@W*&ImRu+cZgwg$$)IJ&YN(iVg>fx&2g8aY$|RO?y;NW zdZT~nj1LGDqGO4$5YUW{L@ru7&NXw_HII4@iq&{yJHcs%1$58p#Qf!~PsVEg5v z{oE*H9_D`z$d%@4uVw62)+w}|?T1~y5$8x;N7vR7KULBT;KR;l;3oqQwzvH_Yl5>?2EL2> zCOJl@+$5o{NALPwpx=>yY>UwTEBXcX_d&?r=0!NWfO>K6+W^}I_ha6|`%>tf2Jivr zh$?Bz|Fl5UKUu2bOeuXIB^bK14tVq0YhAF{G$$5&#fDs2`o1lo??t}#$fGap^5upP z1eGzuOmtpXte5$k1MF<Iy@NLKLbt+M%XQelKft+4J?c&0n_EytDz|CZ@q2z;ckPdGRk9Az$<(*o zjeAC_pR$dIuKVbm)mVQFlaOs(3w474E@3-`*AkV^I$*sPi^PwgbB&#>Mr!xVfe94xCigO&wUtW+HBEBA>$tR;I^DEKln;E^2EEW}pE1QhEz`rUI!(pjY>K}rnEoaee}gIh`e6Q7 ztN1CV`21k}Wh#D+DSmY@{vs7W(-ePOFn+X(Uu25EI~bp?;+L4>i-Ym!sQAZB@s9@M z`>Xhcrud>@d><7**Azd;h_B+Bznh5P6?bbOzG`}*Opo^OsN(N4#orr@k5uswnBtcO z=^uT<=u^AmW(MT1YWi)4{2BRwtK#RH;^ze8|Doddn&KOR@t>&pBc}MKVEo@y{Ew#i zqcR?L&-YaPUrq5J1k?Xf#sA3^|Hokb?^OKPrueUn_+6a;|5n9+Zi?R@Out3NXPWru z3G#P?ieG0+UlvUNw2FVk6t4&K|CNewZ=#R+B-ZFvm!SVVs^Tv(#peXu?;#Z*W1=4& z%>P~$-_;b~C7A!+D!!8`zGE=`?JE8;Q~aaB_}f(c<)-+{g7MQ-{3WLNoM8M-Dt@S` zenW!%y;{Y0HN|%c#$Tr5b4~GA1^IK4ivNu%|LS1=qgDJfrue6W@#!jljVXS0F#a4B zpJ>Q^`WuuQg(s}*aTr;xAX3=4R%6%}jCE`GnfHR^$5WUdHzzuU3PNgqD6Y21T6m@mu9eRJuLh`zjrE4%g;t&{_YUgdl{cy?B;slI`Y zbUy0Me8?NxO=-8G?>U|&-i3M74xB%&!yW{Dc;3qOMs%dVmmlvKuE%^%@S`X9@(q6A zqNrgTQS-WR>v^_QQBQp9Ov8RI@=cr5r|S+aZbVM0I~C_P$4A$sE_dAR#AvbyTSo`o6F-`?&yebYjxD-<{@v#ZD(}V+^*%C7W39a;3?@w%lfK1PC0|;vEb7l zb^RFiQRPzY^g;Z;mp`u@2Y)d4+7)-6NzOBZay}jPG~&NA#eW-&FF-u&PTTgBGGpFb zogJZ7V-KMO-r;a2N}O@X$G(TcTZB90>OJ3a&$!6?ZoQ_@w!BNm`DSN|yJ-*d;X1&` z!#%7;9xmYRz`3aXTGd>vTSZxFLh*uUQr@U=-LWLsIRNu_+_iOq7yK59tG8zOXN27q zI$L~8(gEFVKF`SYyz~WYoE?ppetHt&dk^Qd)8O;c@Nc2c06KrWHuo-R1HytYo&Jir z?uKr=5Yc&ZY3-Jxps#N7^rePu)-+pZ+0#Pe-UhZSe7qWAKr7I5QugY=w^vF}N!#`S>1i6d#9L z_}JIPN8ZaKAMZEwvA%6S(r2BSkFGnx$8-NZeEbXa18u(H|hifmXc1om$|PX2CC*#4Crb5&Ef0+ch*SUUw^A-0-k?9j$ov zBU<3GpQl!Y>QpE1VOrkRV;?ff^3I8~XCK4=jaeU;Volx6f>#QEOL5kB+iZHQ^&QUt z?y}Oum~XS<^|R?elw0z(+w@vXT6cj>|Js7bc6-H&NB_eXJbuSypY`27O)s~kt(gM7 zXTf7zzOYuv2HP@^Z5cPF1@D>1N(((FbS$ipAv`6YYpm~3mRGIs)@!=YLeCu$p`VLy z1(@3?8+RCC1L{iqZw=-qMz|=cYc}QXMt9TG7P{`G5&EzHHJ7s z)PHGBi*i0_#Vd%^@3+3oYOgP`yyLk#hplh0>B=*?Zs6Zx!FLvD`W(wU_fk!t z(c)dCev9>8L3@3Q_1$(&zsd408|T|X%EU0sgnbh?Xk2B%r+l1ck`Eu{qb8$;d=T#p zD_(tU3p~nnSBb~@lRu_$zNL$svMcSIZnm+oi(6qRV ztRMQdkn=j+RWj0+q_#*)-SN4^bE)zj9Ml5Oxlhy2wB*6L#)m3xip(Q!WQ(-SW4FRn zd6Ztz0*`$u){+PLyiKNMe?>iZX{Avu(h_g06;JCL7ViZsUP-sGcu%#!>k$@jjTLY9 z87=U9nVMcA@o*1S)T5*&uUL=!tn{vIDSxE*KcVyv!m{2XU(%Z!O7Ea{WlK3Fp4W=E zt5*wp?g+bXx5#NWe1?SREQYDG(AMsqo~8xQhRUY9pp!n&`Yy|+&$PZ<+DR{L@y@1C zwZ7YK(cRfGU*b^*81$SeE$~S1BP+eQv%=!N zXT|fK9Tsn=6)$g8SiD**URBF6o8@~Y6z`x`6JA$ru;RJHv|9o0C@MURVc^R_t(E!V zYJ~?KW#HAswWx=4yQcqA;<<)NywdQx=UywllJIhHmlf~Iq!#&-FLSJTz5!wJZn5GW zObd&5lNC>EIc6~530Ay=E$6w!%dz5Jd0yCj$5`?5Mu){qH{sRLW>MvAfmgFc(+5ht zx_S?-Jlxa-R`m=)KG zH}g2~8gN(WShQHqb|~j3w68#?MkL4SWtfkxTk5I!RV(Rfiz|oihG!sizY?}N^P2i- z1m^vS?}ojBm$63KgnNlN-?aGyPNLE9U0}n^APS);d?Gy-oRbKE&Vk84SV8& zV!4-UUVCCJtI}*X{ry8CKl0<#q*pgI4zO+b{9OBnFGfae_;O6U4P28lf1XKdM4iaT zFUO2Ud=~IBf$!PyY0~eWXFCjrjVTW0;XdfG=-m@X|Dq>GlYBZR-Gt1FpM&mwJ={(A zoCNJ-mG{0gvMPQKy1b|6ce%wEIaQ2o>aM)+6>)(YT6OyzEqa`T$BfOX#9Vu{M0qa zs}q&}QaY6~?4r)JQD=^!UtIXs6EZ=4N}DzHM*tr(r|>`SZm$TWk#eNcw8$sI7D)Fg z+CC&L)}!XJF(f~8x}=DT<4%`l+YNtkO`pm%ls}ZaB&42L3$>cB;7b7C%99rL6MQl7 zKTg57(7?;)Fg#(p(|@NqaGC?BIdGZ-r#Wz%1E)D~nggdfaGC?BIdGZ-r#Wz%1FdtQ zxqnPDW1IUQaSE6#!+T};a~U2g!+T^n7q@7b?k(KzBHSb4HVNNyiuWpAKN(i^)=4_O zBpsFCOA_x9373S>ecSl^#Vcoe7fQN`5^k1wf0ps8 zTx%@(u99?fWxDw?{vJzx&a;GTEaB&6c&_C8H8MQgg7>Mc=fg5TRW6?_uS>o^BFlZA z47+8yK9}$T3D1`B7c%|LGQ3AZMgOmsa{M66q2kxb^eX(=SAxF}OSn!#6@T5=BK~#x z{t_7;A;Uvu_Kwgp%GW0&6RHpjQ37$9^Mxic(af~q;qOn zng{P@Xqmtw#$}*6RlD8D0iHYLpKpxaXs42gLffxjw#Y!eop+vUxdb3{#;%9~`f-yf`~(!0TFje`R?5i_e>M zapC;z+ow#rt*~J3ta-D3F&|G;3n$H+TQDhq_Uv=!O`SgJnhE0yXH1(nsc`1}X>)Iz zHnlK+{&|(D#!kDVuwdG}L6;%@&_S0?n>R227NqjzUN&O*MOl+_ zr_Gp_KX2Nki>J+;HWw783Zl2ontJ<;X@hPVR4{wCrty9{?^d(U{QJ+B@6N)RbLUT* zf|3vNYTArxGjEv>c%3^uKi_ZV{gnKv&iolOW)TD+TyJ}^tW6K@A;W6>+_Fz}`sVWydi-%!L|hPZk7m#^JoJn@Z) zod8;M@h)Gx&4QJQ-c^YHH5IXQRY89C@`RQ&8+p&rX16H8&&Q9@{IkH_ncylpFyB;) ze^>skwZVVBzp(eqzMpw};f$%%=Av(-$B4iBz4yI%&c<6Wee#CCR8EWQTQW+%uMu!u zkIO{Asv0BonHT;6sNYseSTEs7OF9`8&LcH#+=9ym9j8a6_h$-NeuaQlfv~{4a;$iN zP{JM;iSQ~38zmft55%xMehJ@~&~>qRPhHQy8smR$T)KdPaO~L~qCbB0o5@dAoSkxC z+>jB+iZ2;2%C}0E+jXwYUxu~IMc6CDyJWbBgerckq|~UI^lGf{HPfwAifc5gs&SS;9*(b5(#%*A?nk3nTU7FcCNZmgb$7u z@O=rL68bL?@8dtM>YldpoXnC-n>zlX*WE8zb)5$~VKy`awPHScW}(qf#hic|V-V&G zvkbi!dKU)WfMJD za|Acu7l3QGVcsU@Sc9PZXW*Zv&6_{BaON$}`Lkv@XUv*;i)M^-bLZw4IcHA0)2T*F zO&dF7#>La-dkW?k-eHV@vZ0qsd{VzG7EtL&$MsS#ouGbv|87Ai`+o$iS}36R z1ff&nTjBdfg5HV3!KywdsApG6zFbsvN72f-rI}CEyVllxxpepgA8i?Q)n6XZdE>F) zteKGXUh_XY-%v8)wU4?yn4|T*;`jIc^}nq@s5Qw1Xc_3RK@;ZBotA&wyx>Gc7WhBk zAH@1XmDjw6VqyRD<>P!#a4+1f?#`(V5!a4-=jNrw*T31}#31|OSym!m=CpxdWZktFSCt;6T5nd(B;Z<}`u>WN5 z7IZWT7wi&Y-~S5e{F8t^-WJgRmVh-o1YA`o;MP9~I7&kIb`h?-UFy5Pi16{wpS*t- z_~q{j`2M>BUiprI2Nhj8k1YSIc<+~Cr6=q5i1&jfY?M&NUwMk?EU?g7^+EXZxL*_R zSG_7=o(!wZK>9^;d7(8wv0CH=tQ52-7Rq%vtr#<4 zJ%!CU%OCMBLIJDeXfyp{7=w2ucDQey7BinB4Fs^8E^^Gf*yg7QsS^3{t!&ZDN zz5o1p6gpmxn|1rlsm6+8P}Zy&GcdZqyk;8a|MTTF*+a6Y&6q7GyL+xaGPmT_4o<6y8vPU0b@Ak{|Cpu30l0^DZ68ihfu!L2L?g{E0?*Ku^DWMuC zXP+hB*Yp?Accy^lDFXJ8a6vy2_IDG|CBuWAB3$#-$?>bCvq;}4)1N56uInn&_mFUQ z7ZI+C6EN;1`L(r|NWVZqIj`8&Q@nRdSl?ZQ9TF}`6yf(JpA^695+q){fU{+NSDoOz z;{8D)y_#1zWY}?zc%OZebhUw@bO)!2uq#!-Rf_I0<}1Fl1^!`4uT+NBxIRj@hqAA= zHt#8Q2|7I_tdUUB@vWEhvSXCzSaiydlg_c~waY@sJ4BS&*<_G)b&R^pNAB+Pb)(s^I?pA(#i<&6<^4qqr>iG(f* z<0PyaE#kcr&b~l~&zI@X6YxqIR&bOIyCjUW;Jea8)2ncmq_;Ig#8-_HaFv8U39}_U zI8wxyN_eG&aT4|zA>y~n{M-_%{0rm|>XH-9RJ{5j`cs1sYGckXo z-7a(v_w(jA%95MbVlVAP=f5rIi>huSuOazYyUW%+H@Wi5$?0c3xNf>N{8Q`Odj6rj z%@}a&!K{@BZ+_{X|GT02!n@k&87Coeq3?Ys(*fP z%XNSBzN;1lr^?=(g`N6*$m~q44`>%(^?a8vrsq$ZSUTg;P5KQVdQNqI7h^5Ol^C|n zjlU^BzIn+GPvkYf+WPmu>>RuG`cs`>=>9~8HbQ3LmU^UWn$Rn|rb_)H<1e!8Z|6>% zfBW2-m(N$_6X9%Q8~M^%w-^zC;sub#5wZ@Ggs)yQvw5$=yu9HVeL!-*WZyRQD6c*B3{ z?=r;Q0{S;fyqjcPma#^iVeCRt!%fo`;D3R~nkYP`Q#B<_MGQ}~sP`g-uUg0qNlWa> z1ovhbl{gfw%p!YQ{%nuw7=p1*o-3ucNEwl zI}0iG$7!#eonJ8BI2zJ&*COY(*)xpYCu2=_Y2lQ)`E!c~4H-0e(9q$7hYTG$Xb4WB z6wJ7N>aVdOslWGebA6}?NanAao%W>HUUhZ+tpu;qcW)R zJdt`<(1wS@FW9wJVa^j-&mVn(b4U*0&j!A~6@2VXX$jAZb4vFBVvkCz0`#_m-;VLG zh;u}EG|nUKLRjImeCkh?XOan@>1QMClk~0l3?F&B5~UJXsCG zN*=<+1XU?R6#aTayRMf8K9`?aTB&g#E4b7h*b0_)PCS2ELL{f3=X$ zD!}8FH#FX*Noz5J z6D9sr4Z>z1Fby((hLugQz`QLR%Hn~4Tlbr`b^G|YUp9W<^X|R!)zN*DoW^O&eA}0= z?s?~)d+xdCp8MxL$;6+UBY%93{2}nW`5V>01ow5KPd?bdg+HDfe|8T1)cz#+3oiOl{kpx&z(@SyI{8nYlKj)a2^aac_NKr;7yCr# z$RC^|zo^1*+UN0a%J$}f_1JTb;*SE|>|@IB`-YUC24-CBY4QgYe;8Pg{E0u3@{7QF z_!EkM09cPcKE>ZyMLzk%6FI5J355kHZM@I6L|ANrltEeiwez zomq_ZaUHWgz|oapV|{ZUdMmVPx9kmEtj80KI$T$_{WX; zl=gH*Ig9`7miVf%V9r_*3c6MPNPlkAsiKZwgqCJ(nu}#ya`a-<9$wfc404Qv3;EJ^eNHw3P1y ze}5hJ+^_gEz^gzqnkfBflBiLVwv)l~eeMIu+HeB#f6-{&Hq>NFGaC&BL) ze@H)5f8vjT-_1Ww+4Pyp7yi=zeND2DjelZ}{MkA356pqzX)pNQ+RN=j`I*VNjh9LA zyV>7npZ+=UJL`Gy5B!((H*-A`B4y_z`Q-Otx#)yY@BJv`_sa%D#Z7mDZ&CRnb#*ZM@f0%N!_wbz+aSg8cQN)Rll;6YmSVR*# zX+Q4mr+WpD@Zr)JP$NEmWV%R+|L`IsSL@`3E|F(k0B69 zu9+HMvDmRU(M-NjsGM&G<&vN!*Ok*vS@fA|4H#w3c2Qj<7vCx7#Y8jiXe(<{i%juq+YdH&>Ta_9ES}kXQsS=v2(u1`I;GD0DO96oAN@8 zFZdd}yne=)#8X6@yaeOR1{TwAOgPD`H~b6b?I@sL{ceTHmuB*U*Xml!?b3``V5R`e z>w6TB!p1!*ey2F7@UOSyaaW%M*fnPxlAs zon)P?eQlfE? zw$N#>l(5i=f5t*5{s~5>dYxw&>&xpUy7Mf7(Lr`}O*NJC6P+l1F7&j8PIZhkI?+ha zu!T-@NWh{Gjm`BIH*cqBHL z^EP5#S8Xju++Jht*9f^<2h+a-1`p|w0H01K-vHx_vb-)sb@Utev^*XkxV!>vq1#kz z%}RBUKTaC;=(ag}P#a(`{C10zHUG)F*f)A_Iqv|<*0OKhkU#BW-=x7qdiZa!+joZX z_=S4Tln(W8`|s|ifF2oH$!Eye{|b_N-nkkH_DoNP+cUq*|@LE#UH@F zVGHizYS@Ola7}K-J`-0zt|+cXT(tkpgQwP5)^go2h5E*E#UHG1pI9$%0W!VNuipJ< zy}XywHe|E;?uYs6<23xnk3J3I>ci&<`BIfMf%`=Z52tCFTolz~rds|Kc%yxPnPPI1 zZ?f+PbBr$sc{<{l@hijliVb#oMaCBdpH1E*<4fLb-(O~%%k7bVvweT*WqgSnb*<&= z)NvY1MoO~0zD02+W8Bm7`25A?%_XK#9nN~ys3(bduQfOAA3&@!Q|c{}i|^kWnH@qa z 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 HQ|bQ$a^?;} diff --git a/build/staging/app-sdk/Arm64EC/Microsoft.Windows.Devices.Midi2.Messages.winmd b/build/staging/app-sdk/Arm64EC/Microsoft.Windows.Devices.Midi2.Messages.winmd index 382966a53d4e8bd490f38941cb4aa41249efdfe0..ac8c563bcd064de97c528e88d1a03e7a0519e5c0 100644 GIT binary patch delta 3685 zcmeH~eQ;FO6~NEE@4okTAG@2)ZkEp|TQ<@dK%o#Nk}gV?k4S1PfzZ()iAjWLzJv_m zOmG*IK^T}$$kGy0sIj4)fI?}PX)VQ%Nkkc8Muw4$4osjHIuxiyno`FP^t`jnG0NzF zPX95P{NDYYbMCqK&HLC*tX0HfqHUgbwBv;>^Z#p2%m)B3{)OZBi(YwpM%*Lo!)2KO zp{D_kDu4rzp+zMy4afH6(A-6Z5j;lFI~?(Y@<-`ys7*3e zisMP~&*UdnYu%5yEqK;FAbhZc#<%zegax_83ZxHq2G#|9Z~$pQZ(sm?@Fqo0Q{)4R zd`1!XaJw>-IGs2b881_jXg-Mh04{_OmR}))_?Z{|ptczqnaT!jq7f4{Er!xM8e45x!>>(Z^o&j&mwu-l&(`eAlR0dbzgXt7<@!g-JTeV_2`(A!lQUR}Xxrc2~U!m=1yT@qO4zMjV)@v`Z?J(N3Lu_Y_PVF_eapo>9`a0`kbDwsE zt=)V{JI405*{dCAQ;uWWJ8btj`n7l29(SD8PP1)uT++_6^*OF-=hy}vLS2ZmPIS7| zWw!aw5$XzCJ=#^aO=yE`J!se1`kk5TBQ}Q>QXjMBSUKubwqk3Fx-O#jeQDnctF7ru z;JYwsTdlCt*!EimN@wf03YE#G4+|?N+ns2`*cPF=*;b*Yv2~)QOR(3smp_c^=j27S z0NZd^jvB!>#Z|0Eu`O|xs!XJM;#&T>lBRGO^UNPLJwt`zi;ezz?0T zjs-}_8It`W)=20b5*a#9X2B!y6ud|ULC=?+Z_fS%YjmiN;=zDsqzQ4P1NI=DaPp?f zx24&wBS;06NFAO*8qkh3;WtPJyo_|hyGRTEgB%7PuK*X^Zhz#bPBOWb$5Rn};shi^ zokNOFe8V_dIVs)V%3VkW3(~*dI+^XD?4g^opVC~fFEwi^FaJCI9MHf{E7*%;9S$H3 z_$$(c!$=1lM>^pQ63_2O3+|9?edEmR6FcEelzU>|U*!MuMaJ(|seA0ZxyUtQUtqNU zBr;oHhb+=JA}{M(kdw{rBDyay&D@Q$(fkW?yXnAtsY*KV$*4hkp&pq5E0H5%4Kfqf zB7^V@G8;A_Cqf%?GW-HL4LXt2;W=bJ>_XlPyO9yO`Wg?8#$pF4kBBrW&_o1rscQNhB|0NJ1EkH8!EtueXL#p zez+Ss21@iwid14Gx)o&%?ABXQ!bS@vTI?dD8~IP9AKpRQE&7OmCu+iuXkr2`7D|zp zp?HCq0c~c1D1a{HRLD2WMF>9BD=A({HI*3O9W^VdD28dvXu;4&W(yUyP*DqIyD*z& zbW@}oYa)(rs_CX|AH~58LEH!;6GpjZFBU^uMi(;6054^c2}8vIK2QC|kB?m_r@Is5 zgO^+j=2ka7(9l#Jsae@rTk+Hb6?N5fRy5Svp~CvA>NQZ$qf}*aWmCnfuNBqRR8`eh z7bH{hin}u6S(COUj@@xZin_#sDI4{Xpatz$9E|?QlF;m(;i5lm`QNgu>%~A~;oWU9yX~`@9`f=x5 iJ>%=*B0MWRR>0_Q*(U@AjQQq#B4g%d8NYJx@4o<|Pgqg_ delta 4148 zcmeH~jZ;+D6~NEE@4nslmfeNjg#|y*h1HQnP!S}_>JShDilx=!ify$)fe3`~t)_|g zEd!=TsbZG#BV#*cXi`m^sVTK>s-uofzNTr@(3zM{t)aEm7GuzfiDQgo&%3)ERx{=w zXqn;n?(dv)&w2aa;|&`Mu~0YbU7{3F`4;v6=}b(~{vSSr`U?sLorqmo{a8ULm?&+CSIqy;v6&w(4Z$jBZU8IX}* z%E)QS_arY%et`_H5yeIUutI=Qut5?qD3_+=pd`?vmLY9Y)JmlJ&^mEn3)+1!BWhhy ztCYF@QEQO)a@2a{gdwyf+;_kLW=Tri$ybF^6L%qJN@hwvBv~pMl&nRL*Ec5~#rmC+ zKb1T#`JUv*l5t69O{!eal+2WTNU{`ZtO^CC)Jjgp4d#HqZ;HelJQ=1Jrjxd7=PYS?c4@zFx4`~jiBQdHX4azVx!|E zyG*v*@h3J$_O@e$U5&9z>=QE8`5F5x#yG!0R_5HsZjl+z@3Pxu{f5)Y8H@NE>ILT{ zZXr7!pTQHzxGTU@$+FOVWDTxT?kDR-n@M)eRl#SGrMWA3CfP2xv6g3(W_vd91!N~Z zTX_N5sHc<{OH*Jk*!fjnLbih6;ALbzTqw)Q-r;Vgk}O9_SJsm~uFNx(deX&Wsj`La zL-8%;2V{1&ML9rLsdg$qA=|3{Q2BX`?NyG%*bRP^?3&uI93u-@URI2gq#G>1QijM5 zT23f$l8sp2QhraCZXH(MC9AZaRsKx&ob`fohU{JI73HsFLi=3#kSw4Hao!+p(468T z**~N{kGM@O7;!gqe3U!Yn%qQFJ_>IUVd)x7*$cwRI@gSM%{F_*4njy!l&i{yf zN|rer#bPqU`G_bc>vw)CO2{raL0v|6JU(6xl5tm>x}Gcxt(L68HAk(Jw$}Xgy{HY8 zJmw0hjbv%=fZ9s7%U!H)BFpxCU44q|q^CyRMmFl1qdq%0=IB)GW^o1_njPlD<-;|* zV|^+nem!Pgr<=QO$3(6>%t)SdqR)5@!>gF*4EMX!jmWSQPBZjJq=0iV8@`;4i)WyM zA8COA(h4h(8q^_m2**zhi|jp*aRtoxvVb(C3I#|DEJs?Q%D{sLPa}2Mi?qS3$T)Zh zX@`sEKO)g<5NVg;x;wHuCK7vXV%L$q|8SY7atSHG>W=im_X&g8bh+D1w?@+w*;g^H z!0TU%f5&6S&8&d+xK^PaX@M4`6`n$Bunnn0AJPVgJa>G6WV}O>*0G=LlwNYX^{i?J)95?KR|fO~VK7Ij-Sf&pu=V z97HC<3&<3B2{{#hhV;P^WCpy3%!Ct2V;&6QAs604J_vt6E`niX0h~b=%ce_Y)33>< z%VpD*vgvBsbd79U1!uVqb=X>mMr^G^3wG9_1AFT5B=*r^3;Y||Eo-*RnjS-r?~`Y= zU!KuH8R^FpD#ACy(`pfTAdH*>zfh}Xq#7eva6JW7OBb%6N1BygW{qV4`GIu+<3mU@ zJ|uZwQekF9VY6|TA8D8eIfg9+Ln~rMup1eP=ClqYs(uBDKKkhcQbPGTj2%~s+3vL8ra<2R+9~d zEiJW8HFxx!sLiMupS7|%Qn<1?wsleS#-%F90u R@)%@)RY~$-?V^wPe*wIX&kO(n diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi index e2ab1d9ca..22129c34e 100644 --- a/build/staging/version/BundleInfo.wxi +++ b/build/staging/version/BundleInfo.wxi @@ -1,4 +1,4 @@ - + diff --git a/src/app-sdk/MyMidiApp.exe.manifest b/src/app-sdk/MyMidiApp.exe.manifest index fad0c63bd..131539b9f 100644 --- a/src/app-sdk/MyMidiApp.exe.manifest +++ b/src/app-sdk/MyMidiApp.exe.manifest @@ -158,6 +158,10 @@ name="Microsoft.Windows.Devices.Midi2.Utilities.SysEx.MidiSystemExclusiveSender" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" /> + diff --git a/src/app-sdk/midiusbinfo/main.cpp b/src/app-sdk/midiusbinfo/main.cpp index 448a2ae43..e1d36389f 100644 --- a/src/app-sdk/midiusbinfo/main.cpp +++ b/src/app-sdk/midiusbinfo/main.cpp @@ -30,10 +30,12 @@ int __cdecl main() winrt::init_apartment(); std::cout << dye::grey("===================================================================") << std::endl; - std::cout << "Enumerating kernel streaming devices to discover MIDI pins" << std::endl; - std::cout << "-------------------------------------------------------------------" << std::endl; - std::cout << dye::aqua("If the MIDI service is running when you run this utility, some") << std::endl; - std::cout << dye::aqua("devices may not report all pin properties.") << std::endl; + std::cout << dye::aqua(" Enumerating kernel streaming devices to discover MIDI pins") << std::endl; + std::cout << dye::aqua(" Typically, these are USB, but other KS drivers will be included") << std::endl; + std::cout << dye::grey("-------------------------------------------------------------------") << std::endl; + std::cout << dye::aqua(" If the MIDI service is running when you run this utility, some") << std::endl; + std::cout << dye::aqua(" devices may not report all pin properties. It is recommended") << std::endl; + std::cout << dye::aqua(" that you stop the midisrv service before running this tool.") << std::endl; std::cout << dye::grey("===================================================================") << std::endl; // enumerate all in-scope devices diff --git a/src/app-sdk/winrt-messages/MidiMessageHelper.cpp b/src/app-sdk/winrt-messages/MidiMessageHelper.cpp index 8b96c75b5..a137c0c6d 100644 --- a/src/app-sdk/winrt-messages/MidiMessageHelper.cpp +++ b/src/app-sdk/winrt-messages/MidiMessageHelper.cpp @@ -114,100 +114,6 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::implementation - - _Use_decl_annotations_ - uint8_t MidiMessageHelper::GetDataByteCountFromSystemExclusive7MessageFirstWord(uint32_t word0) noexcept - { - return MIDIWORDNIBBLE4(word0); - } - - _Use_decl_annotations_ - uint8_t MidiMessageHelper::AppendDataBytesFromSingleSystemExclusive7Message( - uint32_t const word0, - uint32_t const word1, - collections::IVector dataBytesToAppendTo) noexcept - { - uint8_t messageByteCount = GetDataByteCountFromSystemExclusive7MessageFirstWord(word0); - uint32_t currentWord = word0; - uint8_t shift = 8; - - for (uint8_t i = 0; i < messageByteCount; i++) - { - dataBytesToAppendTo.Append((uint8_t)(currentWord >> shift & 0xFF)); // we don't & 0x7F in case the data is actually bad - - if (shift == 0) - { - currentWord = word1; - shift = 24; - } - else - { - shift -= 8; - } - } - - return messageByteCount; - } - - _Use_decl_annotations_ - uint8_t MidiMessageHelper::AppendDataBytesFromSingleSystemExclusive7Message( - midi2::MidiMessage64 const& message, - collections::IVector dataBytesToAppendTo) noexcept - { - return AppendDataBytesFromSingleSystemExclusive7Message(message.Word0(), message.Word1(), dataBytesToAppendTo); - } - - - _Use_decl_annotations_ - collections::IVector MidiMessageHelper::GetDataBytesFromMultipleSystemExclusive7Messages( - collections::IIterable const& messages) noexcept - { - auto result = winrt::single_threaded_vector(); - - for (auto const& message : messages) - { - AppendDataBytesFromSingleSystemExclusive7Message(message, result); - } - - return result; - } - - _Use_decl_annotations_ - collections::IVector MidiMessageHelper::GetDataBytesFromSingleSystemExclusive7Message( - uint32_t const word0, - uint32_t const word1 - ) noexcept - { - auto result = winrt::single_threaded_vector(); - - AppendDataBytesFromSingleSystemExclusive7Message(word0, word1, result); - - return result; - } - - _Use_decl_annotations_ - collections::IVector MidiMessageHelper::GetDataBytesFromSingleSystemExclusive7Message( - midi2::MidiMessage64 const& message) noexcept - { - auto result = winrt::single_threaded_vector(); - - AppendDataBytesFromSingleSystemExclusive7Message(message.Word0(), message.Word1(), result); - - return result; - } - - - - - - _Use_decl_annotations_ - bool MidiMessageHelper::MessageIsSystemExclusive7Message(uint32_t word0) noexcept - { - return internal::GetUmpMessageTypeFromFirstWord(word0) == MIDI_UMP_MESSAGE_TYPE_DATA_MESSAGE_64 && - internal::GetStatusFromDataMessage64FirstWord(word0) <= 0x03; // 0x0, 0x1, 0x2, 0x3 are SysEx7 - } - - _Use_decl_annotations_ bool MidiMessageHelper::ValidateMessage32MessageType(uint32_t const word0) noexcept { @@ -363,6 +269,35 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::implementation } + // this works for classic note indexes 0-127 + _Use_decl_annotations_ + winrt::hstring MidiMessageHelper::GetNoteDisplayNameFromNoteIndex(uint8_t const noteIndex) noexcept + { + static const winrt::hstring noteNames[]{ L"C", L"C#/Db", L"D", L"D#/Eb", L"E", L"F", L"F#/Gb", L"G", L"G#/Ab", L"A", L"A#/Bb", L"B" }; + + if (noteIndex > 0x7F) return internal::ResourceGetHString(IDS_NOTE_INVALID); + + return noteNames[noteIndex % _countof(noteNames)]; + } + + // this works for classic note indexes 0-127 + _Use_decl_annotations_ + int16_t MidiMessageHelper::GetNoteOctaveFromNoteIndex(uint8_t const noteIndex) noexcept + { + // default octave range is -2 to 8 with Middle C as C3. Note 0 is C -2, C0 is index 24 + + return GetNoteOctaveFromNoteIndex(noteIndex, 3); + } + + // this works for classic note indexes 0-127 + _Use_decl_annotations_ + int16_t MidiMessageHelper::GetNoteOctaveFromNoteIndex(uint8_t const noteIndex, uint8_t middleCOctave) noexcept + { + if (noteIndex > 0x7F) return 0; + if ((middleCOctave < 1) || (middleCOctave > 7)) return 0; // Middle C is typically 3, 4, or even 5. We allow a bit more. + + return static_cast((noteIndex / 12) - (middleCOctave - 1)); + } // Names used in this function are those used in the MIDI 2.0 Specification diff --git a/src/app-sdk/winrt-messages/MidiMessageHelper.h b/src/app-sdk/winrt-messages/MidiMessageHelper.h index 4ac696763..efeecfee6 100644 --- a/src/app-sdk/winrt-messages/MidiMessageHelper.h +++ b/src/app-sdk/winrt-messages/MidiMessageHelper.h @@ -48,7 +48,11 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::implementation static winrt::hstring GetMessageDisplayNameFromFirstWord(_In_ uint32_t const word0) noexcept; - + static winrt::hstring GetNoteDisplayNameFromNoteIndex(_In_ uint8_t const noteIndex) noexcept; + + // these are int16_t becuase IDL doesn't support int8_t + static int16_t GetNoteOctaveFromNoteIndex(_In_ uint8_t const noteIndex) noexcept; + static int16_t GetNoteOctaveFromNoteIndex(_In_ uint8_t const noteIndex, _In_ uint8_t middleCOctave) noexcept; static uint8_t GetStatusFromUtilityMessage(_In_ uint32_t const word0) noexcept; @@ -68,29 +72,6 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::implementation - static collections::IVector GetDataBytesFromMultipleSystemExclusive7Messages( - _In_ collections::IIterable const& messages) noexcept; - - static collections::IVector GetDataBytesFromSingleSystemExclusive7Message( - _In_ midi2::MidiMessage64 const& message) noexcept; - - static collections::IVector GetDataBytesFromSingleSystemExclusive7Message( - _In_ uint32_t const word0, - _In_ uint32_t const word1 - ) noexcept; - - static uint8_t AppendDataBytesFromSingleSystemExclusive7Message( - _In_ midi2::MidiMessage64 const& message, - _In_ collections::IVector dataBytesToAppendTo) noexcept; - - static uint8_t AppendDataBytesFromSingleSystemExclusive7Message( - _In_ uint32_t const word0, - _In_ uint32_t const word1, - _In_ collections::IVector dataBytesToAppendTo) noexcept; - - static uint8_t GetDataByteCountFromSystemExclusive7MessageFirstWord(_In_ uint32_t word0) noexcept; - static bool MessageIsSystemExclusive7Message(_In_ uint32_t word0) noexcept; - }; } namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::factory_implementation diff --git a/src/app-sdk/winrt-messages/MidiMessageHelper.idl b/src/app-sdk/winrt-messages/MidiMessageHelper.idl index 5a836fa41..8bbf64b94 100644 --- a/src/app-sdk/winrt-messages/MidiMessageHelper.idl +++ b/src/app-sdk/winrt-messages/MidiMessageHelper.idl @@ -53,24 +53,13 @@ namespace Microsoft.Windows.Devices.Midi2.Messages static String GetMessageDisplayNameFromFirstWord(UInt32 word0); + static String GetNoteDisplayNameFromNoteIndex(UInt8 noteIndex); + + static Int16 GetNoteOctaveFromNoteIndex(UInt8 noteIndex); + static Int16 GetNoteOctaveFromNoteIndex(UInt8 noteIndex, UInt8 middleCOctave); static IVector GetPacketListFromWordList(UInt64 timestamp, IIterable words); static IVector GetWordListFromPacketList(IIterable words); - - - // System Exclusive 7 handling - static IVector GetDataBytesFromMultipleSystemExclusive7Messages(IIterable messages); - - static IVector GetDataBytesFromSingleSystemExclusive7Message(Microsoft.Windows.Devices.Midi2.MidiMessage64 message); - static IVector GetDataBytesFromSingleSystemExclusive7Message(UInt32 word0, UInt32 word1); - - static UInt8 AppendDataBytesFromSingleSystemExclusive7Message(Microsoft.Windows.Devices.Midi2.MidiMessage64 message, IVector dataBytesToAppendTo); - static UInt8 AppendDataBytesFromSingleSystemExclusive7Message(UInt32 word0, UInt32 word1, IVector dataBytesToAppendTo); - - static UInt8 GetDataByteCountFromSystemExclusive7MessageFirstWord(UInt32 word0); - static Boolean MessageIsSystemExclusive7Message(UInt32 word0); - - }; } diff --git a/src/app-sdk/winrt-messages/Resources.rc b/src/app-sdk/winrt-messages/Resources.rc index 94bb1253018d48e7aedd18c8971416c1764fb2e0..24f02d7d18d91d3681e0b2c89593467ccf468e6c 100644 GIT binary patch delta 189 zcmcaMhjH3G#tm#-$_fk+sL!AeWaTmBGn6o-0$G_rb{de!%fL0+&{4GBkHMcIgu#^| yp23sBk0Fe~k--PZa)IiGnL<6CLnaeL%H%>><;_Z5CN2Q_rWmRK delta 14 WcmbO>kMY_Z#tm#-n~!k?xBvhxCIx^1 diff --git a/src/app-sdk/winrt-messages/resource.h b/src/app-sdk/winrt-messages/resource.h index 2b23725d1..eea6cab5f 100644 --- a/src/app-sdk/winrt-messages/resource.h +++ b/src/app-sdk/winrt-messages/resource.h @@ -40,6 +40,12 @@ #define IDS_MIDI_COMMON_LABEL_MUID_SHORT 50109 +// Note index info + +#define IDS_NOTE_INVALID 60000 + + + // Message type descriptions. These are optionally displayed by apps using the API diff --git a/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj b/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj index d185b287d..e5340dd2d 100644 --- a/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj +++ b/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj @@ -273,7 +273,12 @@ - + + MidiSystemExclusiveMessageHelper.idl + + + MidiSystemExclusiveSender.idl + @@ -351,7 +356,12 @@ NotUsing NotUsing - + + MidiSystemExclusiveMessageHelper.idl + + + MidiSystemExclusiveSender.idl + Create @@ -359,6 +369,7 @@ + diff --git a/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj.filters b/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj.filters index 1c3dabcfa..7a8e2da08 100644 --- a/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj.filters +++ b/src/app-sdk/winrt-utilities-sysex/Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj.filters @@ -36,6 +36,9 @@ libmidi2\src + + SDK\Messages + @@ -72,6 +75,9 @@ libmidi2\include + + SDK\Messages + @@ -86,6 +92,9 @@ SDK\SysEx Sending + + SDK\Messages + @@ -111,6 +120,9 @@ {bbdd01b4-c1f5-4b22-9f6e-060d872329f5} + + {2268b5d2-008c-4671-85d2-496e318b0c03} + diff --git a/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.cpp b/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.cpp new file mode 100644 index 000000000..245133fa7 --- /dev/null +++ b/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.cpp @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#include "pch.h" +#include "MidiSystemExclusiveMessageHelper.h" +#include "MidiSystemExclusiveMessageHelper.g.cpp" + + +namespace winrt::Microsoft::Windows::Devices::Midi2::Utilities::SysEx::implementation +{ + + + + _Use_decl_annotations_ + uint8_t MidiSystemExclusiveMessageHelper::GetDataByteCountFromSystemExclusive7MessageFirstWord(uint32_t word0) noexcept + { + return MIDIWORDNIBBLE4(word0); + } + + _Use_decl_annotations_ + uint8_t MidiSystemExclusiveMessageHelper::AppendDataBytesFromSingleSystemExclusive7Message( + uint32_t const word0, + uint32_t const word1, + collections::IVector dataBytesToAppendTo) noexcept + { + uint8_t messageByteCount = GetDataByteCountFromSystemExclusive7MessageFirstWord(word0); + uint32_t currentWord = word0; + uint8_t shift = 8; + + for (uint8_t i = 0; i < messageByteCount; i++) + { + dataBytesToAppendTo.Append((uint8_t)(currentWord >> shift & 0xFF)); // we don't & 0x7F in case the data is actually bad + + if (shift == 0) + { + currentWord = word1; + shift = 24; + } + else + { + shift -= 8; + } + } + + return messageByteCount; + } + + _Use_decl_annotations_ + uint8_t MidiSystemExclusiveMessageHelper::AppendDataBytesFromSingleSystemExclusive7Message( + midi2::MidiMessage64 const& message, + collections::IVector dataBytesToAppendTo) noexcept + { + return AppendDataBytesFromSingleSystemExclusive7Message(message.Word0(), message.Word1(), dataBytesToAppendTo); + } + + + _Use_decl_annotations_ + collections::IVector MidiSystemExclusiveMessageHelper::GetDataBytesFromMultipleSystemExclusive7Messages( + collections::IIterable const& messages) noexcept + { + auto result = winrt::single_threaded_vector(); + + for (auto const& message : messages) + { + AppendDataBytesFromSingleSystemExclusive7Message(message, result); + } + + return result; + } + + _Use_decl_annotations_ + collections::IVector MidiSystemExclusiveMessageHelper::GetDataBytesFromSingleSystemExclusive7Message( + uint32_t const word0, + uint32_t const word1 + ) noexcept + { + auto result = winrt::single_threaded_vector(); + + AppendDataBytesFromSingleSystemExclusive7Message(word0, word1, result); + + return result; + } + + _Use_decl_annotations_ + collections::IVector MidiSystemExclusiveMessageHelper::GetDataBytesFromSingleSystemExclusive7Message( + midi2::MidiMessage64 const& message) noexcept + { + auto result = winrt::single_threaded_vector(); + + AppendDataBytesFromSingleSystemExclusive7Message(message.Word0(), message.Word1(), result); + + return result; + } + + + + + + _Use_decl_annotations_ + bool MidiSystemExclusiveMessageHelper::MessageIsSystemExclusive7Message(uint32_t word0) noexcept + { + return internal::GetUmpMessageTypeFromFirstWord(word0) == MIDI_UMP_MESSAGE_TYPE_DATA_MESSAGE_64 && + internal::GetStatusFromDataMessage64FirstWord(word0) <= 0x03; // 0x0, 0x1, 0x2, 0x3 are SysEx7 + } +} diff --git a/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.h b/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.h new file mode 100644 index 000000000..ee70856e7 --- /dev/null +++ b/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.h @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#pragma once +#include "MidiSystemExclusiveMessageHelper.g.h" + +namespace winrt::Microsoft::Windows::Devices::Midi2::Utilities::SysEx::implementation +{ + struct MidiSystemExclusiveMessageHelper + { + MidiSystemExclusiveMessageHelper() = default; + + static collections::IVector GetDataBytesFromMultipleSystemExclusive7Messages( + _In_ collections::IIterable const& messages) noexcept; + + static collections::IVector GetDataBytesFromSingleSystemExclusive7Message( + _In_ midi2::MidiMessage64 const& message) noexcept; + + static collections::IVector GetDataBytesFromSingleSystemExclusive7Message( + _In_ uint32_t const word0, + _In_ uint32_t const word1 + ) noexcept; + + static uint8_t AppendDataBytesFromSingleSystemExclusive7Message( + _In_ midi2::MidiMessage64 const& message, + _In_ collections::IVector dataBytesToAppendTo) noexcept; + + static uint8_t AppendDataBytesFromSingleSystemExclusive7Message( + _In_ uint32_t const word0, + _In_ uint32_t const word1, + _In_ collections::IVector dataBytesToAppendTo) noexcept; + + static uint8_t GetDataByteCountFromSystemExclusive7MessageFirstWord(_In_ uint32_t word0) noexcept; + static bool MessageIsSystemExclusive7Message(_In_ uint32_t word0) noexcept; + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::Utilities::SysEx::factory_implementation +{ + struct MidiSystemExclusiveMessageHelper : MidiSystemExclusiveMessageHelperT + { + }; + +} diff --git a/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.idl b/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.idl new file mode 100644 index 000000000..70e71d0ae --- /dev/null +++ b/src/app-sdk/winrt-utilities-sysex/MidiSystemExclusiveMessageHelper.idl @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +namespace Microsoft.Windows.Devices.Midi2.Utilities.SysEx +{ + static runtimeclass MidiSystemExclusiveMessageHelper + { + // System Exclusive 7 handling + static IVector GetDataBytesFromMultipleSystemExclusive7Messages(IIterable messages); + + static IVector GetDataBytesFromSingleSystemExclusive7Message(Microsoft.Windows.Devices.Midi2.MidiMessage64 message); + static IVector GetDataBytesFromSingleSystemExclusive7Message(UInt32 word0, UInt32 word1); + + static UInt8 AppendDataBytesFromSingleSystemExclusive7Message(Microsoft.Windows.Devices.Midi2.MidiMessage64 message, IVector dataBytesToAppendTo); + static UInt8 AppendDataBytesFromSingleSystemExclusive7Message(UInt32 word0, UInt32 word1, IVector dataBytesToAppendTo); + + static UInt8 GetDataByteCountFromSystemExclusive7MessageFirstWord(UInt32 word0); + static Boolean MessageIsSystemExclusive7Message(UInt32 word0); + + // System Exclusive 8 handling + + + }; +} diff --git a/src/app-sdk/winrt-utilities-sysex/pch.h b/src/app-sdk/winrt-utilities-sysex/pch.h index 649f36120..4c02800cb 100644 --- a/src/app-sdk/winrt-utilities-sysex/pch.h +++ b/src/app-sdk/winrt-utilities-sysex/pch.h @@ -58,6 +58,7 @@ namespace midi2 = ::winrt::Microsoft::Windows::Devices::Midi2; #include #include #include +#include // SDK shared #include @@ -73,4 +74,5 @@ namespace implementation = ::winrt::Microsoft::Windows::Devices::Midi2::Utilitie #include "MidiSystemExclusiveSender.h" +#include "MidiSystemExclusiveMessageHelper.h" diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs index 33855ac79..c4e96b4bf 100644 --- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs +++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs @@ -10,6 +10,7 @@ using Microsoft.Windows.Devices.Midi2.Initialization; using Microsoft.Windows.Devices.Midi2.Messages; +using Microsoft.Windows.Devices.Midi2.Utilities.SysEx; namespace Microsoft.Midi.ConsoleApp { @@ -325,9 +326,9 @@ public override int Execute(CommandContext context, Settings settings) index++; - if (MidiMessageHelper.MessageIsSystemExclusive7Message(e.PeekFirstWord())) + if (MidiSystemExclusiveMessageHelper.MessageIsSystemExclusive7Message(e.PeekFirstWord())) { - countSysEx7BytesReceived += MidiMessageHelper.GetDataByteCountFromSystemExclusive7MessageFirstWord(e.PeekFirstWord()); + countSysEx7BytesReceived += MidiSystemExclusiveMessageHelper.GetDataByteCountFromSystemExclusive7MessageFirstWord(e.PeekFirstWord()); } var receivedMessage = new ReceivedMidiMessage() diff --git a/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs b/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs index 20be3c35f..353cfaa1f 100644 --- a/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs +++ b/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs @@ -9,6 +9,7 @@ using Microsoft.Windows.Devices.Midi2.Messages; +using Microsoft.Windows.Devices.Midi2.Utilities.SysEx; namespace Microsoft.Midi.ConsoleApp { @@ -128,6 +129,8 @@ private void BuildStringFormats() private string m_deltaValueDefaultColor = "lightskyblue3_1"; private string m_deltaValueErrorColor = "red"; + private const int m_detailedMessageTypeTextWidth = 35; + public MidiMessageTable(bool verbose) { m_verbose = verbose; @@ -148,10 +151,10 @@ public MidiMessageTable(bool verbose) if (verbose) { - Columns.Add(new MidiMessageTableColumn(11, "Gr", 2, false, "indianred", "")); - Columns.Add(new MidiMessageTableColumn(12, "Ch", 2, true, "mediumorchid3", "")); - Columns.Add(new MidiMessageTableColumn(13, "Decoded Data", -35, false, "deepskyblue1", "")); - Columns.Add(new MidiMessageTableColumn(14, "Message Type", -35, false, "steelblue1_1", "")); + Columns.Add(new MidiMessageTableColumn(11, "Message Type", m_detailedMessageTypeTextWidth * -1, false, "steelblue1_1", "")); + Columns.Add(new MidiMessageTableColumn(12, "Gr", 2, false, "indianred", "")); + Columns.Add(new MidiMessageTableColumn(13, "Ch", 2, true, "mediumorchid3", "")); + Columns.Add(new MidiMessageTableColumn(14, "Decoded Data", -35, false, "grey", "")); } BuildStringFormats(); @@ -180,44 +183,7 @@ public void OutputRow(ReceivedMidiMessage message) { detailedMessageType = MidiMessageHelper.GetMessageDisplayNameFromFirstWord(message.Word0); - // For SysEx, we display the bytes here. We may want to offer decoding for other message - // types as well, in the future, and just have a dedicated column for the decoding. - - const uint maxSysEx7BytesPerMessage = 6; - if (MidiMessageHelper.MessageIsSystemExclusive7Message(message.Word0)) - { - // show the bytes - var byteCount = MidiMessageHelper.GetDataByteCountFromSystemExclusive7MessageFirstWord(message.Word0); - - foreach (var b in MidiMessageHelper.GetDataBytesFromSingleSystemExclusive7Message(message.Word0, message.Word1)) - { - decodedData += b.ToString("X2") + " "; - } - - if (byteCount < maxSysEx7BytesPerMessage) - { - decodedData += "[grey]"; - - for (int i = 0; i < maxSysEx7BytesPerMessage - byteCount; i++) - { - decodedData += "-- "; - } - - decodedData += "[/]"; - } - - decodedData = $"[darkseagreen2]{decodedData}[/]"; - } - - //if (messageType == MidiMessageType.DataMessage64) - //{ - //} - //else if (MessageIsSysEx8(message)) - //{ - //} - //else - //{ - //} + decodedData = GetDecodedOutput(message); } string word0 = string.Empty; @@ -309,7 +275,7 @@ public void OutputRow(ReceivedMidiMessage message) if (deltaValueText.Length > timestampOffsetValueColumnWidth) { - deltaValueText = "######"; + deltaValueText = "000000"; deltaUnitLabel = ""; Columns[m_deltaColumnNumber].DataColor = m_deltaValueErrorColor; } @@ -320,7 +286,7 @@ public void OutputRow(ReceivedMidiMessage message) if (offsetValueText.Length > timestampOffsetValueColumnWidth) { - offsetValueText = "######"; + offsetValueText = "000000"; offsetUnitLabel = ""; Columns[m_offsetColumnNumber].DataColor = m_offsetValueErrorColor; } @@ -341,10 +307,10 @@ public void OutputRow(ReceivedMidiMessage message) deltaValueText, deltaUnitLabel, word0, word1, word2, word3, + detailedMessageType.PadRight(m_detailedMessageTypeTextWidth, ' ').Substring(0, m_detailedMessageTypeTextWidth), groupText, channelText, - decodedData, - detailedMessageType + decodedData ); } else @@ -359,15 +325,215 @@ public void OutputRow(ReceivedMidiMessage message) deltaValueText, deltaUnitLabel, word0, word1, word2, word3, + detailedMessageType.PadRight(m_detailedMessageTypeTextWidth, ' ').Substring(0, m_detailedMessageTypeTextWidth), groupText, channelText, - decodedData, - detailedMessageType + decodedData ); UInt64 outputEnd = MidiClock.Now; } } + + + + public string GetDecodedOutput(ReceivedMidiMessage message) + { + // For SysEx, we display the bytes here. We may want to offer decoding for other message + // types as well, in the future, like note on/off (easier with M1 protocol) + + var messageType = MidiMessageHelper.GetMessageTypeFromMessageFirstWord(message.Word0); + + switch(messageType) + { + case MidiMessageType.Midi1ChannelVoice32: + return GetDecodedMidi1ChannelVoiceData(message); + + case MidiMessageType.DataMessage64: + return GetDecodedSysEx7MessageData(message); + + default: + return string.Empty; + + } + } + + private string GetDecodedMidi1ChannelVoiceData(ReceivedMidiMessage message) + { + string decodedData = string.Empty; + + var status = MidiMessageHelper.GetStatusFromMidi1ChannelVoiceMessage(message.Word0); + + byte dataByte1 = (byte)((message.Word0 >> 8) & 0xFF); + byte dataByte2 = (byte)((message.Word0) & 0xFF); + + switch (status) + { + case Midi1ChannelVoiceMessageStatus.NoteOn: + case Midi1ChannelVoiceMessageStatus.NoteOff: + decodedData = $"Note: [darkseagreen2]{dataByte1.ToString("000")}[/] [deepskyblue1]({MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}{MidiMessageHelper.GetNoteOctaveFromNoteIndex(dataByte1)})[/], "+ + $"Velocity: [darkseagreen2]{dataByte2.ToString("000")}[/]"; + break; + + case Midi1ChannelVoiceMessageStatus.ControlChange: + decodedData = $"Controller: [darkseagreen2]{dataByte1.ToString("000")}[/], Value: [darkseagreen2]{dataByte2.ToString("000")}[/]"; + break; + + case Midi1ChannelVoiceMessageStatus.PitchBend: + decodedData = $"Fine: [darkseagreen2]{dataByte1.ToString("000")}[/], Coarse: [darkseagreen2]{dataByte2.ToString("000")}[/]"; + break; + + case Midi1ChannelVoiceMessageStatus.ChannelPressure: + decodedData = $"Value: [darkseagreen2]{dataByte1.ToString("000")}[/]"; + break; + + case Midi1ChannelVoiceMessageStatus.PolyPressure: + decodedData = $"Key: [darkseagreen2]{dataByte1.ToString("000")}[/], Value: [darkseagreen2]{dataByte2.ToString("000")}[/]"; + break; + + case Midi1ChannelVoiceMessageStatus.ProgramChange: + decodedData = $"Value: [darkseagreen2]{dataByte1.ToString("000")}[/]"; + break; + + default: + break; + } + + return decodedData; + } + + private string GetDecodedMidi2ChannelVoiceData(ReceivedMidiMessage message) + { + string decodedData = string.Empty; + + var status = MidiMessageHelper.GetStatusFromMidi2ChannelVoiceMessageFirstWord(message.Word0); + + byte dataByte1 = (byte)((message.Word0 >> 8) & 0xFF); + byte dataByte2 = (byte)((message.Word0) & 0xFF); + + switch (status) + { + case Midi2ChannelVoiceMessageStatus.NoteOn: + case Midi2ChannelVoiceMessageStatus.NoteOff: + { + UInt16 velocity = (UInt16)((message.Word1 >> 16) & 0xFFFF); + UInt16 attribute = (UInt16)(message.Word1 & 0xFFFF); + + decodedData = + $"Note: [darkseagreen2]{dataByte1.ToString("000")}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + + $"Type: [darkseagreen2]{dataByte2.ToString("000")}[/], " + + $"Vel: [darkseagreen2]{velocity}[/], " + + $"Attr: [darkseagreen2]{attribute}[/]"; + } + break; + + case Midi2ChannelVoiceMessageStatus.PolyPressure: + decodedData = + $"Note: [darkseagreen2]{dataByte1}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + + $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.RegisteredPerNoteController: + case Midi2ChannelVoiceMessageStatus.AssignablePerNoteController: + decodedData = + $"Note: [darkseagreen2]{dataByte1}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + + $"Index: [darkseagreen2]{dataByte2}[/], " + + $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.PerNoteManagement: + decodedData = + $"Note: [darkseagreen2]{dataByte1}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + + $"Detach: [darkseagreen2]{(bool)((dataByte1 & 0x2) == 0x2)}[/], " + + $"Set: [darkseagreen2]{(bool)((dataByte1 & 0x1) == 0x1)}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.ControlChange: + decodedData = + $"Controller: [darkseagreen2]{dataByte1}[/], " + + $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.RegisteredController: + case Midi2ChannelVoiceMessageStatus.AssignableController: + decodedData = + $"Bank: [darkseagreen2]{dataByte1}[/], " + + $"Index: [darkseagreen2]{dataByte2}[/], " + + $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.RelativeRegisteredController: + case Midi2ChannelVoiceMessageStatus.RelativeAssignableController: + decodedData = + $"Bank: [darkseagreen2]{dataByte1}[/], " + + $"Index: [darkseagreen2]{dataByte2}[/], " + + $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.ProgramChange: + decodedData = + $"Program: [darkseagreen2]{(byte)(message.Word1 & 0xFF000000 >> 24)}[/], " + + $"Bank Valid: [darkseagreen2]{(bool)((dataByte1 & 0x1) == 0x1)}[/], " + + $"MSB: [darkseagreen2]{(byte)(message.Word1 & 0x0000FF00 >> 8)}[/], " + + $"LSB: [darkseagreen2]{(byte)(message.Word1 & 0x000000FF)}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.ChannelPressure: + decodedData = $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.PitchBend: + decodedData = $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + case Midi2ChannelVoiceMessageStatus.PerNotePitchBend: + decodedData = + $"Note: [darkseagreen2]{dataByte1}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + + $"Data: [darkseagreen2]{message.Word1}[/]"; + break; + + default: + break; + } + + return decodedData; + } + + + + private string GetDecodedSysEx7MessageData(ReceivedMidiMessage message) + { + string decodedData = string.Empty; + + const uint maxSysEx7BytesPerMessage = 6; + if (MidiSystemExclusiveMessageHelper.MessageIsSystemExclusive7Message(message.Word0)) + { + // show the bytes + var byteCount = MidiSystemExclusiveMessageHelper.GetDataByteCountFromSystemExclusive7MessageFirstWord(message.Word0); + + foreach (var b in MidiSystemExclusiveMessageHelper.GetDataBytesFromSingleSystemExclusive7Message(message.Word0, message.Word1)) + { + decodedData += b.ToString("X2") + " "; + } + + if (byteCount < maxSysEx7BytesPerMessage) + { + decodedData += "[grey]"; + + for (int i = 0; i < maxSysEx7BytesPerMessage - byteCount; i++) + { + decodedData += "-- "; + } + + decodedData += "[/]"; + } + + decodedData = $"[darkseagreen2]{decodedData}[/]"; + } + + return decodedData; + } + } diff --git a/src/user-tools/midi-console/Midi/Midi.csproj b/src/user-tools/midi-console/Midi/Midi.csproj index 3bcc1edcb..607e13a68 100644 --- a/src/user-tools/midi-console/Midi/Midi.csproj +++ b/src/user-tools/midi-console/Midi/Midi.csproj @@ -35,7 +35,7 @@ - + diff --git a/src/user-tools/midi-console/Midi/midi.exe.manifest b/src/user-tools/midi-console/Midi/midi.exe.manifest index c496106bc..d495317c5 100644 --- a/src/user-tools/midi-console/Midi/midi.exe.manifest +++ b/src/user-tools/midi-console/Midi/midi.exe.manifest @@ -150,5 +150,17 @@ xmlns="urn:schemas-microsoft-com:winrt.v1" /> + + + + + + \ No newline at end of file From 2a9bfbdedc339eadd79d90591a27c6b7fb71b722 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Thu, 1 Aug 2024 14:01:11 -0400 Subject: [PATCH 2/6] More console pretty-printing of messages --- ...crosoft.Windows.Devices.Midi2.Messages.dll | Bin 223232 -> 223744 bytes build/staging/version/BundleInfo.wxi | 2 +- .../winrt-messages/MidiMessageHelper.cpp | 29 ++++++++++- src/app-sdk/winrt-messages/Resources.rc | Bin 20246 -> 21734 bytes src/app-sdk/winrt-messages/resource.h | 14 ++++- .../Midi/CustomTable/MidiMessageTable.cs | 49 ++++++++++-------- src/user-tools/midi-console/Midi/Midi.csproj | 2 +- 7 files changed, 69 insertions(+), 27 deletions(-) diff --git a/build/staging/app-sdk/Arm64EC/Microsoft.Windows.Devices.Midi2.Messages.dll b/build/staging/app-sdk/Arm64EC/Microsoft.Windows.Devices.Midi2.Messages.dll index df34118c7a528ef8d1b5ab88e5174ed4118c65ff..7e4464224271c18b72b4128006074774e601a876 100644 GIT binary patch delta 28266 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 cF!*5j!I*69~&%;761SM delta 27928 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 - + diff --git a/src/app-sdk/winrt-messages/MidiMessageHelper.cpp b/src/app-sdk/winrt-messages/MidiMessageHelper.cpp index a137c0c6d..93f469025 100644 --- a/src/app-sdk/winrt-messages/MidiMessageHelper.cpp +++ b/src/app-sdk/winrt-messages/MidiMessageHelper.cpp @@ -377,7 +377,19 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::implementation case msgs::Midi1ChannelVoiceMessageStatus::PolyPressure: return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT2_A_POLY_PRESSURE); //L"MIDI 1.0 Poly Pressure"; case msgs::Midi1ChannelVoiceMessageStatus::ControlChange: - return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT2_B_CONTROL_CHANGE); //L"MIDI 1.0 Control Change"; + { + uint8_t ccNumber = static_cast((word0 & 0x00007F00) >> 8); + + if (ccNumber >= 120) + { + return internal::ResourceGetHString(IDS_MESSAGE_DESC_CC_MODE_BASE_INDEX + ccNumber); + } + else + { + return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT2_B_CONTROL_CHANGE); //L"MIDI 1.0 Control Change"; + } + } + case msgs::Midi1ChannelVoiceMessageStatus::ProgramChange: return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT2_C_PROGRAM_CHANGE); //L"MIDI 1.0 Program Change"; case msgs::Midi1ChannelVoiceMessageStatus::ChannelPressure: @@ -431,7 +443,20 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::Messages::implementation case msgs::Midi2ChannelVoiceMessageStatus::PolyPressure: return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT4_A_POLY_PRESSURE); //L"MIDI 2.0 Poly Pressure"; case msgs::Midi2ChannelVoiceMessageStatus::ControlChange: - return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT4_B_CONTROL_CHANGE); //L"MIDI 2.0 Control Change"; + { + uint8_t ccNumber = static_cast((word0 & 0x00007F00) >> 8); + + if (ccNumber >= 120) + { + return internal::ResourceGetHString(IDS_MESSAGE_DESC_CC_MODE_BASE_INDEX + ccNumber); + } + else + { + return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT4_B_CONTROL_CHANGE); //L"MIDI 2.0 Control Change"; + } + } + + case msgs::Midi2ChannelVoiceMessageStatus::ProgramChange: return internal::ResourceGetHString(IDS_MESSAGE_DESC_MT4_C_PROGRAM_CHANGE); //L"MIDI 2.0 Program Change"; case msgs::Midi2ChannelVoiceMessageStatus::ChannelPressure: diff --git a/src/app-sdk/winrt-messages/Resources.rc b/src/app-sdk/winrt-messages/Resources.rc index 24f02d7d18d91d3681e0b2c89593467ccf468e6c..102813ae3a93c48e0d393a6bb8cea151cda2d9bc 100644 GIT binary patch delta 742 zcmaiyF-yZh9K~N8GYXnPBvt94MI@8x7Lpc(^ipzla4Mx*D72|GanLW}aNs1}-4s88 zU&htV*>}O(5YNhS)WS^4fldb8JwHu_YXWYdY zVyHfR&#S5=)RLTCvICwITqXQ!?Iu@}T6Nc~l~6O|%+;IgSefSUSNRcHLE)vsC-?Bk z%#GOl;3uUiUF4XtHa03OauQVP7H*a){iU!-NsyWsE=n1>RSz+5Mc}NI{&C&hd5j6W z9hDQ`UPTj3;biZBR;r!9> 24)}[/], " + + $"Program: [darkseagreen2]{FormatByteDecimal((byte)(message.Word1 & 0xFF000000 >> 24))}[/], " + $"Bank Valid: [darkseagreen2]{(bool)((dataByte1 & 0x1) == 0x1)}[/], " + - $"MSB: [darkseagreen2]{(byte)(message.Word1 & 0x0000FF00 >> 8)}[/], " + - $"LSB: [darkseagreen2]{(byte)(message.Word1 & 0x000000FF)}[/]"; + $"MSB: [darkseagreen2]{FormatByteDecimal((byte)(message.Word1 & 0x0000FF00 >> 8))}[/], " + + $"LSB: [darkseagreen2]{FormatByteDecimal((byte)(message.Word1 & 0x000000FF))}[/]"; break; case Midi2ChannelVoiceMessageStatus.ChannelPressure: @@ -488,7 +493,7 @@ private string GetDecodedMidi2ChannelVoiceData(ReceivedMidiMessage message) case Midi2ChannelVoiceMessageStatus.PerNotePitchBend: decodedData = - $"Note: [darkseagreen2]{dataByte1}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + + $"Note: [darkseagreen2]{FormatByteDecimal(dataByte1)}[/] [deepskyblue1](May be: {MidiMessageHelper.GetNoteDisplayNameFromNoteIndex(dataByte1)}[/], " + $"Data: [darkseagreen2]{message.Word1}[/]"; break; diff --git a/src/user-tools/midi-console/Midi/Midi.csproj b/src/user-tools/midi-console/Midi/Midi.csproj index 607e13a68..3b99ebc71 100644 --- a/src/user-tools/midi-console/Midi/Midi.csproj +++ b/src/user-tools/midi-console/Midi/Midi.csproj @@ -35,7 +35,7 @@ - + From 680975846f054fb3db2e5c61ba567023d9fb94f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 02:06:39 +0000 Subject: [PATCH 3/6] Bump rexml from 3.3.2 to 3.3.3 in /docs Bumps [rexml](https://github.com/ruby/rexml) from 3.3.2 to 3.3.3. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.2...v3.3.3) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- docs/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 5b4d4180a..23cef22d9 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -70,7 +70,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.3.2) + rexml (3.3.3) strscan rouge (4.2.0) rubyzip (2.3.2) From 2af82c0bdbeea54842e0f88a3fb873036af9c680 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Fri, 2 Aug 2024 11:29:24 -0400 Subject: [PATCH 4/6] Start of Virtual Patch Bay SDK types --- build/nuke_build/Build.cs | 3 + src/app-sdk/app-sdk.sln | 19 + src/app-sdk/coalesce/coalesce.vcxproj | 3 + .../Microsoft.Windows.Devices.Midi2.props | 3 + ...dows.Devices.Midi2.VirtualPatchBay.vcxproj | 324 ++++++++++++++++++ ...ices.Midi2.VirtualPatchBay.vcxproj.filters | 64 ++++ .../MidiVirtualPatchBayManager.cpp | 42 +++ .../MidiVirtualPatchBayManager.h | 40 +++ .../MidiVirtualPatchBayManager.idl | 35 ++ ...MidiVirtualPatchBayRouteCreationConfig.cpp | 50 +++ .../MidiVirtualPatchBayRouteCreationConfig.h | 42 +++ ...MidiVirtualPatchBayRouteCreationConfig.idl | 28 ++ ...MidiVirtualPatchBayRouteCreationResult.idl | 20 ++ .../MidiVirtualPatchBayRouteDefinition.idl | 21 ++ .../MidiVirtualPatchBayRouteRemovalConfig.cpp | 50 +++ .../MidiVirtualPatchBayRouteRemovalConfig.h | 42 +++ .../MidiVirtualPatchBayRouteRemovalConfig.idl | 21 ++ .../PropertySheet.props | 16 + .../winrt-virtual-patchbay/makefile.inc | 3 + .../winrt-virtual-patchbay/midi-app-sdk.def | 3 + .../winrt-virtual-patchbay/packages.config | 5 + src/app-sdk/winrt-virtual-patchbay/pch.cpp | 10 + src/app-sdk/winrt-virtual-patchbay/pch.h | 110 ++++++ 23 files changed, 954 insertions(+) create mode 100644 src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj create mode 100644 src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationResult.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/PropertySheet.props create mode 100644 src/app-sdk/winrt-virtual-patchbay/makefile.inc create mode 100644 src/app-sdk/winrt-virtual-patchbay/midi-app-sdk.def create mode 100644 src/app-sdk/winrt-virtual-patchbay/packages.config create mode 100644 src/app-sdk/winrt-virtual-patchbay/pch.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/pch.h diff --git a/build/nuke_build/Build.cs b/build/nuke_build/Build.cs index 9584600c4..eebb2a5e7 100644 --- a/build/nuke_build/Build.cs +++ b/build/nuke_build/Build.cs @@ -264,6 +264,7 @@ class Build : NukeBuild "Microsoft.Windows.Devices.Midi2.Endpoints.Loopback", "Microsoft.Windows.Devices.Midi2.Endpoints.Virtual", "Microsoft.Windows.Devices.Midi2.Utilities.SysEx", + "Microsoft.Windows.Devices.Midi2.VirtualPatchBay", "Microsoft.Windows.Devices.Midi2.Initialization" // this last one gets packed 100% in the nuget, including the impl }) { @@ -540,6 +541,7 @@ void UpdateSetupBundleInfoIncludeFile(string platform) FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Endpoints.Loopback.dll", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Endpoints.Virtual.dll", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Utilities.SysEx.dll", stagingFolder, FileExistsPolicy.Overwrite, true); + FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.VirtualPatchBay.dll", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Initialization.dll", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.pri", stagingFolder, FileExistsPolicy.Overwrite, true); @@ -550,6 +552,7 @@ void UpdateSetupBundleInfoIncludeFile(string platform) FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Messages.pri", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Endpoints.Loopback.pri", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Endpoints.Virtual.pri", stagingFolder, FileExistsPolicy.Overwrite, true); + FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.VirtualPatchBay.pri", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Utilities.SysEx.pri", stagingFolder, FileExistsPolicy.Overwrite, true); FileSystemTasks.CopyFileToDirectory(runtimesFolder / "Microsoft.Windows.Devices.Midi2.Initialization.pri", stagingFolder, FileExistsPolicy.Overwrite, true); diff --git a/src/app-sdk/app-sdk.sln b/src/app-sdk/app-sdk.sln index 73b4c1ebd..d4629335e 100644 --- a/src/app-sdk/app-sdk.sln +++ b/src/app-sdk/app-sdk.sln @@ -64,6 +64,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midiusbinfo", "midiusbinfo\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Windows.Devices.Midi2.Utilities.SysEx", "winrt-utilities-sysex\Microsoft.Windows.Devices.Midi2.Utilities.SysEx.vcxproj", "{0D4739EF-C0D3-441C-AC25-20A55909E1DC}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Windows.Devices.Midi2.VirtualPatchBay", "winrt-virtual-patchbay\Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj", "{7BCB819F-CA97-4312-BF7B-1919A5CCDE69}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -348,6 +350,22 @@ Global {0D4739EF-C0D3-441C-AC25-20A55909E1DC}.Release|ARM64EC.Build.0 = Release|ARM64EC {0D4739EF-C0D3-441C-AC25-20A55909E1DC}.Release|x64.ActiveCfg = Release|x64 {0D4739EF-C0D3-441C-AC25-20A55909E1DC}.Release|x64.Build.0 = Release|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|Any CPU.ActiveCfg = Debug|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|Any CPU.Build.0 = Debug|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|ARM64.Build.0 = Debug|ARM64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|ARM64EC.Build.0 = Debug|ARM64EC + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|x64.ActiveCfg = Debug|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Debug|x64.Build.0 = Debug|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|Any CPU.ActiveCfg = Release|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|Any CPU.Build.0 = Release|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|ARM64.ActiveCfg = Release|ARM64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|ARM64.Build.0 = Release|ARM64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|ARM64EC.Build.0 = Release|ARM64EC + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|x64.ActiveCfg = Release|x64 + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -375,6 +393,7 @@ Global {4DABE157-7DD5-422A-8C77-B83EAC9987D0} = {900D72D2-91F0-4E6C-B694-192FD48393D2} {0F688DE9-BE99-4A86-BE79-C5BE32BC471D} = {C8B31D71-0226-4D2D-AC78-53D5C84F472F} {0D4739EF-C0D3-441C-AC25-20A55909E1DC} = {F5AE94B4-47A7-4D35-A9EE-65FD4CF58C4B} + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69} = {F5AE94B4-47A7-4D35-A9EE-65FD4CF58C4B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AE1DF8B9-9FAB-4E20-8AC6-FF316882222F} diff --git a/src/app-sdk/coalesce/coalesce.vcxproj b/src/app-sdk/coalesce/coalesce.vcxproj index f5f0ca627..a13cdda01 100644 --- a/src/app-sdk/coalesce/coalesce.vcxproj +++ b/src/app-sdk/coalesce/coalesce.vcxproj @@ -211,6 +211,9 @@ {0d4739ef-c0d3-441c-ac25-20a55909e1dc} + + {7bcb819f-ca97-4312-bf7b-1919a5ccde69} + diff --git a/src/app-sdk/projections/dotnet-and-cpp/nuget/Microsoft.Windows.Devices.Midi2.props b/src/app-sdk/projections/dotnet-and-cpp/nuget/Microsoft.Windows.Devices.Midi2.props index a1a1ef898..5847802d7 100644 --- a/src/app-sdk/projections/dotnet-and-cpp/nuget/Microsoft.Windows.Devices.Midi2.props +++ b/src/app-sdk/projections/dotnet-and-cpp/nuget/Microsoft.Windows.Devices.Midi2.props @@ -41,6 +41,9 @@ $(NugetRoot)\ref\native\Microsoft.Windows.Devices.Midi2.Utilities.SysEx.winmd + + $(NugetRoot)\ref\native\Microsoft.Windows.Devices.Midi2.VirtualPatchBay.winmd + $(NugetRoot)\ref\native\Microsoft.Windows.Devices.Midi2.Initialization.winmd diff --git a/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj new file mode 100644 index 000000000..6c5678c15 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj @@ -0,0 +1,324 @@ + + + + + Microsoft.Windows.Devices.Midi2.VirtualPatchBay + $(ProjectName) + {7BCB819F-CA97-4312-BF7B-1919A5CCDE69} + true + true + true + true + C++/WinRT + true + 10.0 + 10.0.20348.0 + true + en-US + 14.0 + true + Windows Store + 10.0 + None + + + + + + + Debug + ARM64 + + + Debug + ARM64EC + + + Debug + x64 + + + Release + ARM64 + + + Release + ARM64EC + + + Release + x64 + + + + DynamicLibrary + v143 + v142 + v141 + v140 + Unicode + false + + + true + + + false + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + + + + $(IncludePath) + $(ProjectName) + true + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\ + $(LibraryPath) + + + $(IncludePath) + $(ProjectName) + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\ + $(LibraryPath) + + + $(IncludePath) + $(ProjectName) + true + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\ + $(LibraryPath) + + + $(IncludePath) + $(ProjectName) + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\ + $(LibraryPath) + + + $(IncludePath) + $(ProjectName) + true + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\ + $(LibraryPath) + + + $(IncludePath) + $(ProjectName) + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\ + $(LibraryPath) + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + false + midi-app-sdk.def + + + + + _DEBUG;%(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP + stdcpp20 + false + true + true + true + $(SolutionDir)..\api\inc;$(SolutionDir)..\shared\api-ref\$(Platform);$(SolutionDir)sdk-shared;%(AdditionalIncludeDirectories) + $(SolutionDir)..\api\inc;$(SolutionDir)..\shared\api-ref\$(Platform);$(SolutionDir)sdk-shared;%(AdditionalIncludeDirectories) + $(SolutionDir)..\api\inc;$(SolutionDir)..\shared\api-ref\$(Platform);$(SolutionDir)sdk-shared;%(AdditionalIncludeDirectories) + stdcpp20 + stdcpp20 + + + false + false + %(AdditionalDependencies) + + + false + false + %(AdditionalDependencies) + + + false + false + %(AdditionalDependencies) + + + + + + + + + + + + + + + Yes + + + Yes + + + Yes + + + + + NDEBUG;%(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP + $(SolutionDir)..\api\inc;$(SolutionDir)..\shared\api-ref\$(Platform);$(SolutionDir)sdk-shared;%(AdditionalIncludeDirectories) + $(SolutionDir)..\api\inc;$(SolutionDir)..\shared\api-ref\$(Platform);$(SolutionDir)sdk-shared;%(AdditionalIncludeDirectories) + $(SolutionDir)..\api\inc;$(SolutionDir)..\shared\api-ref\$(Platform);$(SolutionDir)sdk-shared;%(AdditionalIncludeDirectories) + true + true + true + stdcpp20 + stdcpp20 + stdcpp20 + + + true + true + false + false + false + %(AdditionalDependencies) + %(AdditionalDependencies) + %(AdditionalDependencies) + + + + + + + + + + + + + + + Yes + + + Yes + + + Yes + + + + + MidiVirtualPatchBayManager.idl + + + MidiVirtualPatchBayRouteCreationConfig.idl + + + MidiVirtualPatchBayRouteRemovalConfig.idl + + + + + + + MidiVirtualPatchBayManager.idl + + + MidiVirtualPatchBayRouteCreationConfig.idl + + + MidiVirtualPatchBayRouteRemovalConfig.idl + + + Create + + + + + + + + + + + + + + + + + + + {9eaa3af3-7328-4f67-a011-e2dd8fbaa4c4} + + + {72d1a831-0492-41cc-aa58-bdd05c1099f7} + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters new file mode 100644 index 000000000..9f137bb56 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters @@ -0,0 +1,64 @@ + + + + + + + + + + SDK + + + SDK + + + SDK + + + + + + SDK + + + SDK + + + SDK + + + + + SDK\Configuration + + + SDK\Configuration + + + SDK\Configuration + + + SDK\Management + + + SDK\Management + + + + + + + + + + {be86096a-366a-491b-825e-1722b96c678d} + + + {7bedd7f9-3966-4a85-b089-916e72f4211d} + + + {656ea1ee-7afd-4546-89aa-1e2ed9d80f83} + + + \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp new file mode 100644 index 000000000..02c903798 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp @@ -0,0 +1,42 @@ +#include "pch.h" +#include "MidiVirtualPatchBayManager.h" +#include "MidiVirtualPatchBayManager.g.cpp" + +// WARNING: This file is automatically generated by a tool. Do not directly +// add this file to your project, as any changes you make will be lost. +// This file is a stub you can use as a starting point for your implementation. +// +// To add a copy of this file to your project: +// 1. Copy this file from its original location to the location where you store +// your other source files (e.g. the project root). +// 2. Add the copied file to your project. In Visual Studio, you can use +// Project -> Add Existing Item. +// 3. Delete this comment and the 'static_assert' (below) from the copied file. +// Do not modify the original file. +// +// To update an existing file in your project: +// 1. Copy the relevant changes from this file and merge them into the copy +// you made previously. +// +// This assertion helps prevent accidental modification of generated files. +static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + bool MidiVirtualPatchBayManager::IsTransportAvailable() + { + throw hresult_not_implemented(); + } + winrt::guid MidiVirtualPatchBayManager::AbstractionId() + { + throw hresult_not_implemented(); + } + winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationResult MidiVirtualPatchBayManager::CreateRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationConfig const& creationConfig) + { + throw hresult_not_implemented(); + } + bool MidiVirtualPatchBayManager::RemoveRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteRemovalConfig const& removalConfig) + { + throw hresult_not_implemented(); + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h new file mode 100644 index 000000000..005de985d --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h @@ -0,0 +1,40 @@ +#pragma once +#include "MidiVirtualPatchBayManager.g.h" + +// WARNING: This file is automatically generated by a tool. Do not directly +// add this file to your project, as any changes you make will be lost. +// This file is a stub you can use as a starting point for your implementation. +// +// To add a copy of this file to your project: +// 1. Copy this file from its original location to the location where you store +// your other source files (e.g. the project root). +// 2. Add the copied file to your project. In Visual Studio, you can use +// Project -> Add Existing Item. +// 3. Delete this comment and the 'static_assert' (below) from the copied file. +// Do not modify the original file. +// +// To update an existing file in your project: +// 1. Copy the relevant changes from this file and merge them into the copy +// you made previously. +// +// This assertion helps prevent accidental modification of generated files. +static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBayManager : MidiVirtualPatchBayManagerT + { + MidiVirtualPatchBayManager() = default; + + static bool IsTransportAvailable(); + static winrt::guid AbstractionId(); + static winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationResult CreateRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationConfig const& creationConfig); + static bool RemoveRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteRemovalConfig const& removalConfig); + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBayManager : MidiVirtualPatchBayManagerT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl new file mode 100644 index 000000000..1399542a4 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +import "MidiVirtualPatchBayRouteCreationResult.idl"; +import "MidiVirtualPatchBayRouteCreationConfig.idl"; +import "MidiVirtualPatchBayRouteRemovalConfig.idl"; +import "MidiVirtualPatchBayRouteDefinition.idl"; + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + [default_interface] + static runtimeclass MidiVirtualPatchBayManager + { + static Boolean IsTransportAvailable{ get; }; + + static Guid AbstractionId{ get; }; + + static MidiVirtualPatchBayRouteCreationResult CreateRoute( + MidiVirtualPatchBayRouteCreationConfig creationConfig); + + static Boolean RemoveRoute( + MidiVirtualPatchBayRouteRemovalConfig removalConfig); + + + static IVector GetRoutes(); + + } +} + diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp new file mode 100644 index 000000000..616991435 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp @@ -0,0 +1,50 @@ +#include "pch.h" +#include "MidiVirtualPatchBayRouteCreationConfig.h" +#include "MidiVirtualPatchBayRouteCreationConfig.g.cpp" + +// WARNING: This file is automatically generated by a tool. Do not directly +// add this file to your project, as any changes you make will be lost. +// This file is a stub you can use as a starting point for your implementation. +// +// To add a copy of this file to your project: +// 1. Copy this file from its original location to the location where you store +// your other source files (e.g. the project root). +// 2. Add the copied file to your project. In Visual Studio, you can use +// Project -> Add Existing Item. +// 3. Delete this comment and the 'static_assert' (below) from the copied file. +// Do not modify the original file. +// +// To update an existing file in your project: +// 1. Copy the relevant changes from this file and merge them into the copy +// you made previously. +// +// This assertion helps prevent accidental modification of generated files. +static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + MidiVirtualPatchBayRouteCreationConfig::MidiVirtualPatchBayRouteCreationConfig(winrt::guid const& routeId) + { + throw hresult_not_implemented(); + } + winrt::guid MidiVirtualPatchBayRouteCreationConfig::RouteId() + { + throw hresult_not_implemented(); + } + void MidiVirtualPatchBayRouteCreationConfig::RouteId(winrt::guid const& value) + { + throw hresult_not_implemented(); + } + winrt::guid MidiVirtualPatchBayRouteCreationConfig::TransportId() + { + throw hresult_not_implemented(); + } + bool MidiVirtualPatchBayRouteCreationConfig::IsFromCurrentConfigFile() + { + throw hresult_not_implemented(); + } + hstring MidiVirtualPatchBayRouteCreationConfig::GetConfigJson() + { + throw hresult_not_implemented(); + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h new file mode 100644 index 000000000..9d5ec6d6f --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h @@ -0,0 +1,42 @@ +#pragma once +#include "MidiVirtualPatchBayRouteCreationConfig.g.h" + +// WARNING: This file is automatically generated by a tool. Do not directly +// add this file to your project, as any changes you make will be lost. +// This file is a stub you can use as a starting point for your implementation. +// +// To add a copy of this file to your project: +// 1. Copy this file from its original location to the location where you store +// your other source files (e.g. the project root). +// 2. Add the copied file to your project. In Visual Studio, you can use +// Project -> Add Existing Item. +// 3. Delete this comment and the 'static_assert' (below) from the copied file. +// Do not modify the original file. +// +// To update an existing file in your project: +// 1. Copy the relevant changes from this file and merge them into the copy +// you made previously. +// +// This assertion helps prevent accidental modification of generated files. +static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBayRouteCreationConfig : MidiVirtualPatchBayRouteCreationConfigT + { + MidiVirtualPatchBayRouteCreationConfig() = default; + + MidiVirtualPatchBayRouteCreationConfig(winrt::guid const& routeId); + winrt::guid RouteId(); + void RouteId(winrt::guid const& value); + winrt::guid TransportId(); + bool IsFromCurrentConfigFile(); + hstring GetConfigJson(); + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBayRouteCreationConfig : MidiVirtualPatchBayRouteCreationConfigT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl new file mode 100644 index 000000000..82485aabf --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +import "MidiVirtualPatchBayRouteDefinition.idl"; + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + [default_interface] + runtimeclass MidiVirtualPatchBayRouteCreationConfig : Microsoft.Windows.Devices.Midi2.ServiceConfig.IMidiServiceTransportPluginConfig + { + MidiVirtualPatchBayRouteCreationConfig(); + + MidiVirtualPatchBayRouteCreationConfig( + Guid routeId + ); + + + Guid RouteId; + + } +} + diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationResult.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationResult.idl new file mode 100644 index 000000000..f58205234 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationResult.idl @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + struct MidiVirtualPatchBayRouteCreationResult + { + Boolean Success; + + Guid RouteId; + + + }; +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl new file mode 100644 index 000000000..7e79ee2d7 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + struct MidiVirtualPatchBayRouteDefinition + { + String Name; + String UniqueId; + String Description; + + Boolean IsEnabled; + + }; +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp new file mode 100644 index 000000000..fab354151 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp @@ -0,0 +1,50 @@ +#include "pch.h" +#include "MidiVirtualPatchBayRouteRemovalConfig.h" +#include "MidiVirtualPatchBayRouteRemovalConfig.g.cpp" + +// WARNING: This file is automatically generated by a tool. Do not directly +// add this file to your project, as any changes you make will be lost. +// This file is a stub you can use as a starting point for your implementation. +// +// To add a copy of this file to your project: +// 1. Copy this file from its original location to the location where you store +// your other source files (e.g. the project root). +// 2. Add the copied file to your project. In Visual Studio, you can use +// Project -> Add Existing Item. +// 3. Delete this comment and the 'static_assert' (below) from the copied file. +// Do not modify the original file. +// +// To update an existing file in your project: +// 1. Copy the relevant changes from this file and merge them into the copy +// you made previously. +// +// This assertion helps prevent accidental modification of generated files. +static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + MidiVirtualPatchBayRouteRemovalConfig::MidiVirtualPatchBayRouteRemovalConfig(winrt::guid const& routeId) + { + throw hresult_not_implemented(); + } + winrt::guid MidiVirtualPatchBayRouteRemovalConfig::RouteId() + { + throw hresult_not_implemented(); + } + void MidiVirtualPatchBayRouteRemovalConfig::RouteId(winrt::guid const& value) + { + throw hresult_not_implemented(); + } + winrt::guid MidiVirtualPatchBayRouteRemovalConfig::TransportId() + { + throw hresult_not_implemented(); + } + bool MidiVirtualPatchBayRouteRemovalConfig::IsFromCurrentConfigFile() + { + throw hresult_not_implemented(); + } + hstring MidiVirtualPatchBayRouteRemovalConfig::GetConfigJson() + { + throw hresult_not_implemented(); + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h new file mode 100644 index 000000000..ae8420f1d --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h @@ -0,0 +1,42 @@ +#pragma once +#include "MidiVirtualPatchBayRouteRemovalConfig.g.h" + +// WARNING: This file is automatically generated by a tool. Do not directly +// add this file to your project, as any changes you make will be lost. +// This file is a stub you can use as a starting point for your implementation. +// +// To add a copy of this file to your project: +// 1. Copy this file from its original location to the location where you store +// your other source files (e.g. the project root). +// 2. Add the copied file to your project. In Visual Studio, you can use +// Project -> Add Existing Item. +// 3. Delete this comment and the 'static_assert' (below) from the copied file. +// Do not modify the original file. +// +// To update an existing file in your project: +// 1. Copy the relevant changes from this file and merge them into the copy +// you made previously. +// +// This assertion helps prevent accidental modification of generated files. +static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBayRouteRemovalConfig : MidiVirtualPatchBayRouteRemovalConfigT + { + MidiVirtualPatchBayRouteRemovalConfig() = default; + + MidiVirtualPatchBayRouteRemovalConfig(winrt::guid const& routeId); + winrt::guid RouteId(); + void RouteId(winrt::guid const& value); + winrt::guid TransportId(); + bool IsFromCurrentConfigFile(); + hstring GetConfigJson(); + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBayRouteRemovalConfig : MidiVirtualPatchBayRouteRemovalConfigT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.idl new file mode 100644 index 000000000..79b3e9a70 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.idl @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +import "MidiVirtualPatchBayRouteDefinition.idl"; + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + [default_interface] + runtimeclass MidiVirtualPatchBayRouteRemovalConfig : Microsoft.Windows.Devices.Midi2.ServiceConfig.IMidiServiceTransportPluginConfig + { + MidiVirtualPatchBayRouteRemovalConfig(Guid routeId); + + Guid RouteId; + } +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/PropertySheet.props b/src/app-sdk/winrt-virtual-patchbay/PropertySheet.props new file mode 100644 index 000000000..e34141b01 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/PropertySheet.props @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/makefile.inc b/src/app-sdk/winrt-virtual-patchbay/makefile.inc new file mode 100644 index 000000000..bad71dcc9 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/makefile.inc @@ -0,0 +1,3 @@ +$(OBJ_PATH)\$(O)\merged\Windows.Devices.Midi2.winmd : + -$(MKDIR) $(OBJ_PATH)\$(O)\merged + $(MDMERGE) -i $(OBJ_PATH)\$(O) -o $(OBJ_PATH)\$(O)\merged -metadata_dir $(PROJECT_SDK_METADATA_PATH) -partial \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/midi-app-sdk.def b/src/app-sdk/winrt-virtual-patchbay/midi-app-sdk.def new file mode 100644 index 000000000..24e7c1235 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/midi-app-sdk.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/src/app-sdk/winrt-virtual-patchbay/packages.config b/src/app-sdk/winrt-virtual-patchbay/packages.config new file mode 100644 index 000000000..7b7f4f96c --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/pch.cpp b/src/app-sdk/winrt-virtual-patchbay/pch.cpp new file mode 100644 index 000000000..b437ca7e5 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/pch.cpp @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +#include "pch.h" diff --git a/src/app-sdk/winrt-virtual-patchbay/pch.h b/src/app-sdk/winrt-virtual-patchbay/pch.h new file mode 100644 index 000000000..53689ec8f --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/pch.h @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + + +#pragma once + +//#define _VSDESIGNER_DONT_LOAD_AS_DLL + + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace json = ::winrt::Windows::Data::Json; +namespace enumeration = ::winrt::Windows::Devices::Enumeration; +namespace midi1 = ::winrt::Windows::Devices::Midi; +namespace foundation = ::winrt::Windows::Foundation; +namespace collections = ::winrt::Windows::Foundation::Collections; + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// pre-declare namespaces + +namespace WindowsMidiServicesInternal {}; +namespace winrt::Microsoft::Windows::Devices::Midi2 {}; + +namespace internal = ::WindowsMidiServicesInternal; +namespace midi2 = ::winrt::Microsoft::Windows::Devices::Midi2; + + +#include +#include +#include + +// shared +#include // general shared +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// service interface +#include +#include +#include + +// SDK shared +#include + +// References to other midi2 SDKs ------------------------------------- + +#include +namespace midi2 = ::winrt::Microsoft::Windows::Devices::Midi2; + +#include +namespace svc = ::winrt::Microsoft::Windows::Devices::Midi2::ServiceConfig; + +//#include +//namespace msgs = ::winrt::Microsoft::Windows::Devices::Midi2::Messages; + +// Project-local ------------------------------------------------ + +namespace winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback {}; +namespace winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback::implementation {}; +namespace loop = ::winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback; +namespace implementation = ::winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback::implementation; + +//#include "resource.h" + +#include "MidiVirtualPatchBayRouteCreationConfig.h" +#include "MidiVirtualPatchBayRouteRemovalConfig.h" + +#include "MidiVirtualPatchBayManager.h" From 6232c5266971a3533124267efa7fd14b3c4dfea0 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Sun, 4 Aug 2024 22:42:14 -0400 Subject: [PATCH 5/6] Add timer resolution reporting to mididiag --- src/app-sdk/mididiag/main.cpp | 62 ++++++++++++++++++++++ src/app-sdk/mididiag/mididiag.vcxproj | 12 ++--- src/app-sdk/mididiag/mididiag_field_defs.h | 9 ++++ src/app-sdk/mididiag/pch.h | 5 ++ src/app-sdk/midiusbinfo/pch.h | 1 + 5 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/app-sdk/mididiag/main.cpp b/src/app-sdk/mididiag/main.cpp index 474334b01..4f50876f3 100644 --- a/src/app-sdk/mididiag/main.cpp +++ b/src/app-sdk/mididiag/main.cpp @@ -129,6 +129,34 @@ void OutputNumericField(_In_ std::wstring const& fieldName, _In_ uint32_t const << std::endl; } +void OutputDoubleField(_In_ std::wstring const& fieldName, _In_ double const value, _In_ uint32_t precision) +{ + OutputFieldLabel(fieldName); + + std::wcout + << fieldSeparator + << std::dec + << std::setprecision(precision) + << value + << std::endl; +} + +void OutputDecimalMillisecondsField(_In_ std::wstring const& fieldName, _In_ double const value, _In_ uint32_t precision) +{ + OutputFieldLabel(fieldName); + + std::wcout + << fieldSeparator + << std::dec + << std::setprecision(precision) + << std::fixed + << value + << " ms" + << std::endl; +} + + + void OutputHexNumericField(_In_ std::wstring const& fieldName, _In_ uint32_t const value) { OutputFieldLabel(fieldName); @@ -519,6 +547,40 @@ bool DoSectionSystemInfo(_In_ bool verbose) ::GetNativeSystemInfo(&sysinfoNative); OutputSystemInfo(sysinfoNative); + TIMECAPS timecaps; + auto tcresult = ::timeGetDevCaps(&timecaps, sizeof(timecaps)); + + OutputBlankLine(); + + if (tcresult == MMSYSERR_NOERROR) + { + OutputNumericField(MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMECAPS_MIN_PERIOD, timecaps.wPeriodMin); + OutputNumericField(MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMECAPS_MAX_PERIOD, timecaps.wPeriodMax); + } + else + { + OutputStringField(MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMECAPS_ERROR, std::wstring{ L"Could not get timecaps" }); + } + + ULONG minResolution; + ULONG maxResolution; + ULONG actualResolution; + + auto resresult = NtQueryTimerResolution(&maxResolution, &minResolution, &actualResolution); + + if (resresult == STATUS_SUCCESS) + { + double minResolutionMilliseconds = (double)minResolution / 10000.0; // minResolution is in 100 nanosecond units + double maxResolutionMilliseconds = (double)maxResolution / 10000.0; // maxResolution is in 100 nanosecond units + double actualResolutionMilliseconds = (double)actualResolution / 10000.0; // actualResolution is in 100 nanosecond units + + // results here are in 100ns units + OutputBlankLine(); + OutputDecimalMillisecondsField(MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMER_RESOLUTION_MIN_MS, minResolutionMilliseconds, 3); + OutputDecimalMillisecondsField(MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMER_RESOLUTION_MAX_MS, maxResolutionMilliseconds, 3); + OutputDecimalMillisecondsField(MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMER_RESOLUTION_CURRENT_MS, actualResolutionMilliseconds, 3); + } + return true; } diff --git a/src/app-sdk/mididiag/mididiag.vcxproj b/src/app-sdk/mididiag/mididiag.vcxproj index d1056c544..fffd30e84 100644 --- a/src/app-sdk/mididiag/mididiag.vcxproj +++ b/src/app-sdk/mididiag/mididiag.vcxproj @@ -127,9 +127,9 @@ Console false - %(AdditionalDependencies) - %(AdditionalDependencies) - %(AdditionalDependencies) + ntdll.lib;%(AdditionalDependencies) + ntdll.lib;%(AdditionalDependencies) + ntdll.lib;%(AdditionalDependencies) @@ -159,9 +159,9 @@ true true false - %(AdditionalDependencies) - %(AdditionalDependencies) - %(AdditionalDependencies) + ntdll.lib;%(AdditionalDependencies) + ntdll.lib;%(AdditionalDependencies) + ntdll.lib;%(AdditionalDependencies) diff --git a/src/app-sdk/mididiag/mididiag_field_defs.h b/src/app-sdk/mididiag/mididiag_field_defs.h index 79efc6beb..79eb4055d 100644 --- a/src/app-sdk/mididiag/mididiag_field_defs.h +++ b/src/app-sdk/mididiag/mididiag_field_defs.h @@ -70,6 +70,15 @@ #define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_PROCESSOR_LEVEL L"processor_level" #define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_PROCESSOR_REVISION L"processor_revision" +#define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMECAPS_ERROR L"timecaps_error" +#define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMECAPS_MIN_PERIOD L"timecaps_min_period" +#define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMECAPS_MAX_PERIOD L"timecaps_max_period" + +#define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMER_RESOLUTION_MIN_MS L"timer_resolution_min" +#define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMER_RESOLUTION_MAX_MS L"timer_resolution_max" +#define MIDIDIAG_FIELD_LABEL_SYSTEM_INFO_TIMER_RESOLUTION_CURRENT_MS L"timer_resolution_current" + + #define MIDIDIAG_SECTION_LABEL_HEADER L"header" #define MIDIDIAG_FIELD_LABEL_CURRENT_TIME L"current_time" diff --git a/src/app-sdk/mididiag/pch.h b/src/app-sdk/mididiag/pch.h index eb542e265..47a667ca9 100644 --- a/src/app-sdk/mididiag/pch.h +++ b/src/app-sdk/mididiag/pch.h @@ -12,6 +12,8 @@ #include #include +#include + //#pragma warning (disable: 4005) //#include //#pragma warning (pop) @@ -42,6 +44,9 @@ namespace diag = winrt::Microsoft::Windows::Devices::Midi2::Diagnostics; namespace svc = winrt::Microsoft::Windows::Devices::Midi2::ServiceConfig; #include "combaseapi.h" +#include +#include + #include "wstring_util.h" namespace internal = ::WindowsMidiServicesInternal; diff --git a/src/app-sdk/midiusbinfo/pch.h b/src/app-sdk/midiusbinfo/pch.h index aa3768a9a..2889949fd 100644 --- a/src/app-sdk/midiusbinfo/pch.h +++ b/src/app-sdk/midiusbinfo/pch.h @@ -64,6 +64,7 @@ namespace collections = winrt::Windows::Foundation::Collections; //#include "Devpkey.h" #include + #include "wstring_util.h" From 7672adfd4f0d748b2049b4e3f16b6ab0db1a0492 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Sun, 4 Aug 2024 22:42:39 -0400 Subject: [PATCH 6/6] Working on virtual patchbay --- build/staging/version/BundleInfo.wxi | 2 +- ...idi2.VirtualPatchBayRoutingDestination.cpp | 20 +++++- .../Midi2.VirtualPatchBayRoutingDestination.h | 3 +- .../Midi2.VirtualPatchBayRoutingSource.cpp | 70 ++++++++++++++----- .../Midi2.VirtualPatchBayRoutingSource.h | 11 +-- src/app-sdk/MyMidiApp.exe.manifest | 31 ++++++++ src/app-sdk/app-sdk.sln | 3 + ...dows.Devices.Midi2.VirtualPatchBay.vcxproj | 52 ++++++++++---- ...ices.Midi2.VirtualPatchBay.vcxproj.filters | 21 +++++- ...diVirtualPatchBayDestinationDefinition.cpp | 28 ++++++++ ...MidiVirtualPatchBayDestinationDefinition.h | 38 ++++++++++ ...diVirtualPatchBayDestinationDefinition.idl | 29 ++++++++ .../MidiVirtualPatchBayManager.cpp | 66 +++++++++++------ .../MidiVirtualPatchBayManager.h | 46 ++++++------ .../MidiVirtualPatchBayManager.idl | 15 ++-- ...MidiVirtualPatchBayRouteCreationConfig.cpp | 52 ++++---------- .../MidiVirtualPatchBayRouteCreationConfig.h | 46 ++++++------ ...MidiVirtualPatchBayRouteCreationConfig.idl | 1 - .../MidiVirtualPatchBayRouteDefinition.cpp | 49 +++++++++++++ .../MidiVirtualPatchBayRouteDefinition.h | 41 +++++++++++ .../MidiVirtualPatchBayRouteDefinition.idl | 17 +++-- .../MidiVirtualPatchBayRouteRemovalConfig.cpp | 53 ++++---------- .../MidiVirtualPatchBayRouteRemovalConfig.h | 45 ++++++------ .../MidiVirtualPatchBayRouteUpdateConfig.cpp | 27 +++++++ .../MidiVirtualPatchBayRouteUpdateConfig.h | 38 ++++++++++ .../MidiVirtualPatchBayRouteUpdateConfig.idl | 25 +++++++ .../MidiVirtualPatchBayRouteUpdateResult.idl | 20 ++++++ .../MidiVirtualPatchBaySourceDefinition.cpp | 41 +++++++++++ .../MidiVirtualPatchBaySourceDefinition.h | 41 +++++++++++ .../MidiVirtualPatchBaySourceDefinition.idl | 27 +++++++ src/app-sdk/winrt-virtual-patchbay/pch.h | 12 ++-- src/user-tools/midi-console/Midi/Midi.csproj | 2 +- .../Config/EndpointConfigMetadataPayload.cs | 19 +++-- .../MidiEndpointNativeDataFormatConverter.cs | 6 +- .../MidiFunctionBlockMidi10Converter.cs | 10 +-- .../Helpers/MidiGroupIndexConverter.cs | 2 +- .../Microsoft.Midi.Settings.csproj | 8 ++- .../Services/PageService.cs | 1 + .../Strings/en-us/Resources.resw | 3 + .../ViewModels/DeviceDetailViewModel.cs | 20 ++++-- .../ViewModels/DevicesViewModel.cs | 2 +- .../ViewModels/ManagementSessionsViewModel.cs | 5 +- .../ViewModels/PluginsTransportViewModel.cs | 2 +- .../ViewModels/RoutesViewModel.cs | 30 ++++++++ .../Views/DeviceDetailPage.xaml | 50 ++++++------- .../Views/DeviceDetailPage.xaml.cs | 15 ++-- .../Views/DevicesPage.xaml | 12 ++-- .../Views/ManagementSessionsPage.xaml | 5 +- .../Views/PluginsTransportPage.xaml | 9 +-- .../Views/RoutesPage.xaml | 15 ++++ .../Views/RoutesPage.xaml.cs | 31 ++++++++ .../Views/ShellPage.xaml | 14 ++-- 52 files changed, 936 insertions(+), 295 deletions(-) create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateResult.idl create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.cpp create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.h create mode 100644 src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.idl create mode 100644 src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/RoutesViewModel.cs create mode 100644 src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml create mode 100644 src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml.cs diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi index 8d0427f45..83cc8bfb7 100644 --- a/build/staging/version/BundleInfo.wxi +++ b/build/staging/version/BundleInfo.wxi @@ -1,4 +1,4 @@ - + diff --git a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.cpp b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.cpp index 6dc6633cf..0c4fdb894 100644 --- a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.cpp +++ b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.cpp @@ -18,6 +18,11 @@ CMidi2VirtualPatchBayRoutingDestination::Initialize( m_matchJson = endpointMatchJson; m_router = router; + for (uint8_t i = 0; i < 16; i++) + { + m_groupTransformMap[i] = i; + } + return S_OK; } @@ -68,7 +73,20 @@ CMidi2VirtualPatchBayRoutingDestination::SetGroupTransforms( std::map groupTransformMap ) { - UNREFERENCED_PARAMETER(groupTransformMap); + // reset all groups before applying any transform + for (uint8_t i = 0; i < 16; i++) + { + m_groupTransformMap[i] = i; + } + + // apply only the transforms presented + for (auto transform : groupTransformMap) + { + if (transform.first < 16) + { + m_groupTransformMap[transform.first] = transform.second; + } + } return S_OK; } diff --git a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.h b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.h index 507f49133..e95e7946a 100644 --- a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.h +++ b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingDestination.h @@ -32,6 +32,7 @@ class CMidi2VirtualPatchBayRoutingDestination : CMidi2VirtualPatchBayRoutingEntry* m_router; std::wstring m_matchJson{ }; + GUID m_endpointAbstractionId{ }; std::wstring m_resolvedEndpointDeviceInterfaceId{ }; wil::com_ptr_nothrow m_endpointBiDi{ nullptr }; @@ -39,6 +40,6 @@ class CMidi2VirtualPatchBayRoutingDestination : // each entry in this array is the destination group. Index is the source group // all values in this array must be valid. Multiple source groups can map to the // same destination group, but not the other way around. - uint8_t m_groupTransformMap[16]{ }; + std::array m_groupTransformMap{ }; }; diff --git a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.cpp b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.cpp index b2096c00f..e05b5cfa4 100644 --- a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.cpp +++ b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.cpp @@ -38,49 +38,83 @@ CMidi2VirtualPatchBayRoutingSource::Callback( // Verify message meets criteria. auto word0 = internal::MidiWord0FromVoidMessageDataPointer(data); + auto mt = internal::GetUmpMessageTypeFromFirstWord(word0); - // if this is a groupless message - if (internal::MessageHasGroupField(word0)) + // check to see if we support this message type + if (m_includedMessageTypes[mt]) { - // if group is not in our list, return - auto groupIndex = internal::GetGroupIndexFromFirstWord(word0); - - if (!m_includedGroupIndexes[groupIndex]) + if (internal::MessageHasGroupField(word0)) { - return S_OK; + // if group is not in our list, return + auto groupIndex = internal::GetGroupIndexFromFirstWord(word0); + + if (!m_includedGroupIndexes[groupIndex]) + { + return S_OK; + } } + + RETURN_IF_FAILED(m_router->Callback(data, length, position, context)); } - else + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT +CMidi2VirtualPatchBayRoutingSource::SetIncludedGroups( + std::vector groupIndexes +) +{ + if (groupIndexes.size() > 0) { - // message has no group field - if (!m_includeGrouplessMessages) + m_includedGroupIndexes = { false }; + + for (auto const messageType : groupIndexes) { - return S_OK; + if (messageType < 16) + { + m_includedGroupIndexes[messageType] = true; + } } } - - RETURN_IF_FAILED(m_router->Callback(data, length, position, context)); + else + { + // if an empty set is provided, all groups are included + m_includedGroupIndexes = { true }; + } return S_OK; } _Use_decl_annotations_ HRESULT -CMidi2VirtualPatchBayRoutingSource::AddIncludedGroups( - std::vector groupIndexes +CMidi2VirtualPatchBayRoutingSource::SetIncludedMessageTypes( + std::vector messageTypes ) { - for (auto const index : groupIndexes) + if (messageTypes.size() > 0) { - if (index < 16) + m_includedMessageTypes = { false }; + + for (auto const messageType : messageTypes) { - m_includedGroupIndexes[index] = true; + if (messageType < 16) + { + m_includedMessageTypes[messageType] = true; + } } } + else + { + // if an empty set is provided, all message types are included + m_includedMessageTypes = { true }; + } return S_OK; } + _Use_decl_annotations_ HRESULT CMidi2VirtualPatchBayRoutingSource::SetEndpointCallback( diff --git a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.h b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.h index c51380de0..397a18d3b 100644 --- a/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.h +++ b/src/api/Abstraction/VirtualPatchbayAbstraction/Midi2.VirtualPatchBayRoutingSource.h @@ -20,7 +20,8 @@ class CMidi2VirtualPatchBayRoutingSource : STDMETHOD(Callback)(_In_ PVOID data, _In_ UINT length, _In_ LONGLONG position, _In_ LONGLONG context); - STDMETHOD(AddIncludedGroups)(_In_ std::vector groupIndexes); + STDMETHOD(SetIncludedGroups)(_In_ std::vector groupIndexes); + STDMETHOD(SetIncludedMessageTypes)(_In_ std::vector messageTypes); STDMETHOD(SetEndpointCallback)(_In_ LPCWSTR resolvedEndpointDeviceInterfaceId, _In_ IMidiCallback* sourceEndpointCallback); STDMETHOD(Cleanup)(); @@ -29,13 +30,15 @@ class CMidi2VirtualPatchBayRoutingSource : CMidi2VirtualPatchBayRoutingEntry* m_router; std::wstring m_matchJson{ }; - std::wstring m_resolvedEndpointDeviceInterfaceId{ }; + GUID m_endpointAbstractionId{ }; + std::wstring m_resolvedEndpointDeviceInterfaceId{ }; - bool m_includeGrouplessMessages{ false }; + // array of booleans indexed by message type. If true, the type is included + std::array m_includedMessageTypes{ true }; // array of booleans. If an index is true, it is included - bool m_includedGroupIndexes[16]{ false }; + std::array m_includedGroupIndexes{ true }; wil::com_ptr m_sourceEndpointBiDi{ nullptr }; diff --git a/src/app-sdk/MyMidiApp.exe.manifest b/src/app-sdk/MyMidiApp.exe.manifest index 131539b9f..d0f8abd83 100644 --- a/src/app-sdk/MyMidiApp.exe.manifest +++ b/src/app-sdk/MyMidiApp.exe.manifest @@ -164,6 +164,37 @@ xmlns="urn:schemas-microsoft-com:winrt.v1" /> + + + + + + + + + + diff --git a/src/app-sdk/app-sdk.sln b/src/app-sdk/app-sdk.sln index d4629335e..e17de24a6 100644 --- a/src/app-sdk/app-sdk.sln +++ b/src/app-sdk/app-sdk.sln @@ -12,6 +12,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Windows.Devices.Midi2.Messages", "winrt-messages\Microsoft.Windows.Devices.Midi2.Messages.vcxproj", "{001601DE-B7AB-41D1-81B7-40286B139841}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Windows.Devices.Midi2.Endpoints.Loopback", "winrt-endpoint-loopback\Microsoft.Windows.Devices.Midi2.Endpoints.Loopback.vcxproj", "{D3B84D5D-8BED-4CB7-B430-B0BF1E46F3A1}" + ProjectSection(ProjectDependencies) = postProject + {001601DE-B7AB-41D1-81B7-40286B139841} = {001601DE-B7AB-41D1-81B7-40286B139841} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Windows.Devices.Midi2.Endpoints.Virtual", "winrt-endpoint-virtual\Microsoft.Windows.Devices.Midi2.Endpoints.Virtual.vcxproj", "{9B93146C-4D9D-4915-BECB-5227DF2667E2}" EndProject diff --git a/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj index 6c5678c15..3344ca42d 100644 --- a/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj +++ b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj @@ -260,38 +260,66 @@ - - MidiVirtualPatchBayManager.idl + + MidiVirtualPatchBayDestinationDefinition.idl - - MidiVirtualPatchBayRouteCreationConfig.idl + + MidiVirtualPatchBayManager.idl + + + MidiVirtualPatchBayRouteCreationConfig.idl + + + MidiVirtualPatchBayRouteDefinition.idl - - MidiVirtualPatchBayRouteRemovalConfig.idl + + MidiVirtualPatchBayRouteRemovalConfig.idl + + + MidiVirtualPatchBayRouteUpdateConfig.idl + + + MidiVirtualPatchBaySourceDefinition.idl - - MidiVirtualPatchBayManager.idl + + MidiVirtualPatchBayDestinationDefinition.idl - - MidiVirtualPatchBayRouteCreationConfig.idl + + MidiVirtualPatchBayManager.idl + + + MidiVirtualPatchBayRouteCreationConfig.idl + + + MidiVirtualPatchBayRouteDefinition.idl + + + MidiVirtualPatchBayRouteRemovalConfig.idl + + + MidiVirtualPatchBayRouteUpdateConfig.idl - - MidiVirtualPatchBayRouteRemovalConfig.idl + + MidiVirtualPatchBaySourceDefinition.idl Create + + + + diff --git a/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters index 9f137bb56..4fcdb3cb2 100644 --- a/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters +++ b/src/app-sdk/winrt-virtual-patchbay/Microsoft.Windows.Devices.Midi2.VirtualPatchBay.vcxproj.filters @@ -32,9 +32,6 @@ SDK\Configuration - - SDK\Configuration - SDK\Configuration @@ -44,6 +41,21 @@ SDK\Management + + SDK\Definitions + + + SDK\Definitions + + + SDK\Configuration + + + SDK\Definitions + + + SDK\Management + @@ -60,5 +72,8 @@ {656ea1ee-7afd-4546-89aa-1e2ed9d80f83} + + {1d805a69-c470-459d-be7d-59011bb9d8d9} + \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.cpp new file mode 100644 index 000000000..d054348cc --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.cpp @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#include "pch.h" +#include "MidiVirtualPatchBayDestinationDefinition.h" +#include "MidiVirtualPatchBayDestinationDefinition.g.cpp" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + + + collections::IMap MidiVirtualPatchBayDestinationDefinition::GroupTransformMap() + { + throw hresult_not_implemented(); + } + + void MidiVirtualPatchBayDestinationDefinition::GroupTransformMap(collections::IMap const& value) + { + UNREFERENCED_PARAMETER(value); + + throw hresult_not_implemented(); + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.h new file mode 100644 index 000000000..57c20729d --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.h @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#pragma once +#include "MidiVirtualPatchBayDestinationDefinition.g.h" + + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBayDestinationDefinition : MidiVirtualPatchBayDestinationDefinitionT + { + MidiVirtualPatchBayDestinationDefinition() = default; + + bool IsEnabled() { return m_isEnabled; } + void IsEnabled(_In_ bool value) { m_isEnabled = value; } + + winrt::hstring EndpointDeviceId() { return m_endpointDeviceId; } + void EndpointDeviceId (_In_ winrt::hstring const& value) { m_endpointDeviceId = value; } + + collections::IMap GroupTransformMap(); + void GroupTransformMap(_In_ collections::IMap const& value); + + private: + bool m_isEnabled{ true }; + winrt::hstring m_endpointDeviceId{}; + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBayDestinationDefinition : MidiVirtualPatchBayDestinationDefinitionT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.idl new file mode 100644 index 000000000..f1aab3352 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayDestinationDefinition.idl @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + [default_interface] + runtimeclass MidiVirtualPatchBayDestinationDefinition + { + MidiVirtualPatchBayDestinationDefinition(); + + Boolean IsEnabled; + + String EndpointDeviceId; // TODO: May want to have fuzzy match here + + // first group is incoming group. Second group is the group to transform it into in the destination + // If this map is empty, we map 1:1 + // source group must be unique (0-15), but destination group can be duplicated to allow mapping multiple + // source groups to a single destination group. The opposite is not true, however - one source group + // cannot be mapped to multiple destination groups, as that would require duplicating messages + // This group map is also how we handle MIDI 1.0 devices and mapping to the correct port/cable. + IMap GroupTransformMap; + } +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp index 02c903798..b04679f0c 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.cpp @@ -1,26 +1,15 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + #include "pch.h" #include "MidiVirtualPatchBayManager.h" #include "MidiVirtualPatchBayManager.g.cpp" -// WARNING: This file is automatically generated by a tool. Do not directly -// add this file to your project, as any changes you make will be lost. -// This file is a stub you can use as a starting point for your implementation. -// -// To add a copy of this file to your project: -// 1. Copy this file from its original location to the location where you store -// your other source files (e.g. the project root). -// 2. Add the copied file to your project. In Visual Studio, you can use -// Project -> Add Existing Item. -// 3. Delete this comment and the 'static_assert' (below) from the copied file. -// Do not modify the original file. -// -// To update an existing file in your project: -// 1. Copy the relevant changes from this file and merge them into the copy -// you made previously. -// -// This assertion helps prevent accidental modification of generated files. -static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); - namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation { bool MidiVirtualPatchBayManager::IsTransportAvailable() @@ -31,12 +20,47 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementa { throw hresult_not_implemented(); } - winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationResult MidiVirtualPatchBayManager::CreateRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationConfig const& creationConfig) + + _Use_decl_annotations_ + local::MidiVirtualPatchBayRouteCreationResult MidiVirtualPatchBayManager::CreateRoute( + local::MidiVirtualPatchBayRouteCreationConfig const& creationConfig) + { + UNREFERENCED_PARAMETER(creationConfig); + + return {}; + } + + _Use_decl_annotations_ + bool MidiVirtualPatchBayManager::RemoveRoute( + local::MidiVirtualPatchBayRouteRemovalConfig const& removalConfig) + { + UNREFERENCED_PARAMETER(removalConfig); + + return false; + } + + _Use_decl_annotations_ + local::MidiVirtualPatchBayRouteUpdateResult MidiVirtualPatchBayManager::UpdateRoute( + local::MidiVirtualPatchBayRouteUpdateConfig const& updateConfig) + { + UNREFERENCED_PARAMETER(updateConfig); + + return {}; + } + + collections::IVector MidiVirtualPatchBayManager::GetRoutes() { throw hresult_not_implemented(); } - bool MidiVirtualPatchBayManager::RemoveRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteRemovalConfig const& removalConfig) + + _Use_decl_annotations_ + local::MidiVirtualPatchBayRouteDefinition MidiVirtualPatchBayManager::GetRoute( + winrt::guid routeId) { + UNREFERENCED_PARAMETER(routeId); + throw hresult_not_implemented(); } + + } diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h index 005de985d..d2315eaae 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.h @@ -1,25 +1,14 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + #pragma once #include "MidiVirtualPatchBayManager.g.h" -// WARNING: This file is automatically generated by a tool. Do not directly -// add this file to your project, as any changes you make will be lost. -// This file is a stub you can use as a starting point for your implementation. -// -// To add a copy of this file to your project: -// 1. Copy this file from its original location to the location where you store -// your other source files (e.g. the project root). -// 2. Add the copied file to your project. In Visual Studio, you can use -// Project -> Add Existing Item. -// 3. Delete this comment and the 'static_assert' (below) from the copied file. -// Do not modify the original file. -// -// To update an existing file in your project: -// 1. Copy the relevant changes from this file and merge them into the copy -// you made previously. -// -// This assertion helps prevent accidental modification of generated files. -static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); - namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation { struct MidiVirtualPatchBayManager : MidiVirtualPatchBayManagerT @@ -28,13 +17,26 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementa static bool IsTransportAvailable(); static winrt::guid AbstractionId(); - static winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationResult CreateRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteCreationConfig const& creationConfig); - static bool RemoveRoute(winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::MidiVirtualPatchBayRouteRemovalConfig const& removalConfig); + + + static local::MidiVirtualPatchBayRouteCreationResult CreateRoute( + _In_ local::MidiVirtualPatchBayRouteCreationConfig const& creationConfig); + + static local::MidiVirtualPatchBayRouteUpdateResult UpdateRoute( + _In_ local::MidiVirtualPatchBayRouteUpdateConfig const& updateConfig); + + static bool RemoveRoute( + _In_ local::MidiVirtualPatchBayRouteRemovalConfig const& removalConfig); + + static collections::IVector GetRoutes(); + + static local::MidiVirtualPatchBayRouteDefinition GetRoute( + _In_ winrt::guid routeId); }; } namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation { - struct MidiVirtualPatchBayManager : MidiVirtualPatchBayManagerT + struct MidiVirtualPatchBayManager : MidiVirtualPatchBayManagerT { }; } diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl index 1399542a4..ff779e548 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayManager.idl @@ -8,8 +8,12 @@ import "MidiVirtualPatchBayRouteCreationResult.idl"; +import "MidiVirtualPatchBayRouteUpdateResult.idl"; + import "MidiVirtualPatchBayRouteCreationConfig.idl"; import "MidiVirtualPatchBayRouteRemovalConfig.idl"; +import "MidiVirtualPatchBayRouteUpdateConfig.idl"; + import "MidiVirtualPatchBayRouteDefinition.idl"; namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay @@ -18,18 +22,21 @@ namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay static runtimeclass MidiVirtualPatchBayManager { static Boolean IsTransportAvailable{ get; }; - static Guid AbstractionId{ get; }; + static IVector GetRoutes(); + static MidiVirtualPatchBayRouteDefinition GetRoute(Guid routeId); + + static MidiVirtualPatchBayRouteCreationResult CreateRoute( MidiVirtualPatchBayRouteCreationConfig creationConfig); + static MidiVirtualPatchBayRouteUpdateResult UpdateRoute( + MidiVirtualPatchBayRouteUpdateConfig updateConfig); + static Boolean RemoveRoute( MidiVirtualPatchBayRouteRemovalConfig removalConfig); - - static IVector GetRoutes(); - } } diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp index 616991435..babfd057e 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.cpp @@ -1,49 +1,25 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + #include "pch.h" #include "MidiVirtualPatchBayRouteCreationConfig.h" #include "MidiVirtualPatchBayRouteCreationConfig.g.cpp" -// WARNING: This file is automatically generated by a tool. Do not directly -// add this file to your project, as any changes you make will be lost. -// This file is a stub you can use as a starting point for your implementation. -// -// To add a copy of this file to your project: -// 1. Copy this file from its original location to the location where you store -// your other source files (e.g. the project root). -// 2. Add the copied file to your project. In Visual Studio, you can use -// Project -> Add Existing Item. -// 3. Delete this comment and the 'static_assert' (below) from the copied file. -// Do not modify the original file. -// -// To update an existing file in your project: -// 1. Copy the relevant changes from this file and merge them into the copy -// you made previously. -// -// This assertion helps prevent accidental modification of generated files. -static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); - namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation { - MidiVirtualPatchBayRouteCreationConfig::MidiVirtualPatchBayRouteCreationConfig(winrt::guid const& routeId) - { - throw hresult_not_implemented(); - } - winrt::guid MidiVirtualPatchBayRouteCreationConfig::RouteId() - { - throw hresult_not_implemented(); - } - void MidiVirtualPatchBayRouteCreationConfig::RouteId(winrt::guid const& value) + _Use_decl_annotations_ + MidiVirtualPatchBayRouteCreationConfig::MidiVirtualPatchBayRouteCreationConfig( + winrt::guid const& routeId) { - throw hresult_not_implemented(); - } - winrt::guid MidiVirtualPatchBayRouteCreationConfig::TransportId() - { - throw hresult_not_implemented(); + m_routeId = routeId; } - bool MidiVirtualPatchBayRouteCreationConfig::IsFromCurrentConfigFile() - { - throw hresult_not_implemented(); - } - hstring MidiVirtualPatchBayRouteCreationConfig::GetConfigJson() + + winrt::hstring MidiVirtualPatchBayRouteCreationConfig::GetConfigJson() { throw hresult_not_implemented(); } diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h index 9d5ec6d6f..291169295 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.h @@ -1,37 +1,33 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + #pragma once #include "MidiVirtualPatchBayRouteCreationConfig.g.h" -// WARNING: This file is automatically generated by a tool. Do not directly -// add this file to your project, as any changes you make will be lost. -// This file is a stub you can use as a starting point for your implementation. -// -// To add a copy of this file to your project: -// 1. Copy this file from its original location to the location where you store -// your other source files (e.g. the project root). -// 2. Add the copied file to your project. In Visual Studio, you can use -// Project -> Add Existing Item. -// 3. Delete this comment and the 'static_assert' (below) from the copied file. -// Do not modify the original file. -// -// To update an existing file in your project: -// 1. Copy the relevant changes from this file and merge them into the copy -// you made previously. -// -// This assertion helps prevent accidental modification of generated files. -static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); - namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation { struct MidiVirtualPatchBayRouteCreationConfig : MidiVirtualPatchBayRouteCreationConfigT { MidiVirtualPatchBayRouteCreationConfig() = default; + MidiVirtualPatchBayRouteCreationConfig(_In_ winrt::guid const& routeId); + + winrt::guid RouteId() { return m_routeId; } + void RouteId(_In_ winrt::guid const& value) { m_routeId = value; } + + winrt::guid TransportId() { return m_transportId; } + bool IsFromCurrentConfigFile() { return m_isFromCurrentConfigFile; } + winrt::hstring GetConfigJson(); + + private: + winrt::guid m_routeId{}; + winrt::guid m_transportId{}; + bool m_isFromCurrentConfigFile{ false }; - MidiVirtualPatchBayRouteCreationConfig(winrt::guid const& routeId); - winrt::guid RouteId(); - void RouteId(winrt::guid const& value); - winrt::guid TransportId(); - bool IsFromCurrentConfigFile(); - hstring GetConfigJson(); }; } namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl index 82485aabf..9b88b042d 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteCreationConfig.idl @@ -20,7 +20,6 @@ namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay Guid routeId ); - Guid RouteId; } diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.cpp new file mode 100644 index 000000000..de03478fe --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.cpp @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#include "pch.h" +#include "MidiVirtualPatchBayRouteDefinition.h" +#include "MidiVirtualPatchBayRouteDefinition.g.cpp" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + local::MidiVirtualPatchBayRouteDefinition MidiVirtualPatchBayRouteDefinition::CreateFromConfigJson(winrt::hstring const& jsonSection) + { + UNREFERENCED_PARAMETER(jsonSection); + + throw hresult_not_implemented(); + } + + collections::IVector MidiVirtualPatchBayRouteDefinition::Sources() + { + throw hresult_not_implemented(); + } + void MidiVirtualPatchBayRouteDefinition::Sources(collections::IVector const& value) + { + UNREFERENCED_PARAMETER(value); + + throw hresult_not_implemented(); + } + + collections::IVector MidiVirtualPatchBayRouteDefinition::Destinations() + { + throw hresult_not_implemented(); + } + + void MidiVirtualPatchBayRouteDefinition::Destinations(collections::IVector const& value) + { + UNREFERENCED_PARAMETER(value); + + throw hresult_not_implemented(); + } + + winrt::hstring MidiVirtualPatchBayRouteDefinition::GetConfigJson() + { + throw hresult_not_implemented(); + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.h new file mode 100644 index 000000000..94dda33c0 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +#pragma once +#include "MidiVirtualPatchBayRouteDefinition.g.h" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBayRouteDefinition : MidiVirtualPatchBayRouteDefinitionT + { + MidiVirtualPatchBayRouteDefinition() = default; + + static local::MidiVirtualPatchBayRouteDefinition CreateFromConfigJson(_In_ winrt::hstring const& jsonSection); + + bool IsEnabled() { return m_isEnabled; } + void IsEnabled(bool value) { m_isEnabled = value; } + + collections::IVector Sources(); + void Sources(_In_ collections::IVector const& value); + + collections::IVector Destinations(); + void Destinations(_In_ collections::IVector const& value); + + hstring GetConfigJson(); + + private: + bool m_isEnabled{ true }; + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBayRouteDefinition : MidiVirtualPatchBayRouteDefinitionT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl index 7e79ee2d7..9065f77ce 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteDefinition.idl @@ -6,16 +6,23 @@ // Further information: https://aka.ms/midi // ============================================================================ +import "MidiVirtualPatchBaySourceDefinition.idl"; +import "MidiVirtualPatchBayDestinationDefinition.idl"; namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay { - struct MidiVirtualPatchBayRouteDefinition + [default_interface] + runtimeclass MidiVirtualPatchBayRouteDefinition { - String Name; - String UniqueId; - String Description; + MidiVirtualPatchBayRouteDefinition(); Boolean IsEnabled; - }; + IVector Sources; + IVector Destinations; + + static MidiVirtualPatchBayRouteDefinition CreateFromConfigJson(String jsonSection); + + String GetConfigJson(); + } } \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp index fab354151..0519694ab 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.cpp @@ -1,49 +1,26 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + #include "pch.h" #include "MidiVirtualPatchBayRouteRemovalConfig.h" #include "MidiVirtualPatchBayRouteRemovalConfig.g.cpp" -// WARNING: This file is automatically generated by a tool. Do not directly -// add this file to your project, as any changes you make will be lost. -// This file is a stub you can use as a starting point for your implementation. -// -// To add a copy of this file to your project: -// 1. Copy this file from its original location to the location where you store -// your other source files (e.g. the project root). -// 2. Add the copied file to your project. In Visual Studio, you can use -// Project -> Add Existing Item. -// 3. Delete this comment and the 'static_assert' (below) from the copied file. -// Do not modify the original file. -// -// To update an existing file in your project: -// 1. Copy the relevant changes from this file and merge them into the copy -// you made previously. -// -// This assertion helps prevent accidental modification of generated files. -static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); - namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation { - MidiVirtualPatchBayRouteRemovalConfig::MidiVirtualPatchBayRouteRemovalConfig(winrt::guid const& routeId) - { - throw hresult_not_implemented(); - } - winrt::guid MidiVirtualPatchBayRouteRemovalConfig::RouteId() + _Use_decl_annotations_ + MidiVirtualPatchBayRouteRemovalConfig::MidiVirtualPatchBayRouteRemovalConfig( + winrt::guid const& routeId) { - throw hresult_not_implemented(); - } - void MidiVirtualPatchBayRouteRemovalConfig::RouteId(winrt::guid const& value) - { - throw hresult_not_implemented(); - } - winrt::guid MidiVirtualPatchBayRouteRemovalConfig::TransportId() - { - throw hresult_not_implemented(); - } - bool MidiVirtualPatchBayRouteRemovalConfig::IsFromCurrentConfigFile() - { - throw hresult_not_implemented(); + m_routeId = routeId; + } - hstring MidiVirtualPatchBayRouteRemovalConfig::GetConfigJson() + + winrt::hstring MidiVirtualPatchBayRouteRemovalConfig::GetConfigJson() { throw hresult_not_implemented(); } diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h index ae8420f1d..0ac579039 100644 --- a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteRemovalConfig.h @@ -1,37 +1,32 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + #pragma once #include "MidiVirtualPatchBayRouteRemovalConfig.g.h" -// WARNING: This file is automatically generated by a tool. Do not directly -// add this file to your project, as any changes you make will be lost. -// This file is a stub you can use as a starting point for your implementation. -// -// To add a copy of this file to your project: -// 1. Copy this file from its original location to the location where you store -// your other source files (e.g. the project root). -// 2. Add the copied file to your project. In Visual Studio, you can use -// Project -> Add Existing Item. -// 3. Delete this comment and the 'static_assert' (below) from the copied file. -// Do not modify the original file. -// -// To update an existing file in your project: -// 1. Copy the relevant changes from this file and merge them into the copy -// you made previously. -// -// This assertion helps prevent accidental modification of generated files. -static_assert(false, "This file is generated by a tool and will be overwritten. Open this error and view the comment for assistance."); - namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation { struct MidiVirtualPatchBayRouteRemovalConfig : MidiVirtualPatchBayRouteRemovalConfigT { MidiVirtualPatchBayRouteRemovalConfig() = default; + MidiVirtualPatchBayRouteRemovalConfig(_In_ winrt::guid const& routeId); + + winrt::guid RouteId() { return m_routeId; } + void RouteId(_In_ winrt::guid const& value) { m_routeId = value; } + + winrt::guid TransportId() { return m_transportId; } + bool IsFromCurrentConfigFile() { return m_isFromCurrentConfigFile; } + winrt::hstring GetConfigJson(); - MidiVirtualPatchBayRouteRemovalConfig(winrt::guid const& routeId); - winrt::guid RouteId(); - void RouteId(winrt::guid const& value); - winrt::guid TransportId(); - bool IsFromCurrentConfigFile(); - hstring GetConfigJson(); + private: + winrt::guid m_routeId{}; + winrt::guid m_transportId{}; + bool m_isFromCurrentConfigFile{ false }; }; } namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.cpp new file mode 100644 index 000000000..3a25b2e67 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#include "pch.h" +#include "MidiVirtualPatchBayRouteUpdateConfig.h" +#include "MidiVirtualPatchBayRouteUpdateConfig.g.cpp" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + _Use_decl_annotations_ + MidiVirtualPatchBayRouteUpdateConfig::MidiVirtualPatchBayRouteUpdateConfig( + winrt::guid const& routeId) + { + m_routeId = routeId; + + } + + winrt::hstring MidiVirtualPatchBayRouteUpdateConfig::GetConfigJson() + { + throw hresult_not_implemented(); + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.h new file mode 100644 index 000000000..b64df3707 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.h @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#pragma once +#include "MidiVirtualPatchBayRouteUpdateConfig.g.h" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBayRouteUpdateConfig : MidiVirtualPatchBayRouteUpdateConfigT + { + MidiVirtualPatchBayRouteUpdateConfig() = default; + MidiVirtualPatchBayRouteUpdateConfig(_In_ winrt::guid const& routeId); + + winrt::guid RouteId() { return m_routeId; } + void RouteId(_In_ winrt::guid const& value) { m_routeId = value; } + + winrt::guid TransportId() { return m_transportId; } + bool IsFromCurrentConfigFile() { return m_isFromCurrentConfigFile; } + winrt::hstring GetConfigJson(); + + private: + winrt::guid m_routeId{}; + winrt::guid m_transportId{}; + bool m_isFromCurrentConfigFile{ false }; + + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBayRouteUpdateConfig : MidiVirtualPatchBayRouteUpdateConfigT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.idl new file mode 100644 index 000000000..e0aea16d9 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateConfig.idl @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +import "MidiVirtualPatchBayRouteDefinition.idl"; + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + [default_interface] + runtimeclass MidiVirtualPatchBayRouteUpdateConfig : Microsoft.Windows.Devices.Midi2.ServiceConfig.IMidiServiceTransportPluginConfig + { + MidiVirtualPatchBayRouteUpdateConfig(); + + MidiVirtualPatchBayRouteUpdateConfig( + Guid routeId + ); + + Guid RouteId; + } +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateResult.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateResult.idl new file mode 100644 index 000000000..15425e004 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBayRouteUpdateResult.idl @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + struct MidiVirtualPatchBayRouteUpdateResult + { + Boolean Success; + + Guid RouteId; + + + }; +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.cpp b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.cpp new file mode 100644 index 000000000..c84ca2c98 --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#include "pch.h" +#include "MidiVirtualPatchBaySourceDefinition.h" +#include "MidiVirtualPatchBaySourceDefinition.g.cpp" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + + collections::IVector MidiVirtualPatchBaySourceDefinition::IncludedMessageTypes() + { + throw hresult_not_implemented(); + } + + _Use_decl_annotations_ + void MidiVirtualPatchBaySourceDefinition::IncludedMessageTypes( + collections::IVector const& value) + { + UNREFERENCED_PARAMETER(value); + + } + + collections::IVector MidiVirtualPatchBaySourceDefinition::IncludedGroups() + { + throw hresult_not_implemented(); + } + + _Use_decl_annotations_ + void MidiVirtualPatchBaySourceDefinition::IncludedGroups( + collections::IVector const& value) + { + UNREFERENCED_PARAMETER(value); + + } +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.h b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.h new file mode 100644 index 000000000..772668d1a --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#pragma once +#include "MidiVirtualPatchBaySourceDefinition.g.h" + +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation +{ + struct MidiVirtualPatchBaySourceDefinition : MidiVirtualPatchBaySourceDefinitionT + { + MidiVirtualPatchBaySourceDefinition() = default; + + bool IsEnabled() { return m_isEnabled; } + void IsEnabled(_In_ bool value) { m_isEnabled = value; } + + winrt::hstring EndpointDeviceId() { return m_endpointDeviceId; } + void EndpointDeviceId(_In_ winrt::hstring const& value) { m_endpointDeviceId = value; } + + + collections::IVector IncludedMessageTypes(); + void IncludedMessageTypes(_In_ collections::IVector const& value); + + collections::IVector IncludedGroups(); + void IncludedGroups(_In_ collections::IVector const& value); + + private: + bool m_isEnabled{ true }; + winrt::hstring m_endpointDeviceId{}; + }; +} +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::factory_implementation +{ + struct MidiVirtualPatchBaySourceDefinition : MidiVirtualPatchBaySourceDefinitionT + { + }; +} diff --git a/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.idl b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.idl new file mode 100644 index 000000000..745b5aabb --- /dev/null +++ b/src/app-sdk/winrt-virtual-patchbay/MidiVirtualPatchBaySourceDefinition.idl @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +namespace Microsoft.Windows.Devices.Midi2.VirtualPatchBay +{ + [default_interface] + runtimeclass MidiVirtualPatchBaySourceDefinition + { + MidiVirtualPatchBaySourceDefinition(); + + Boolean IsEnabled; + + String EndpointDeviceId; // TODO: May want to have fuzzy match here + + // message types to include. If empty, all types are included. + IVector IncludedMessageTypes; + + // only for messages with groups. If this is empty, all groups are included. + IVector IncludedGroups; + } +} \ No newline at end of file diff --git a/src/app-sdk/winrt-virtual-patchbay/pch.h b/src/app-sdk/winrt-virtual-patchbay/pch.h index 53689ec8f..02a6186b4 100644 --- a/src/app-sdk/winrt-virtual-patchbay/pch.h +++ b/src/app-sdk/winrt-virtual-patchbay/pch.h @@ -97,14 +97,18 @@ namespace svc = ::winrt::Microsoft::Windows::Devices::Midi2::ServiceConfig; // Project-local ------------------------------------------------ -namespace winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback {}; -namespace winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback::implementation {}; -namespace loop = ::winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback; -namespace implementation = ::winrt::Microsoft::Windows::Devices::Midi2::Endpoints::Loopback::implementation; +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay {}; +namespace winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation {}; +namespace local = ::winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay; +namespace implementation = ::winrt::Microsoft::Windows::Devices::Midi2::VirtualPatchBay::implementation; //#include "resource.h" +#include "MidiVirtualPatchBaySourceDefinition.h" +#include "MidiVirtualPatchBayDestinationDefinition.h" + #include "MidiVirtualPatchBayRouteCreationConfig.h" #include "MidiVirtualPatchBayRouteRemovalConfig.h" +#include "MidiVirtualPatchBayRouteUpdateConfig.h" #include "MidiVirtualPatchBayManager.h" diff --git a/src/user-tools/midi-console/Midi/Midi.csproj b/src/user-tools/midi-console/Midi/Midi.csproj index 3b99ebc71..a3be80c10 100644 --- a/src/user-tools/midi-console/Midi/Midi.csproj +++ b/src/user-tools/midi-console/Midi/Midi.csproj @@ -35,7 +35,7 @@ - + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Config/EndpointConfigMetadataPayload.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Config/EndpointConfigMetadataPayload.cs index 027fe001c..93c7314d6 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Config/EndpointConfigMetadataPayload.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Config/EndpointConfigMetadataPayload.cs @@ -5,14 +5,14 @@ using System.Threading.Tasks; using Windows.Data.Json; +using Microsoft.Windows.Devices.Midi2.ServiceConfig; namespace Microsoft.Midi.Settings.Config { - internal class EndpointConfigMetadataPayload : IMidiServiceTransportPluginConfiguration + internal class EndpointConfigMetadataPayload : IMidiServiceTransportPluginConfig { - public bool IsFromConfigurationFile => true; + public bool IsFromCurrentConfigFile => true; - public JsonObject? SettingsJson { get; private set; } public Guid TransportId { get; private set; } @@ -51,9 +51,20 @@ public EndpointConfigMetadataPayload(Guid transportId, string newName, string ne // } // } - public void BuildJson() + + public string GetConfigJson() { + // TODO + + + + + + + + return string.Empty; } + } } diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiEndpointNativeDataFormatConverter.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiEndpointNativeDataFormatConverter.cs index f366dd212..c2c880d3d 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiEndpointNativeDataFormatConverter.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiEndpointNativeDataFormatConverter.cs @@ -24,11 +24,11 @@ public object Convert(object value, Type targetType, object parameter, string la switch (val) { - case MidiEndpointNativeDataFormat.UniversalMidiPacket: + case MidiEndpointNativeDataFormat.UniversalMidiPacketFormat: return "MIDI 2.0 Universal MIDI Packet (UMP) format"; - case MidiEndpointNativeDataFormat.ByteStream: - return "MIDI 1.0 byte stream format"; + case MidiEndpointNativeDataFormat.Midi1ByteFormat: + return "MIDI 1.0 byte format"; default: diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiFunctionBlockMidi10Converter.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiFunctionBlockMidi10Converter.cs index 7840bd561..dafff9d68 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiFunctionBlockMidi10Converter.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiFunctionBlockMidi10Converter.cs @@ -16,21 +16,21 @@ public object Convert(object value, Type targetType, object parameter, string la return string.Empty; } - if (value is MidiFunctionBlockMidi10) + if (value is MidiFunctionBlockRepresentsMidi10Connection) { - var val = (MidiFunctionBlockMidi10)value; + var val = (MidiFunctionBlockRepresentsMidi10Connection)value; // TODO: Localize switch (val) { - case MidiFunctionBlockMidi10.Not10: + case MidiFunctionBlockRepresentsMidi10Connection.Not10: return "Not MIDI 1.0"; - case MidiFunctionBlockMidi10.YesBandwidthUnrestricted: + case MidiFunctionBlockRepresentsMidi10Connection.YesBandwidthUnrestricted: return "MIDI 1.0 unrestricted bandwidth"; - case MidiFunctionBlockMidi10.YesBandwidthRestricted: + case MidiFunctionBlockRepresentsMidi10Connection.YesBandwidthRestricted: return "MIDI 1.0 restricted bandwidth"; default: diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiGroupIndexConverter.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiGroupIndexConverter.cs index 9a15c9a81..7fcf0799e 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiGroupIndexConverter.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/MidiGroupIndexConverter.cs @@ -21,7 +21,7 @@ public object Convert(object value, Type targetType, object parameter, string la var val = (byte)value; // todo: localize - return $"{MidiGroup.LabelFull} {(val + 1)} (Index {val})"; + return $"{MidiGroup.LongLabel} {(val + 1)} (Index {val})"; } else { diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Microsoft.Midi.Settings.csproj b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Microsoft.Midi.Settings.csproj index e5e612086..4b77f5702 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Microsoft.Midi.Settings.csproj +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Microsoft.Midi.Settings.csproj @@ -15,7 +15,7 @@ true true - + true Properties\PublishProfiles\win10-$(Platform).pubxml @@ -63,6 +63,7 @@ + @@ -82,7 +83,7 @@ - + @@ -127,6 +128,9 @@ Never + + MSBuild:Compile + MSBuild:Compile diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs index 40147639f..6e3b1af9c 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs @@ -15,6 +15,7 @@ public PageService() { Configure(); Configure(); + Configure(); Configure(); //Configure(); diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw index 09c39d3d1..9ad19a74f 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw @@ -297,4 +297,7 @@ Home + + Routing + \ No newline at end of file diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DeviceDetailViewModel.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DeviceDetailViewModel.cs index 4105502b0..4497222f6 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DeviceDetailViewModel.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DeviceDetailViewModel.cs @@ -17,15 +17,23 @@ public class DeviceDetailViewModel : ObservableRecipient, INavigationAware { public EndpointUserMetadata UserMetadata { get; private set; } = new EndpointUserMetadata(); - public MidiEndpointDeviceInformation? DeviceInformation + public MidiEndpointDeviceInformation DeviceInformation { get; private set; } + public IReadOnlyList FunctionBlocks => DeviceInformation.GetDeclaredFunctionBlocks(); - public DeviceInformation? ParentDeviceInformation - { - get; private set; - } + public MidiEndpointTransportSuppliedInfo TransportSuppliedInfo => DeviceInformation.GetTransportSuppliedInfo(); + + public MidiEndpointUserSuppliedInfo UserSuppliedInfo => DeviceInformation.GetUserSuppliedInfo(); + + public MidiDeclaredDeviceIdentity DeviceIdentity => DeviceInformation.GetDeclaredDeviceIdentity(); + + public MidiDeclaredStreamConfiguration StreamConfiguration => DeviceInformation.GetDeclaredStreamConfiguration(); + + public MidiDeclaredEndpointInfo EndpointInfo => DeviceInformation.GetDeclaredEndpointInfo(); + + public DeviceInformation ParentDeviceInformation => DeviceInformation.GetParentDeviceInformation(); public void OnNavigatedFrom() @@ -36,8 +44,6 @@ public void OnNavigatedFrom() public void OnNavigatedTo(object parameter) { DeviceInformation = (MidiEndpointDeviceInformation)parameter; - - ParentDeviceInformation = DeviceInformation.GetParentDeviceInformation(); } } } diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DevicesViewModel.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DevicesViewModel.cs index a0118507d..b974f11af 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DevicesViewModel.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/DevicesViewModel.cs @@ -103,7 +103,7 @@ public void RefreshDeviceCollection(bool showDiagnosticsEndpoints = false) { // TODO: this is a hack. Probably shouldn't be using the mnemonic directly // Instead, need a transport properly for purpose like we have with endpoints - if (item.Transport.Abbreviation == "DIAG") + if (item.Transport.TransportCode == "DIAG") { if (showDiagnosticsEndpoints) { diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/ManagementSessionsViewModel.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/ManagementSessionsViewModel.cs index 85f8d4f3b..01be37bb4 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/ManagementSessionsViewModel.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/ManagementSessionsViewModel.cs @@ -6,6 +6,9 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.Windows.Devices.Midi2.Diagnostics; + + namespace Microsoft.Midi.Settings.ViewModels { public class ManagementSessionsViewModel : ObservableRecipient @@ -23,7 +26,7 @@ public void RefreshSessions() { Sessions.Clear(); - var sessions = MidiService.GetActiveSessions(); + var sessions = MidiReporting.GetActiveSessions(); foreach (var session in sessions) { diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/PluginsTransportViewModel.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/PluginsTransportViewModel.cs index 40975d12c..79dea7a89 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/PluginsTransportViewModel.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/PluginsTransportViewModel.cs @@ -17,7 +17,7 @@ public PluginsTransportViewModel() { Plugins.Clear(); - var plugins = MidiService.GetInstalledTransportPlugins(); + var plugins = MidiReporting.GetInstalledTransportPlugins(); foreach (var plugin in plugins.OrderBy(x => x.Name)) { diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/RoutesViewModel.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/RoutesViewModel.cs new file mode 100644 index 000000000..b48c0ecb6 --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/ViewModels/RoutesViewModel.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.Midi.Settings.Contracts.ViewModels; +using Microsoft.Midi.Settings.Models; +using Microsoft.Midi.Settings.ViewModels.Data; +using Microsoft.UI.Dispatching; +using Windows.Devices.Enumeration; + +namespace Microsoft.Midi.Settings.ViewModels +{ + public class RoutesViewModel : ObservableRecipient, INavigationAware + { + + + public void OnNavigatedFrom() + { + throw new NotImplementedException(); + } + + public void OnNavigatedTo(object parameter) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml index 1c937b7b3..f44e37462 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml @@ -4,7 +4,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Microsoft.Midi.Settings.Views" - xmlns:midi2="using:Windows.Devices.Midi2" + xmlns:midi2="using:Microsoft.Windows.Devices.Midi2" xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters" xmlns:helpers="using:Microsoft.Midi.Settings.Helpers" @@ -60,23 +60,23 @@ - - - - - @@ -108,10 +108,10 @@ - - - - + + + + @@ -142,20 +142,20 @@ - + - + - + - + - + @@ -184,19 +184,19 @@ - + - + - + - + - + @@ -211,7 +211,7 @@ @@ -308,7 +308,7 @@ Text="MIDI 1.0" Style="{StaticResource SmallPropertyLabel}" /> - - - diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml.cs index 2ed74aad2..663ae900d 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DeviceDetailPage.xaml.cs @@ -53,10 +53,17 @@ public DeviceDetailPage() private async void Button_Click(object sender, RoutedEventArgs e) { - ViewModel.UserMetadata.Name = ViewModel.DeviceInformation!.UserSuppliedName; - ViewModel.UserMetadata.Description = ViewModel.DeviceInformation.UserSuppliedDescription; - ViewModel.UserMetadata.LargeImagePath = ViewModel.DeviceInformation.UserSuppliedLargeImagePath; - ViewModel.UserMetadata.SmallImagePath = ViewModel.DeviceInformation.UserSuppliedSmallImagePath; + if (ViewModel.DeviceInformation == null) + { + return; + } + + var userSuppliedInfo = ViewModel.DeviceInformation.GetUserSuppliedInfo(); + + ViewModel.UserMetadata.Name = userSuppliedInfo.Name; + ViewModel.UserMetadata.Description = userSuppliedInfo.Description; + ViewModel.UserMetadata.LargeImagePath = userSuppliedInfo.LargeImagePath; + ViewModel.UserMetadata.SmallImagePath = userSuppliedInfo.SmallImagePath; editUserDefinedPropertiesDialog.Width = this.Width / 3; diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DevicesPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DevicesPage.xaml index ae5d6c84d..d3f6d5210 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DevicesPage.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/DevicesPage.xaml @@ -8,7 +8,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views="using:Microsoft.Midi.Settings.Views" xmlns:local="using:Microsoft.Midi.Settings.ViewModels" - xmlns:midi2="using:Windows.Devices.Midi2" + xmlns:midi2="using:Microsoft.Windows.Devices.Midi2" xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:helpers="using:Microsoft.Midi.Settings.Helpers" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" @@ -55,8 +55,8 @@ - - + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ManagementSessionsPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ManagementSessionsPage.xaml index a3c517faf..ac1f597d0 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ManagementSessionsPage.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ManagementSessionsPage.xaml @@ -7,7 +7,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views="using:Microsoft.Midi.Settings.Views" xmlns:local="using:Microsoft.Midi.Settings.ViewModels" - xmlns:midi2="using:Windows.Devices.Midi2" + xmlns:midi2="using:Microsoft.Windows.Devices.Midi2" + xmlns:mididiag="using:Microsoft.Windows.Devices.Midi2.Diagnostics" xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:helpers="using:Microsoft.Midi.Settings.Helpers" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" @@ -44,7 +45,7 @@ - + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/PluginsTransportPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/PluginsTransportPage.xaml index 10a76c883..4660f5ff7 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/PluginsTransportPage.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/PluginsTransportPage.xaml @@ -7,7 +7,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views="using:Microsoft.Midi.Settings.Views" xmlns:local="using:Microsoft.Midi.Settings.ViewModels" - xmlns:midi2="using:Windows.Devices.Midi2" + xmlns:midi2="using:Microsoft.Windows.Devices.Midi2" + xmlns:mididiag="using:Microsoft.Windows.Devices.Midi2.Diagnostics" xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:helpers="using:Microsoft.Midi.Settings.Helpers" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" @@ -35,7 +36,7 @@ - + @@ -78,7 +79,7 @@ - + @@ -103,7 +104,7 @@ - + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml new file mode 100644 index 000000000..adaa4a640 --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml.cs new file mode 100644 index 000000000..347e1e315 --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/RoutesPage.xaml.cs @@ -0,0 +1,31 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Microsoft.Midi.Settings.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class RoutesPage : Page + { + public RoutesPage() + { + this.InitializeComponent(); + } + } +} diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ShellPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ShellPage.xaml index 14afda169..82d0e1562 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ShellPage.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Views/ShellPage.xaml @@ -96,8 +96,7 @@ - + @@ -106,9 +105,14 @@ - - - + + + + + + + +