From a1340889fb4546b8ea4cbf666efc627d35b1a6c1 Mon Sep 17 00:00:00 2001
From: tobias <tobias.ullerich@icloud.com>
Date: Thu, 6 Oct 2016 15:27:32 +0200
Subject: [PATCH] Add NativeAudioMac project to branch

---
 .../src/de/tobias/playpad/audio/Peakable.java |  16 +++
 PlayWallNative/.classpath                     |   9 ++
 PlayWallNative/.gitignore                     |   1 +
 PlayWallNative/.project                       |  17 +++
 .../.settings/org.eclipse.jdt.core.prefs      |  11 ++
 PlayWallNative/libNativeAudio.dylib           | Bin 0 -> 55808 bytes
 .../src/de/tobias/playpad/NativeAudio.java    |  58 ++++++++
 .../tobias/playpad/NativeAudioMacHandler.java | 135 ++++++++++++++++++
 .../playpad/NativeAudioMacHandlerConnect.java |  78 ++++++++++
 .../src/de/tobias/playpad/Waveform.java       |   7 +
 .../de/tobias/playpad/view/WaveformView.java  |  39 +++++
 .../src/de_tobias_playpad_NativeAudio.h       |  85 +++++++++++
 .../src/de_tobias_playpad_Waveform.h          |  29 ++++
 .../de/tobias/playpad/NativeAudioTest.java    |  20 +++
 .../test/de/tobias/playpad/WaveformTest.java  |  38 +++++
 15 files changed, 543 insertions(+)
 create mode 100644 PlayWallCore/src/de/tobias/playpad/audio/Peakable.java
 create mode 100644 PlayWallNative/.classpath
 create mode 100644 PlayWallNative/.gitignore
 create mode 100644 PlayWallNative/.project
 create mode 100644 PlayWallNative/.settings/org.eclipse.jdt.core.prefs
 create mode 100644 PlayWallNative/libNativeAudio.dylib
 create mode 100644 PlayWallNative/src/de/tobias/playpad/NativeAudio.java
 create mode 100644 PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java
 create mode 100644 PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java
 create mode 100644 PlayWallNative/src/de/tobias/playpad/Waveform.java
 create mode 100644 PlayWallNative/src/de/tobias/playpad/view/WaveformView.java
 create mode 100644 PlayWallNative/src/de_tobias_playpad_NativeAudio.h
 create mode 100644 PlayWallNative/src/de_tobias_playpad_Waveform.h
 create mode 100644 PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java
 create mode 100644 PlayWallNative/test/de/tobias/playpad/WaveformTest.java

diff --git a/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java b/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java
new file mode 100644
index 00000000..29f41ebc
--- /dev/null
+++ b/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java
@@ -0,0 +1,16 @@
+package de.tobias.playpad.audio;
+
+import javafx.beans.property.DoubleProperty;
+
+public interface Peakable {
+
+	public enum Channel {
+
+		LEFT,
+		RIGHT;
+	}
+	
+	public DoubleProperty audioLevelProperty(Channel channel);
+	
+	public double getAudioLevel(Channel channel);
+}
diff --git a/PlayWallNative/.classpath b/PlayWallNative/.classpath
new file mode 100644
index 00000000..7d032884
--- /dev/null
+++ b/PlayWallNative/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="test"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/PlayWallCore"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/libUtils"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/PlayWallNative/.gitignore b/PlayWallNative/.gitignore
new file mode 100644
index 00000000..ae3c1726
--- /dev/null
+++ b/PlayWallNative/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/PlayWallNative/.project b/PlayWallNative/.project
new file mode 100644
index 00000000..68507fdf
--- /dev/null
+++ b/PlayWallNative/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>PlayWallNative</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/PlayWallNative/.settings/org.eclipse.jdt.core.prefs b/PlayWallNative/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..3a215370
--- /dev/null
+++ b/PlayWallNative/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/PlayWallNative/libNativeAudio.dylib b/PlayWallNative/libNativeAudio.dylib
new file mode 100644
index 0000000000000000000000000000000000000000..14afa4716652379483939e006f1d32ba3adde6bb
GIT binary patch
literal 55808
zcmX^A>+L^w1_nlE1_lN;1_lOE1_p);JPZu23<3-wAj!bMkipEr5Fa1n8W92#LBj#q
z`Roh~46F<c3|vs@`1q34iV`S?0n@w#(h#}Bst_8)XMr#wBnv|WgaIMr<BLm5lZqi6
zEatU1LZrGN6a$FQ2xWsP4ybt`KZE!X^Wrm7a|%+6u$U*{1X9Jo@C`ySfcQ*MHkg8%
z2WEryrza=Jr&c7V7L>%7BqpJUABQtUWe(I35Fg5fNT8AN@yW#{MVWc&P;qqgN?ail
zxlm8S_z+PB26VII<MWfUlH+qzOEU5jb5k+m_n{j^XCx>R85kH~e26Gc^OAECi;F=9
zqPx$^2ck0^LNUPjP%b|Al~fjBx^E)Xyb!3zV0_%>CFkcABN8CG`#$(VbZS5-1`r=5
z{XxZHRD67CUU_C-N_=KsT0S_wQS*m{KSbpV2*m*6L!Am0L8U<X%!3t_FI*f$plKJZ
z0+zoNz&r*9G(ISwf$}aSw}SNN<-`|P<|gIm#21tlF~rAXHxH&BWFAOA)O2teAP(bz
z{gs}N2sM!TsOAYk-2)3Z5Fgz<kl$cN#>eL*;&Yz`)Vv)~4In<Uc_9DFLFGVHd^~!*
zqPp(`)Vv8G#S9D#AU^(hO-@73Xz1bB5C}2o0EA)y@sZsJ6^2vLd<M=JIhn;J=;k>D
zL6pLx7sN+14<1z@l~D5vit<bHv6+_uH4ml<#78p^WDFcb&CAS9Oiu+RWpwuyK+WTT
z>HzWarDLdh@JK;7uL5e`4Ni!GAU+Z9D^ATRN=+-qOn(6}5OXr1<sOKSY#u8Ev?7Bj
zV}Q92R8E0RM0ekgSct+12*m*6Bb&#7-Mr$`g47~x<_W|>41$Fph);xhnPrKfS_sp>
z5>WGC`3=NJGY?`Rl!W>>C9xzCEQ0P|2dH@t(C`EC@tX%X3afby@nB(w4G@X}#K&)5
zQZb?y$Mmm30>mH#2n8mQ&4W4{EDj<-WsL{8-171C^LBOdgtb`;K(Y)B4Cr(gL>yGE
zAe+U@z`)?Zz`!8Ez`y_z2a${n`lZE1`Z@W@i8=Z?nMok*mspZnmg-oVl9{iUQkj#P
z1U68KfuRBH<^l$W84L^zGYS|O43IL;i6RCD4JHPL4<!r?7Z@S+DabB~at4MKj0_Ap
zlNcBh6c`w|84yK&J|hDI2#YW<Ff=nVFhHA1VEfRC850>8Owk1y7#Kj!ERa3EmG2+k
zJ8JNF$Ilq$MdzRXP=O_EZY~A}ZY~Bb7$0f|52zgo4G)MnKqMoBesE=RNouaXPi9h4
zVo{~OTTx<eYI%N9cCo%=m|K2nUP@v~W`3St8cbY2EVZaOGe56b-w{Oxl0Bd(2e}bs
z0|Ub=76t|#Mm+Z5x5Zf>A<w|T0P=?gia(x!V;B;zkQfEEjPx9lA`_|)6rXT+F;-yc
zOV-xbGlXhGw}+AI6bmRNA=?89Iz1<-7H|lF^r8A6R9oQ>=j7znoYbPkl2ja_43~%c
zBLl_%Zy3Suf;a|iJc5#TNPd1!Qho&v8<13heE|t)6nhv!@i+}%dU4J#N=3vKcAHSu
zFfcHvLDT7hG6n`vnXL)sgYpr`DY8)hg-r|$2I?S@Q9K#~qaiRF0;3@?8UmvsFd71*
zAut*OqaiRF0;3@?8UjNv1VTMJpL#UE3GnC@U8>2z;L*#w97J{2{_yB5{ov7E`@^HV
z^ur5Lc95Lt1dv=W?^F=g>G}dL{f!MQ-2xKt<?RPiovshy($~S#r58LpU2lK{U#NkM
z>*g(YWMJ^<4!z*fUHZbO+x3A@w=YQkgHN~U7kdT<kIvc?9-ZesI!h1ubYAo5_C4U!
z9eTp2Q$(fHb<YbSRR#u+<|6^Ihtty1^!Vjlz=03-kAnx)2c4mBJi2Z9z!sS<2N~MU
znqdqw+x5i%3m%=vU%XHO^B#C~oA!g`JCA#GgXCU<%riXDdCa5N_kl;}`4>k)3Y(8O
z#2z+0*?G>RxAsBjMUam=eXqP&36krsz42n13IhXS_tZInJZ>ruvag%<h7s5WQ1?WD
zi~@(ADLY6Wr+Z963URnc5+nz5j~G$zc?Ytn+qB&d<SbSX6!)A^2D=UvKJ_4ZobFi)
zQi#Jnogg`od)kz-hfl`|q!{aPeeKb08)?tL&<%<{)AzOv3_jhg8w?p3d^%lEI6@*$
zA7o~y>jRfA-`B1!Cms2x9`xuoeQe9X;K;x2q6bcQ{#61e9IWy95F`h3=RG9`27Y-5
z2JGo+A1ENYO~Y-$;U!@R4k2j#%>WqziNAP|Jj@-R_yt`LU?i#nB?g91`~t2AJaB}Z
zKgc+ci+q$A7}6$SaSzDg2OizFns%`8+HV7P7ia+4qto>OB)Awr26ejL0NDnL%u^sm
zV8<Q!e*xKDH$aK~h9X)Z-2f-{3!T1aUhDzMb=O{au~QKonOM?$0#a;xbozpv*JTTH
zo&w0`Zr+Fb3=IE4@$@1UWFWL`@aQgmV0h_;3o|%OH-H`H(e1jyqto?*N4KpHC`h|a
zMIlDa(+8<K1Tw{S1ypJ6iWi~~^LBvB8jyLQGUkO7GXn!m$qkS0&>bG#rq`^&0Tm8%
z$%PKr<zRVep5M_Gy1d~LqetiYj?iT<PAD)iKqbK8vqOP_p(}J5|F%OO%|{Yq4}(MJ
zM5phOmtqVI4A25%2VC?;2b%s01(40PCtj2)fWnYK`Q-=puIY0tkS5j@dLUne$|z9z
zr2#StlHT}1-T_DH3DhVBmtU+Pg*Z~#OL>sVwKrZolLtA6P<gr!WKp+iIK({?DDIg7
zG793Jc91;GJ)mTYCH>12O8+3^!08|4GHmJJquW*w;-2G{AYZU{=pu&?2gm@3d;Wvu
z@w?}N90B+2mjl^Rd*j6(IR=IaF!vb1(z{1z=nF`K_x<6~E$GobsRNXfyTNto3y*Hs
z2OgcZpcLc*s_QyKFL-pG^5{J1(d~NS{{@fcBL?8=3?uv%;O2Li{_yCw^XT4x15~MY
zyMFNKtbO6p`Q4-Qm`Atk3$P&yv4_#>Lsa*5hyL*BHuC7+23j%T(Ovriq|>9b_JK#|
zb&u}Q2OgcJH#|D8d2}A~=ytsUHqroOqzePAJj7vM04q3fh%;{j2!PA8#y1L#paz8N
z3%ECryMk9ffJ*VsYcITH85lf{yFLI_$;VyqfT-r$I}H4-<_sWxr4Jw;IQ}A8mVu$u
z^$u9F1+*5)qnGuj4g-Tna_Jq9&f^;xUYwVK76XRgc7P^9I}dsE`fdOfd7`om498v9
zfCRz%TV)s+81|LqrlooGhOY7Gb=~064GN-zFTTrwZ9z7n0c65u83qQ3R?sXVNNe&g
zkZ~Tpt_|J3XF7Xp{{R0EDt|YCGDE|0*N)uef}G>7J)p_#Zm?|Ud5?q7nL2-V`c63R
zIt4Um*zG%of4%R7PTv_&6~1$hyDk9D_rsi11#ynY@z#R>|Nnym=Xh(*|Ns9%bH)(o
zD1m&ETa>2k(K{6+<IxLN3Nt_*Za@Om0FUFX5l|+?1Upa!bwhM@wg&wF|KFn<Om+Lt
z=se}Yzy6R%XR8ND_;{-WRHsKbM5GgJmPhwqkdZG|NP}``E665@(f7b{xK#zDxp%6@
z|NsAww}MEp=UwM?wi<wBx_d#Ucb@2MHGyzJws<i2g3R&g?6rUhf*b}?12(L?_Q8t?
zX>e3E?*)l4@VA1NBfZRFU|{HO1&M%i-c*n#56x2^onRJ3f`7g1jLrj{2R)d3!4`Fb
zDKxq6sUSB&w1Qd9dqHNwtO464@&EsSaJAxbycNU-MGwT^z6=ZujypiU^yp@-F$3kC
zsbJr9_kse-quVsx6ckj)U#Lq#Xj>57-3v0tqZ4czDAkEdF)+LY&HH(D?*-|9VFgmw
zT>F55zl9$ZwxDpZlVV`#Z2j{O6mNS$2E2GB39`}jw+V={4bcEuvG)T=0jPv*1+hR4
zhgJb_$b$8FbemoQD~HJ*e8J?=*~$S{VS5nd+HTWbC@Q+ALiG1S6qzmo$)Z}o0M^d?
zNFC&Y<Nq(Z8Xj=zJm}H87c9|v&ZD#S1=v}=5B~lC|H2OB?p~;Swt|JU!9uk!Jh~x#
zX%N2~s_VE%;}KBt68rL&1ibtT@aT2D0WWM|W%hB`8=&a%=sfPzdF;hi2~ZQL_5}lf
zD`*zbqnC9(IFLZ4NT&p-thfS-yqBjzVGIuLRzVQ6mvuQ@U7`d7!!8a6Mh1^w*ApJy
zzArqwIX${P4LrI*h4!)k7du^#G}j*a$KMKC?`3!ZTpFDK^@lvV%{;ox6d(#qcX)K3
z^XT^7@&97;4+j1gsC(k!_WTq_xW}3STEc+}Z*bjG3hGAv4-kOZ1e*Q_mzUiP9^DQa
zARGQ)=yct3-1Q2`_mEaj?Tr^##Tgj7U9U91VC;0=z~2s9NdQU6;7%8)@SXsz{~F(b
zmTRB{XLs!nutA-r3qUnVcj$r_g+KrQ_W)PKwr!vuShuM^sH4#>dIQvx>kOR%sc&Y0
zQr+<vf#RU#0O>D6!Xxy-i@Kk%%+y_b!=u|Y4rD;DXgMh9^zu#sQQfSastgPuGh8P?
zoZDSH;RQ3uG>{%}E0Z-3tmL@s36O_D{X?*OLP16fgN*EEbpfmJ=ydIX8Pf4$pBUIl
zJ3N|ecQEj`n1G8!+go4_;O69gP)DGfl>?@?0j9U%MH58t29IvjgJ4y*k3e0t&b<|&
z)DO-OAQs5o;6fIv6U^>B*y(%1qq}y)3p0=@-KOmj6Ba;B$bg#wVu4Kn6$3C6Kx~gr
z*A<|~aChm67q38R6jCI^lz@wyPS*oqCB7$ox?NWoUh?QX_Tn8ZDS_h>T2Jm3Wng#-
zs(8VzTTqYSC1`~of)|Ep0dIhdzGwq!1Eo!<Svx$sT@Qe}_uzWuMVcrBgW;vlYml6I
z{6&~3s9*xic{CmYC9v4TaIKx^UzmZ^L%Qdn_S6eCu=?5yFO)?=4Kw8Q+5AQTlsG#}
zzkqz`(arAB-LQg{fuXzf3%GG30BYQzj32<;H=UtxI(=XGfRin(<+Xwh)E#yG&>i{)
zoTFiFy6--n$2>a^fU+IfScBNZc-n`ckrmTkPzR=)_Zqlw=6mD+MUU>#7arZ94wGpm
zNDh=Tz)i5u<KWieOHmO}10B7;0Cz8<{RuW-7i2~^Zy7f8J@w)B4~8x4g+bk4r1qXm
z#{p0ff(M15#bt-<eMoSc9tU**x_Jd4wp>8*#bZ4N1{eN)uJ=JrIY=uP<`pktczF!(
zFCyIU`@rMiLne<-@Q~1r7lp#0Cg8#U;KUB<3W6{wtUyiG;~t%$GVYp3cj$>1n!<2@
zb%Pq=;PIsg9>-mOKy!Nl$hn=h;KbMMd%&X;Uc7pAx^8%}QwWsJ4|;U^{s8r__6RXB
zfU6|XK+q3xf^}W-Vh2c3x9bW>?+>HB?f|XWp`%bpzWM=);ZkG=?FV;Qkh%q+p)yc;
zf8m7=$evEPWAw2&=EMtakfLta6Ob{4G%Wq`0GEyfKE1y1K^B;Uz;WpN10Fcwf`-=|
z96-JoJi1MFbU|Y-=U=Q61U0llA#%v0GxP_js0NM9T?36TyjTsA1m$LM<zxveV7fu0
zgP_nC{RH+Liy*k~1C9{U=TISsuG0G+-L5}8x_R&DGB7xFm~eo(oyT9e3Br5PKRh~J
zcf4?i*s%jT<cHS3LF*sc_UbY)G}zcN@V9^#BZCd?=FI?E+s(oOid8X?alN&mjswX2
z2Oiz5jv#69sHUl%4g<rB?E;|s|A+#pM~0f;u+?{<E|n=8$cSzcBahC|2Oi*Fmg#R$
z?*k%q<C6!!)**fk-tDps44?VyLSLluCtXbA*WleI%fOJvA9FE{zvj{>{<uS+?!g6c
zLOJ+|$)of7i(-&lI$ckA^wzEb)!l|CLEXmM22h6$)KQxXsysY8!PUhJ6R_grFZe)o
zw`eA)$J!a%aoiQOi22ZQ*D2t9&@1`@6j7jhw^vjZ+(`~y0P37v0ND=e>-_NO7WDyZ
zZUxsYmmt*$sJL?lmEI>nk?+wP+Tqc?7u56c=-vua_hKDCsN`nl1ZnNw3ljQ&0a{YL
z)dEXB1NG-R!F>RblxZ7C7*q(sg+igNCDX-P@Z5}|ptixIdn?q}p!(~D8rW7ySECcu
z=mS?7FQ4*ZD=(qr!;nGl&e|9J8mvk(;7IZPkj9^MB8^{zRZ#{UDJRnSYfgURkM!60
z#2<AKGA8YM;Kgk|P$>Z#<aRyr$%9{~Km*)s?k;`c!CZR7qq{=Eqnr01$Y0hb{QPa8
zb(7!<uiHbxqg(VTNTQoZ&_f$Ew(NTY+zkK?HHTgSm;RuVue<hu2eZF{PdBKgdfun=
z;EU;eASVjAg4BHQ=ng&L(OqQmnO~5l50dlw<zfAEaD4|ZtRW*0KRh~rcr+hS05>U*
zyMua<44`cAkr$lC!4)8Qe+;-k-uy-YT+@O|FVGA?^Kpe2$Kfh5%NLM3@N5C7hO}h_
z`;Em8RH;JTgDU?LG(FG_l83b)o8KViU(<<TdD|jz;}+CR{tjyYy-)%<pxbmdSoru0
zVF-7PHYgfcmx8J9FE~M>&7eHXFOTp~;~NkgR)2w~1Wb!TI=XFjG@+xCtWjWtLAA-T
z7u$G1rXGKB223CG=(cqM$%2P$YA=B5fNtLlkUHlasLlapgcprq#m8Sv2h-q`aR3y?
zr64|}e*jwb@6pX#4>rsc++OWG{=x&Kpxg8ysQKD?{Dmc$3mR!~eel8p%7F}oA5&*w
zcp(WEV%-D|W>7g}ny$gX(CrJF=$HyNqjm>qK&Ts3t%Ys?6%?*3UOeW8c<CpY26?Gb
z9o&pr;n7*Uz^C)LPq*s=kIvE=KA?f5&<!5lzB4>JT_?O)1=7&%IsxPr2pd#tvKmW)
zTG`Nn&Ih1|@{1*4m9-rnjYmM?9s4qq8<h7j(@XOkM0*81o@M(K<nCs0fjygnfngV@
zV+Ad>Pl2RBrFOUJbv1||#K9JU>y0%C*^A(A#PJtDxxhnstc4Pw2Bl-?1;?Eb<9OY{
ziouC=iW<oCqEo>pf)W{Mn&|;}nh6x7zArjl@4r~j1+nialwJ*@A!BrC^$&7>`{B`T
zD+;m+;vdj%6R21IgKUF%MF;9wABd3xv4_+6<q_>Ibn}jabVAIt2bJ28N^?C(6k^^J
za9`l~i$9zU4E*7sHYli8?L#Qo47Kn!CnCoq>{IBt0LvaKj2*7;Js{EI2htC*HkyHf
z;hXDwM*bGi(r%CAhrlf{h&$9l${_9tfm&0-$-wXuH0%WK(}JsgQ_x~tk8U1Ak8V?4
zu(I<nd_l^<)e$(;BF%5~;v5XL1^EDMv8f!?*K8o6Ue<h2zrR<s14MO~zVPU_wFN5x
zwX8se$PEwhfa@WTZr=+pE^$C2_XUUswc|lmf9LrZ$H08n-yogf#<(d1h}n7k#R8B_
z=kXWYz%(d>v;GB1b(<aoPemPnQO5yoD;@+7qjsD6g5*1ozeojX0f&O<FOX2TiJ(U(
zi=ap6_ZMMcDR5%G50+x#@Bphcl>l)&k9%~UdZCI?v<oB(3GDw+YuRDef|{rgY#8{b
zg4(tnuIFC}BFnr0jTZf9XJF`ZJ+H#ZzYRL)ge`xfr$1MarI3UGTKx`9&-x%yh*MI)
zZU5shYS=-U4m4W}_7N{g1>*@&+0h1?^KCu?O6h4B?Pa9$ADlg}f_&C(V&~CqD+M+g
zltn>N_~L~WJE#(j0y$nG_As=*g6jvhU0y&_?*ynJpZKFdtx;R>oECVL8)VXh7Z*Sy
z=#X@W+P*`nkHGG6g&O72ZMz9PxrA^}7u*!2`9ipRpiW^$=nq2kj~AwXXnln{3s`~l
zfU|(;YLIc=ECL?grjQxF<1c=&g4@ogAhBfH2~lC-(QWz+?Dpd?uCX#OfD6UWQ=j<-
zU7tWz#v@dM=lD90zgPnr(eGt71$C}_Mft!(9;V_Vpw2+;29Vwd9?i!Ue7aeGD}oAC
zUKLP;ck`-(sLs+2$6Y}i@eUn#-2=|#ouLOjK&@Di(>rTdfVza8z6*RhU1#`o`c8Ne
z2(}C~8t;1HGrxfA6OaWrK&%HK)*VoP1muHm*BKzK-Jugaz?GJ7hezi@pKjNV7k^nm
z?Mradn*>$~%1oyJK{H>S$6wrMVPLRf;BOU%6rnFXx=r6erH-&b=l8mOSAep~4H&=I
z7o2TQfDDG#YlqR&Z?H%6n+T82+7F;cR%hu8$RHOe$uW3zH)Mcxf=eS_esC%f6;K8R
zmAisZH}6*k1_t+T5suINQSKU_`J?=GAk#zNJvz_1K*mlsF!^-5UI5K`gG(bJkM2nj
zBSGVxrhAk?X0aXxQ@%HRyCW4mx@G4nFfcfF^GHLv?FtMGzTGm?9^JB6zzzM{6F!~y
zLF+0!I`4UOhVJO}-Qv^fy5hw?@LW|bXaMqnM|bFoZr?2%7=5~3cYv&KJ`xcP>I)Gn
zFCeQ%u(vlGK^A}u0p#`>w)SQ?TqUM`ko?hc!UszZ@c|W>*E(FczYqnP&?~wM)H&`o
zJq(U>+ZaIx2A^Kn9bK;5J6xZ8HXi`Rg1tN_5JfY<DTX%_M0M8gIPMB+t{pn=dIXYo
zK_d*Hu>?@>_qtD~?+TyJ&;=fyzB7D4&7`SJpgiHb1GFN<quaCv-1%_@C-Lsk1s>oe
zi%6%TOrVP5woB(d4`|aW9U%ht)$tb~HL#`>`g|U=e1Y~~KuOK@g9m6l7na;Ucy#lE
zCW$<{MK^+ycy~Q0leWn*Ft~N|u!EY1pagajlvFn`fY#nXVi?@n#WH??Tp!?z--Vz8
zf~fc{hpWVl-)>igebB)spH9~sKAoUOH)tFk)HYz<2};V~302l}5atb!PS(v3<^_*V
z)(sHm36D<JsqzdAxcVcRpw1|`KZ58#LBqH719+eWobkZ*fGtQZ<3DitU3;+^l%^mR
z2ugbpwZ9`M%fJ9N9=e_cDi7|6fQ@|znt&6rLyQ-K`d^^FCM1F(jj@9=3=AGnyU)D<
z4ZwPULwdr0)pdLf4F6R(fXPi@atoN;1}1la$z5P_518BsCJ%tgLtyd<m^=n1Pk_l&
zVDb!@JO?H(fXPc>@(P%|1}1NS$y<D&Y~s@^3+huk2LD%m$jiVm0knsU;pMac|Nm!z
zwnV<X17d+T!o9o%V!40@m`{LMpnaq-_kmcTjjJ!WfLN^{*;OFcVi0Qqh;<gkng(J$
z1+jWStUn-D6Nn|q$iVOtG%Apx0b=EW#JoVP6c8&M#EJs3(m^cHTwO*Ph~)+nYXz}v
zKrB!yerW_^9R!JiCL=TMf>?4Ov2P%j2#6)d#K7>93q0HTf3_wwczYOp?>&eCn%7MQ
z1&bF01A`Ta0m3v_8w#=ogh32Yu-Ae(ppB(OxB+w;0Rzarptu3)V}QFCdd2|*1Be0g
z8z`z6Ku0nlnR~c_ff?j?2Iz?r3}A*40|Nti{I#5c0n|<b8_X~h%3%X_&~`I0FjPUr
z84z}YjRJ{+7$7@I2~RwJ0T~A}mI1^7nTt*Bq{apY=6;al7;?di85qC}9R>!5KOkX{
z2W((6R~Z->Kqi4@K(pG$Fd0y?1j%rLwxmiiGBAK9@W7Jhj0_A?p#78}nLtJc2GDu|
zuuLT*14AZE<`E+U!&a~`0|P^To?B*KW^o3ChNos2Lw;UBYGSr;YDsDlgNCP@8$>9-
zII|=(KhHTMF)uweg+as9MKg@SwW0*P&)6+9C)K|oH7_*C$4WspCxyW+v#7X4!8tJ}
zM*(>|a%Ns;NoHbBW>u<&CWB{QNorAIj)H4ZQGSt?f-`6byh2`ni9#A^mo9^IercY1
z30NSpq$DvpL!l&JA-S}uC^fG{p(LXyH8F)jfkD;CfT7IL%)#Cu&;rURii@lE^7Dk)
z3$`RJF*!B9)`B4;u{eVvBv2=a0lYmPd<FtTh_X%)LrQ9Ka#3ah$cGFe4oZH(!Qit^
zlyri0oEcJ5lS<QFkW>`pBvz&tffPE1f&Cu<7Esbr)A7>@gUV*6q~?`mrh(LD>VzS9
z#i=D;Ww}=6nI##%sU;ctDgMyVw@S=Qfr)@(0EG_?eyg<nB5*)iF=XZymn7yTr@G}A
zd8Sw~fNW(bNGvT*WhgGmFJLH6E%C|EFR)@L%g-szO$G78z$_~U$Z-<knI##aA#N5B
zpIR~G<R_-M73JrG;?jyCC9}97zc`g4rL+jVUz(u+>H-GPc6*Rsr^=GlV!wRn{DMlW
zoYcJZk_@Y~qSVyzjMO}r{Jc~vh9r;z28a|xVopweG6N|7L3)D|a|?1(i>;FLOY=$~
zR)fRQu>_QY7?Klna*`60v%!G`@h&L1oO1G$vtiD6stigk$Vp7j%uDxAh9ryR)MEcM
zsCPi>p-hI*ARn-$;3&0X09(pX3~>Uwlb{{~t3mS*$ngv*sSuw)(hkHB$D*RdO0W$O
zGhyDsE{kFV)EVd|pr}C&Rgf!?>_SnAZW<^Hl~^&vLmX1f5D)eiLp-vH40)xwNvTC3
zBRxTJk)M>6nq1<RU*w%yX$49(p0IQb=J|uALCFv%4=yM&^U_`O5|eULQ>++rK_!P3
zLveCOYD#HNYD!3EF2sBg1Dqer5_7Cd5{uGPORS1hb5fH_@{6oWi&Kj{^V0IIic$+w
z6HAK0wmCzxJ4hp#?+13Pe;O!d7lX1uW(mmQ&iQ#Isd**E{%N4(lL{_RKu&i_%}Gs9
zEJ?LuC@4xTNGwVX$p__B21s%#0U66sT9A@hk_z@jF+*ZmYEfc(YCwK@YLQ!h5vZ`s
zOU<!j$Selw108mhnOByWlL^uSPC1amj3E)U-yEbQwa6ti1yY!TxS4tBR>h^s$*IM~
zX{9+il~yP!Q<L*kQo*I4OJ)i<5nDmso>}Z#Selpv@^elaLqTd$T7FS(Ff6Dr1VD)$
z8Zr3fkd<W?2NdO3R5D~1duQgQ_@_Z~8AE2VZz?D`zy*@?^FVeNhvWx<PIyVq&#_`C
zN-ZwP&r2x|$wxS;D77RpGmoJtH77N(IF%u>v?L$KhDd?aB12VvUMi#*Mk;}k3tx<~
zRxi1tB0eRxxTL5wxddFwr51tW78JaxMOF-mf;Bv`EEQ6)xTofUjvvS`VhAnC%qeC-
z$bd5%1EgvImpBY4B{(d>F!%*S!jnOe!NJJH!NAJG!O)DM%)|i1gjO(~d1d+8so(?+
zsbCDv;;Q4bAQ{NE*2u)c-q?u2!Pp3-Coav<EYQe=!NJ%JiJNR}1g^9UtSn&m1R9z#
zfE0sNF$5ZdRWrn;F$6LsGdLK5?au@`#S|=q-zlKOwDMCtT|kZjISs)#HbUi_7=ZXN
zr<+(Xlo?roT;O16mTY7K=P99tmJ(DF;zI{RGY61TC=Wv^s8$6hb|oVdhGaybDntDU
z(vK7lR)%J<u(N`g>;MUU2+zUTh#?uO6Ka^Up&8s<C0J@zLI{FP3<I?lK(@qH$NL3G
z<>#f^)<R7IxerofC_zQaAi?cqXvW}#aBm7+7Mw0pK#_rv&4kOsqbifZ0WC0K?Jfvy
z;LN~a0B_qO#6T<q*I6?`V5dE(aR^#J3ToDY&PD<8K}|alpMik^bP5!sL;wQ==$tyx
z`7WTdVnAoiflLAMC&(}`fX;MNkY!*nab{rHAj`mz;LO0_AjiPa<IKPSTBp3jnSr4|
zo`K<sGXsNw0t1793j;%dA_GH&3j@OgMFxfz7X}8<{(=plmb?}N!yOj}2GH3zJPZO1
zK9Eys7%wm|FeETCFnnNSU}#`sU{GLYVA#OSz!1Q~z%YT8fkA<dfnft11A_xQ1ET{U
z1H%IW21W-(1||n321Z5@0y&rrtN=X^PYX($KxsQD?E$5OpmYqBPJ_|~P`V0Aw?OGW
zC_Mv8FM`r*p!7B<eE>?Ig3?!@^gSs30!n{^(tn^d%&VaI0<kAR+xQotv@!JDJ4o<?
zR6sDO%L``Nfk_4jC~bp7Jt(b!R6YPr_b@OpC_pX5rTzry03rqkhPBX?2|8y6q#uT1
z^2ea^$}kBi4U>Nbl?TmQL8ZVHOr8_!UR?Thq4J>g4%P@IVEXl;@}P7GlF9(}`xzJ*
zc0lO|P}%@`4ixD8Cy=@uP(Fwa!XW>F?D*mi;xRD5&hK*oWi|!|hDHWRR|*!65LFED
za|1!=hQY+}(V&S;&^l@mMplP@{vfg(Ha5(?ETF@s7#JAlK+hlC0CgZP_xeHAX#`_4
z6;lkCdtv5a>cB1naxW;3)<WHT0qPC~U5NVAXyOe}@%K>i`%v`{pyIgv7XnpxgGm2@
z+yzSNccJkPbC-i2#9a!W5E>>fpby~}pt)-SRD3>E{3FyI4bY5g3pM8_RQv-}JOiqp
z1+;n_WV8v0U|>jsit|Fn6`<mvl@_3Ilz^t|V5qsGP<0?VP})*}%Ev(ECD7zGpz_I3
zc`2wo$aYXZfW<rL{4$Uj48y{=0CtWUR6+qXGz4WMQ=sq#xoH(>1c-rw0TwO}Q2%H`
z!(9ey{{pBu?0ipksCWRhyaJgAnr>nBhS>59Di7f?Ff50L+eb8UKB)SiXyU?9aYoP(
z6wD9?1_l+VI1ie*15{iJO*|bcu8k(14;42?6R*P|-VYT=_t#>mcrcnd+o9s<{@Mo>
zk3&;`3@VPU{t{Fimfm1NaStk<j%Lnds5rX%7f^BZ@c#@IN4FOgpP=;iABQ~X+(^)g
zV=>TjJ`qZ%LFqy$T?VC_p!8%Y4dcVY6Xq_MJ7Dn+i)UE8!r~DYZ!p>p8V;~{fSCge
zXBZzAF0gQe@nQB?Ld}8EpfCW1IjnvHu|XIVKA<+<R%rfdM@zr=q2im+#HT{}2cR^}
zeDrz`G)N7qGC&w)9}K5J%c%>{d>s)9lfh1d+zHyPU;)j~uzYS{22pQ|Ce8qwZ(v|x
za7GgkfQoxS#k-;5bO0(|2^F6P6%PO{A7Ef$Xorf!?7aY5H417NL&X<D)jL2(mLs6z
zE1}{IQ1O1KI86NosQ3&taRJcEa|Q;6L(uYb3)Gwds5p9j6+qi(0?=@UxibJXT+G10
zAO{tPrJoJZ@=g^h4m1A(RNMe6z8`9@0Mwj5sC$k>#SNh1pn3z8jx3<%K1}~5s5+1w
zD4!WX<zeo*0+k1q;h=g2lpjH7R4;+%uhmfcB$U1kr76v?EsP8dAp1b+3Y3ESq5g%X
z%N@}42uqg{p!Gx`g;2Zz%7@h>uzCiTK4Iw*mi}PrEf5;du=J4(<-^h)ES<s92|Qgu
z)t!RU7ohZYC=F|0C_(F|U?>f1Z^G((SbG50zL*772WwZr>bF8@JU2jTSiH}H^4CFW
zSo%B(<#R#H3n?hA1EoEobQqLQfzky~x)w^q+M83M{P|EC*1m=YKb(TKzhMHf_Bo7?
zi$-t1gVF*>EhzngXjr;{@nP~HIed5q^t@ltxw81wJ%Fmirv@bF0c~eafaV*J7&bfs
zs*VG#-+`{S16tmqi=*>3pzW^+0_Jf*&m%_HkIpZE<|mkV8#KSc_zIv+I4}<A+-lG)
z9THyvbl4>W<jhNua0HYOVk6@MsJTCI$P1vk1Ev?I+yjR^Ox-9w8UmvsFd71*Aut*O
zqaiRF0;3@?8UmvsFd71*Aut*OqaiT(LqJf`B0=0K*ck*HSS1QL!kmJggWL-YAY`O-
zkZXddV=xH11UVK+L^=i$1D%4L5@Z|;1R#nF6oOq6j6r5N#W;mJCg?jAa1<y6c?LNb
zC<Hk}$O451R*nLJAg2Ne(BcX~hj@P{FXwn?AIIR}c$IjRl`sr}g$*(jgwT}u1w+=W
zF*LjY?QH~M#t9f|AZtz-8bFKIK}!BJP7uaW1YM2Pu!3>tmYpy&d|g8vVa|asSZZka
z2R7yZf5r(rChVQCW5NUn=$%WcxdkPa@yUtF8L12nFaE-m9bi|O-~hdSuQ)w8H7|vs
zVZ%e1EKCZvnhU`PFZh}u;t(GnpI%WBUyxc<oS&DNlUY(3UuMA2@BnJUf5r)-4)O7R
z!Or=4$wjFpslg?Q$=TqwoD2;g5Q-d9Dsxi6mng<3W#*-%7NG>21V)g!fNqd#I3NuR
z4Ma%zmX?5)BD!QIgVysV7F9AdNMNc0t^O-wXyCw<2@UdLXt;soviSITXE$fib$y9>
zC6M?6ua^r-O-n6G%}Y*YXjt$Zs-E!xs|4s+ghC4;hj_nWpZs)&2@Hh}!q5;#S{N6U
zT2fk+7nYb)nhH|l0aKC-jf4pdg#l<{!Ju2cj6kX*U^4J{VJJ*Mh(Y3pp)dng$PsB-
z-UNoi0-UlbXpXCZsVoMq>kBR^%FhG)tAP;|x1o@m2ZK_JK`V_XFcfxxh2wKmbCU}y
z<C8P8K~A0k5(KR)PAo~zh)*mi$f*Pg&p;7QPc4a0&&f|p%!w~7O@)Na0+0&OnpKeU
z6(CMdPElrFNg9a10mRRREXtk0P`CrkP0cM%Edj|MU=(+VM_#4w0$tZUfuZmOx}1Az
zNkCD4L26M6*kKpY<)JIwLFV2-mkR<dN1wn@_yAoZ7}d}hjA9P)WiG)1@wtf=WegJ-
z7#QOjSQ(hS63Y_fQ&Qtg@{=+Xi{nA7xeF3g;u$o+g$_d(69W^{s>OJQAkdmd(8|pC
z<f7EXl2jO%p_Pe&4YWoWx-zxCfT4x4m|-qsdTI&7F-FiLZ-$SIpjZH{?*7Ke%mA8L
zW6DXaWSGndUOhg8k(ptFB?B|V0xJdvCeTvyRg9@64C@)088%omFff7E-ZC6yge)d!
zcmp!QhJk?@%74!20$VZun=t^kX1sxknc;yg12e-1I|gQk2@VX*3>Tajm>C{8gT!1I
zm>C*E7#Nt43p9phOt2iy@SKT(8RS98>Q08!Ops-rE0~djgy9%70~2E5=R+pQQqNt?
zEDQ(sFfyPR(8CNdU>%A92T%-H#0)WD3o{GDi#?1CEDRI&g2)|U@&TCa*as5X048tj
zgUqlVFu%Y!0Sp%~PGDTXcz_AQOK=DX_`q?2X#uN2Kte(SNYMkvf&<JC7#$206cQ#d
zUtkO<n84V;T;LGk;IM(Yfyu$3fvLd3AVI-FK>>0fTMAP34Vq3s=9e-sFr+avGW5jU
z0FTUrT%*SbSq})(=E}&xpn}8)$%B?Qf!6DR<UxEtMg|6CK1e@k-5^N51gam#2dM|?
z2bFaoc@Q6@ADIu*4_a>slAjCJ595Q>6QdurP7$R4I8;B3Ppp2>`bLm`(0W9W|6zQX
z{skaO2GEUT3=AOmBlAJ-2d#?)DUo4<gddC#(~s<5kbY!7NIz&jB}l&)R6mRl(~oQ)
zNIx<kq#v{n6QsWasvpLO>30Azklc^V2k8f`-vsGj2-OecgR~J7{-AZAApK{d`eA%x
z^@G-ng7p7|>WA@R`ujkVNbX1GgWS&mT^Oj#3<-Z2KbDz+0dm3`!~mFipu6foA|O5}
zJdybz^Ae!uZHAf$<Ac<L!UH<J4qk2v(vQps>0bcVe-)}9#)s*LUhfLmkIV<@{{Yp`
z!~*dTj1SWfT?PZ!596D#FfgdGK-Tbr{O1PcgVyqb_z_S(XiYDOp9STE*7kz<HBdfi
zjW3Ab2jzp-`hxfipnTApUl4y2ln+|_3*sMz@<D5WL444Dc946(Yk{HhmjdzxNRk1w
zyn4;Tz<^v{F|tC+tK+$-<rQqb<uO)B_`vueqe1ag09vE~wGR|OF#cQ6+G42PAWE2x
zfdRDU0mKGjkbZpbGi5_{pDi22eZ6SqDQtb^7dD9dV0@7IAoqEK7)b7e@uk^O-D8Z#
z2Wi9SK6iFh_ocE!+;`&-YWRUK$^@O4$N_O5j1Mv&<i6>kg&s)mL*|3h=K|1HL<R<i
zM5ulkAEqC=Y!RM5k@+C~7ohs<q55Hbn10Z)q_Fq^#UG3hIs*lio<M8LVe<IG;{*q4
zc--QEga>+hf~_x|%?Sw)7$4>y<njUJ9%MeqKd^PEXQ29Fd}8&()~hmeLF|X|iPaBV
zhw2X1597o1BiGj;_apN`?uV^cErjZa@nQOr>no6cWIjkgY+dU@sD2n9rXPHSHd1;*
z=7aRZ*1z6^>WA@R`auU<!{QrcKQbSrAGS^wbO;lu{)X{k`VW8@NcJQ1LHaj<HVT7w
z1#?5fAI1l11LX%~_k!$4=7aRZ*5k)Q^~3lu{mAtLNIx<kq#w49zZj|?#)s)g&Oadi
z$b67~2IzX&9;kj8AEqBx#)0@C{m6Wfe%QL<<xu@FK1e;t|FDh2AU;SxjDLWefkBNA
zaz8mJer|B1mS6wS_)0ve^1f*NY&1T|K79GRmj^X}&*p*T?}M?Z<sEDtaRe_Ueqnr&
z`5^xx=Vy@rkolnSfvq<#g6fCyVfrV47)a?0nGezrTi-YVsvpJ&X#?4hoF75<BlAJ}
zVe255K=s4;F#X8w2atYbK1e@oz2r`)ei$F7A2~mP^ds{@`a#`4Q2d^S>WA@R`jN{6
zkbY!7NIz`-<x{AB7$2s;0mMKGKV&{gKWv>Q6CWi0V0@4^Q1~Ic7i2#&AEY0)o>LO4
zAI692N6wER{m6Wfe%QKCeW-pIAEqBUyg~Yr`5^tU^`V|n{V+aEKeBxw{m6Wfe%LzF
zM5ulkpIH5{^`@0j{V+aE{{|2PDg2T7Ap03?L9x%k&=1uQ<Abz;!XI4GBk4!xgY`q#
zwQh&$hw@?ik^PI!|FC^aXQBFGe3*XZ@(`pSnGdobwyyRWR6mRl(~s<4kbY!7SU+?>
zlsrEq{S`p@F#X8s4Wu8L57H0YPn8AL597o16Y@W7A67F|Ka3C4kL+KN{m6Wf{jhxz
z^P&1-e3*XZ@(!dQnGezrTW9<YsvpLO=|`?lK>CsSApNlQ$UFj&@PqMT`U&|Twr*Js
zsvpL;7r@@XL$)8AdtmFG=R(bc@nP;Eq#w2(dlytcj1SWf-IfPVMj-oP{Obac`ceTj
zS-`-+@E*z!fbzKnQR_!7G`=qyKOKz^x(Yx|ih;oZ8i5l885lr(3n+gol<xrL&w}zj
zp!^k3egKre3(Ajx@<IMXu8&U%GBC(7HZZ{Y+rOZESbteY2qF*b|9V3Cu>Ned5Ca3~
zbT?T4Z4s0Y>o1*zs)zM2o<sSt{(_t^L_e&(?hoa|+TU$ZKCC@`3d)DIkH0|qu=cKs
z2*f;C`!x~DhqXs*pnO>Saw(J#YcD>4@?q`2Z%{t0J;yH!F(1}G(}MD0?JZ|0AJ#sJ
zh4NwTjcO<#)_&-R@?q_PB~U)Be%}G*!|Lk`P(G~weGBEo>Qfdmi2GpmqZE`6tM5#p
zd|3VE1Lec&qZB9~R=-q1`LOz85sVKl|93$7u=4yOln*PPxx^vvft9zRP(G~u%!Be_
z<zW|;4=djuLiw=r>N}JVD}MwfAm+o$6D=qoRvx%R`LO(*0^%c$uarUgu<?}+C?7Vy
zG7HLwjjybM@?qmE`=ET-_{s$+A2z=72+D_zuY85_VdE<tk_-%dEDQ{=@fFY&Bp^Pl
zf2<3VM{1wDLiw=rCl<<wl|L1d3=DGO3=FV+gY%$#*gnBSP(Ey5;9DpkwjYF73Zfsr
ze?*Fbfe)!XvWD_u<&guF4=aycp?p|*6b$9V%A-^$A66cfN-;3-GeY*CgIXvHp?ui*
z<3%VRKAtEIQ4brR)rayy`{6<Q<Dh)l_-Q+o4;zo(2<5}Zw{JoDu<>Fx8Ho9?@mmup
zA2uEx3+2PcTY5o!2?hq(zKG>eK5SpZZYUqNKjJ2o58EH{8_I{R@0XNiVBnWvV1Vs2
zFog19`w4=feAvE*N?GujHfU=r$omX^X#C}9{5@#=b7=hM5I%JDh=Ji9gb%7Vz~*zw
zf$f8D!;nYgJ3{zy{Sgp8Xj>6je?Ei{mv4jc;pWXj<8OfQ;rdTQ_@FD2z~((d<9~wi
z;pU0RgWU@qO=Muug7D$`Eg*cj`Q8vdTs|6&Uxvo7LF2cg@q5wupaTU#(^O!`GcYi0
zg2=<|KY+#uox6#w{t=q|do(_~0@%NB^R&_Uwh%sOYZurF9uPj<za5MW4D%Qn80IrF
zFf3qXU;rIyw}_E}VKE~E!xBaYhNX-Q43ild7^X2YFw9_NV3^6sz%YxEfnhcy1H&9f
z1_sdlPctI}1883tXwP9ABLhP_BLl-SMh1rEkW}O_iIIU}D%1{``LwiGfk8jCIJKx)
zA2REz?~<QfnhQEeNI#$`KfNe1H#ZYBzpwAC;Fg%1nUk5S?~|ESlvq@$k2LX!!e&67
z!YxnC$%#i&tCyRLW+lu(m(;S<9MIgeegx=LAbpqAqRg_?6wo3EWD9gt6H^nD63dE9
zi<2tLk`v3)3Uagaiz-SBk_z+mok}xvQuM(m(&VP5WG0rR79(rcO9IQgfQ~c6A`V$&
zQmmVoUzD4eqhDcR7H?*vPryU@4DmRou93VQk2E1ojB?QIH&Nz7&O0N<Nbs3xL@9)v
zn?{uN>8T~qX>TG;CP6iLrk)sMVRQM!s7+5Tfltp9sUALuA0Hp(XYS?a>6%v-Z)onG
zS`u86Sdy6xIkC>u#Wlb@J_~#*T7Y+QuyH(EI;T8qW#wh+WiTMS!qPpp1eEx~d|d+q
z%pt6J6ctc+7G>t8hlaR0XCxLCy9QXqXF*QD3qUo_$S??UdKF}a4>k?n$qeq!&he=g
z$*Bb;@!(ZP#uy?d7$T+^B4!vO<`^Ot7$TM!B8EnoLYOWxG(kE73%*7|Z^)HJh&3Px
zPvkRbM`ICJ0OcR>315&i1!EZ?%lD9%m|)QcRRvplf=vZ@>B!IvJBYJEp#^3s;5}mz
zTWEo`p@k1b3|>X(feLQWvL#TsffgqX<@yfOGq~$In19h1V<DGThQ@xW<!(9oi6!8L
zMXs5sC6#4xY6(I%C^bDZKhHJ5&?r7D4X!6MGr&6yBf}dYWp1$1LoacH!Vj{z3*rG#
zGDQ<pfE;28mIs~r2vH6@LNpeo6aXv2p#kN<Oft2B)*`~sIgMq|MJj+GR)g9**c?ev
zC7SC<Q%}%Y(8Eiyxfm^U!KXD^#WKXl$D0^nx&piE_$1H)t?`-Qa}hyWlk*EI<1<oo
z3Q~)pav)LgVUGFe61XfW#^%~&(7CZ-*Fmg=ogkTC6kn2C04=0E!yJR+RpQaoksjhS
zRPfSDT&loU5HJZjz@bVpYYuRVfXZU8eIP23+RH;P10y>glzEZ(3ZTpYS&a(HZm2TI
zM;L=58d(-pnP7;4mZ+i&g4*^NVvuIM6}mX6SpYxf7+n(DltveZoS=*@S`2IaW7q*Z
zGZ|e6><DFaamazW;N)y%s2hzO22d$z?jbj4A)83_QMF+An3|!whj`sYI9bok3}<<u
zXJ*czjS>`8IyW0V@Ik38wFq6bIJE?Nz%059{Jhy%s`qe^qDe1<0X5)@Q%evBF{8T)
z<&0c#ykRdE<Drp)T3qUxSwM>?XjzEt4oL9emWKxiR0*v7Lox#@gIxBZ$ifaXFJ_3(
zD$8YvPtGZ3h=&|i>kmGP9*GBAP!5-eoVASFlp>;Yirg?8kZvTAofhqAa1)zgYaO|7
zPOWw(vJ=5o6pj{^6}YOj0u}CPbuA7JXpJ0V?LpCoT=jwrV05cNwa#c0ES}a)Fw`;{
z6zHQ>eP+JGXjPBe?jPz^J^7XK5FIZ>ceVkjrAA7t0+)J>)&^R^P2>I<WlbEaG*v(Y
z)mXOrA+?F(p&b!oCn3lm(<j0$q)l=lY5<}f59*E)rI7fU9#D&wC?laa<PfWtgt;3~
zhZLu=p!5zJ8^sta1P@2xZa>3hzzsrZn;IqtG7~Z&25zX~l!XtQLsj5xlY`xYEQ@R_
zvN(2|v8zC`9ov>%lzqC$dvQ@DV4HAJ1i`y+QAC1~w%tOvVM8VWU_pkue;-xOFBmlM
z3JoKe2ESm;edXxdp!@yNg&{Mm80JCdnJ|PQ8`IIv0BuT#h#?0qeA_>c4fgTzsC%;s
z?_|fmn?F7tc{4Yb^8~;}7ShIU1RrBZH~9J?hIrT>?s(|tZIA_^UE7e82ypC^he*P9
z$fNL}d*dNuuwC&m9(X@IG6#7lJPvV`J@61U$h+T>c5!2zTmW7{0U>_f<2k^<!2E)N
zfdRJG1hhkniGhJ}4Fdz{^iswh;Kig2%nyFu;{k~`Fff4^M1a=9fR@{Xmi&U)JPZt*
zE{HHP@IXvvV93c#LaH@%O-)TrO)O1JOj67(Q`1rnQ&N*njSW(blPuCKO_Pm`6OEG7
zQccq=7_3Ua-DYjo6zLPWTeoma(VPSGP8P$=M5a}(t}SBvHCb}Xo@1X)dd>=VUo<>?
z^J-bAZ1I8VKTTMFM=U(PWvlL^48a&<Ti!)6rXj-eKVMq~sy#Y1ZIWx$cS{lJJ{gHd
z->17-*-UaWJXzMMMqd^8Eq+%owr|Jp?k|lSeqDC$<(c$blGjLp@mclG?ao(h?K=hT
z7~Ym;<MasXdN=o*)a=dd4Vw-ct<LXWbMIxz_4$jAy!q0kB)iYWS?kp6CE{rY54X41
zaK9){`*<R`ZNumKjb9X1ZE{mi9yk8cGr9BBt3QtybT6*f|8>vqMff?ViA-;r&jd&J
z7YR?gyVWa4{Uqn!i??RwuWm0Cb(*l|*F7Fkz=OjV5*JJwNO7@(fq?-fE)<w3kBb?V
z3KRTRr}C9n^sss@*bwBG)v*7#)MDKqm&})mJO6A$jt^{X&%h4lBhPYbyS+EX3)Cn`
zowkT>WqKsC<EX|e^_HJ1A<7I^w~{}V8J`yJT^kY4Q1jDbhtWfeE~%ycxzF_MEEh<Y
zcZsRJO0+(5cA}gZGr#a>kDy6A8jBKGeox(Q=UhKy(^g?e^(Ren8|9U+#z@_8Y2JEi
z?oz(3ADP#CGk!>F(75ID;g0{rxQm(o4I7jD%of=gDLm`2OyB6A>-F~e+2yS6n>S`Y
zSevlK;{M+=&bQZQ?YkEI@V-giRK=rv?qAy^f4(Vw^9pm_N;RR)B6(bX)g~oOQ^NT<
zH)d>FGdp_u>asUY0hW`RY~ALRR!Ppf(x|~@W@%E<|9hM4ZH*tl*72Ha1Rqg~j+3u$
znExkUT(pU&ea_Ye|KFs3zj*IX$h?2-cY9i%+pe5?^YrS3iBCFIdt8bIy%<ei?79?k
z+U}QFclg~7z3#=T)5Tkti}{!D4@{jsFEQX>>E=_rlAO9E-9H;@EJ`X4oAjHlT14h{
z-jSEv+U{zlJqa)BJj;7T=y$sFuha8>-QxzO8Th&~Y;iOyHW~t>Aut*OqaiRF0;3@?
z8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*O
WqaiRF0;3@?8UmvsFd70QB?JKOFJtTg

literal 0
HcmV?d00001

diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudio.java b/PlayWallNative/src/de/tobias/playpad/NativeAudio.java
new file mode 100644
index 00000000..cee1d727
--- /dev/null
+++ b/PlayWallNative/src/de/tobias/playpad/NativeAudio.java
@@ -0,0 +1,58 @@
+package de.tobias.playpad;
+
+public class NativeAudio {
+
+	public static native void initialize();
+	
+	public static native void play(int id);
+
+	public static native void pause(int id);
+
+	public static native void stop(int id);
+
+	public static native void setLoop(int id, boolean loop);
+
+	public static native double getVolume(int id);
+
+	public static native void setVolume(int id, double volume);
+
+	public static native boolean load(int id, String path);
+
+	public static native void dispose(int id);
+
+	public static native double getDuration(int id);
+
+	public static native double getPosition(int id);
+	
+	public static void onPeakMeter(int id, float left, float right) {
+		if (delegate != null) {
+			delegate.onPeakMeter(id, left, right);
+		}
+	}
+
+	public static void onPositionChanged(int id, double position) {
+		if (delegate != null) {
+			delegate.onPositionChanged(id, position);
+		}
+	}
+	
+	public static void onFinish(int id) {
+		if (delegate != null) {
+			delegate.onFinish(id);
+		}
+	}
+
+	private static NativeAudioDelegate delegate;
+
+	public static void setDelegate(NativeAudioDelegate delegate) {
+		NativeAudio.delegate = delegate;
+	}
+
+	public interface NativeAudioDelegate {
+		public void onFinish(int id);
+		
+		public void onPeakMeter(int id, float left, float right);
+		
+		public void onPositionChanged(int id, double position);
+	}
+}
diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java
new file mode 100644
index 00000000..066831de
--- /dev/null
+++ b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java
@@ -0,0 +1,135 @@
+package de.tobias.playpad;
+
+import java.nio.file.Path;
+
+import de.tobias.playpad.audio.AudioHandler;
+import de.tobias.playpad.audio.Peakable;
+import de.tobias.playpad.pad.PadStatus;
+import de.tobias.playpad.pad.conntent.PadContent;
+import de.tobias.utils.util.Worker;
+import javafx.application.Platform;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.util.Duration;
+
+public class NativeAudioMacHandler extends AudioHandler implements Peakable {
+
+	private static int counter = 0;
+
+	private final int id;
+	ObjectProperty<Duration> positionProperty;
+	private ObjectProperty<Duration> durationProperty;
+	private boolean isLoaded;
+
+	private DoubleProperty leftPeak;
+	private DoubleProperty rightPeak;
+
+	public NativeAudioMacHandler(PadContent content) {
+		super(content);
+
+		id = counter++;
+		positionProperty = new SimpleObjectProperty<>();
+		durationProperty = new SimpleObjectProperty<>();
+
+		leftPeak = new SimpleDoubleProperty();
+		rightPeak = new SimpleDoubleProperty();
+	}
+
+	protected int getId() {
+		return id;
+	}
+
+	@Override
+	public void play() {
+		NativeAudio.setLoop(id, getContent().getPad().getPadSettings().isLoop());
+		NativeAudio.play(id);
+	}
+
+	@Override
+	public void pause() {
+		NativeAudio.pause(id);
+	}
+
+	@Override
+	public void stop() {
+		NativeAudio.stop(id);
+	}
+
+	@Override
+	public Duration getPosition() {
+		return positionProperty.get();
+	}
+
+	@Override
+	public ReadOnlyObjectProperty<Duration> positionProperty() {
+		return positionProperty;
+	}
+
+	@Override
+	public Duration getDuration() {
+		return durationProperty.get();
+	}
+
+	@Override
+	public ReadOnlyObjectProperty<Duration> durationProperty() {
+		return durationProperty;
+	}
+
+	@Override
+	public void setVolume(double volume) {
+		NativeAudio.setVolume(id, volume);
+
+	}
+
+	@Override
+	public boolean isMediaLoaded() {
+		return isLoaded;
+	}
+
+	@Override
+	public void loadMedia(Path[] paths) {
+		Platform.runLater(() ->
+		{
+			if (getContent().getPad().isPadVisible()) {
+				getContent().getPad().getController().getView().showBusyView(true);
+			}
+		});
+		Worker.runLater(() ->
+		{
+			isLoaded = NativeAudio.load(id, paths[0].toString());
+			if (isLoaded) {
+				Platform.runLater(() ->
+				{
+					durationProperty.set(Duration.seconds(NativeAudio.getDuration(id)));
+					getContent().getPad().setStatus(PadStatus.READY);
+					if (getContent().getPad().isPadVisible()) {
+						getContent().getPad().getController().getView().showBusyView(false);
+					}
+				});
+			}
+		});
+	}
+
+	@Override
+	public void unloadMedia() {
+		NativeAudio.dispose(id);
+	}
+
+	@Override
+	public DoubleProperty audioLevelProperty(Channel channel) {
+		if (channel == Channel.LEFT) {
+			return leftPeak;
+		} else if (channel == Channel.RIGHT) {
+			return rightPeak;
+		}
+		return null;
+	}
+
+	@Override
+	public double getAudioLevel(Channel channel) {
+		return audioLevelProperty(channel).get();
+	}
+}
diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java
new file mode 100644
index 00000000..66245637
--- /dev/null
+++ b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java
@@ -0,0 +1,78 @@
+package de.tobias.playpad;
+
+import java.util.HashMap;
+
+import de.tobias.playpad.NativeAudio.NativeAudioDelegate;
+import de.tobias.playpad.audio.AudioCapability;
+import de.tobias.playpad.audio.AudioHandler;
+import de.tobias.playpad.audio.AudioHandlerConnect;
+import de.tobias.playpad.audio.Peakable.Channel;
+import de.tobias.playpad.pad.PadStatus;
+import de.tobias.playpad.pad.conntent.PadContent;
+import de.tobias.playpad.viewcontroller.AudioHandlerViewController;
+import javafx.util.Duration;
+
+public class NativeAudioMacHandlerConnect extends AudioHandlerConnect implements NativeAudioDelegate {
+
+	private static final HashMap<Integer, NativeAudioMacHandler> handlers = new HashMap<>();
+
+	public NativeAudioMacHandlerConnect() {
+		NativeAudio.initialize();
+		NativeAudio.setDelegate(this);
+	}
+
+	@Override
+	public AudioHandler createAudioHandler(PadContent content) {
+		NativeAudioMacHandler nativeAudioMacHandler = new NativeAudioMacHandler(content);
+		handlers.put(nativeAudioMacHandler.getId(), nativeAudioMacHandler);
+		return nativeAudioMacHandler;
+	}
+
+	@Override
+	public AudioHandlerViewController getAudioHandlerSettingsViewController() {
+		return null;
+	}
+
+	@Override
+	public String getType() {
+		return "Native";
+	}
+
+	@Override
+	public void onFinish(int id) {
+		NativeAudioMacHandler nativeAudioMacHandler = handlers.get(id);
+		if (nativeAudioMacHandler != null) {
+			PadContent content = nativeAudioMacHandler.getContent();
+			if (content != null) {
+				content.getPad().setStatus(PadStatus.STOP);
+			}
+		}
+	}
+	
+	@Override
+	public void onPositionChanged(int id, double position) {
+		NativeAudioMacHandler nativeAudioMacHandler = handlers.get(id);
+		if (nativeAudioMacHandler != null) {
+			nativeAudioMacHandler.positionProperty.set(Duration.seconds(position));
+		}
+	}
+	
+	@Override
+	public void onPeakMeter(int id, float left, float right) {
+		NativeAudioMacHandler nativeAudioMacHandler = handlers.get(id);
+		if (nativeAudioMacHandler != null) {
+			nativeAudioMacHandler.audioLevelProperty(Channel.LEFT).set(left);
+			nativeAudioMacHandler.audioLevelProperty(Channel.RIGHT).set(right);
+		}
+	}
+
+	@Override
+	public boolean isFeatureAvaiable(AudioCapability audioCapability) {
+		return false;
+	}
+
+	@Override
+	public AudioHandlerViewController getAudioFeatureSettings(AudioCapability audioCapablility) {
+		return null;
+	}
+}
diff --git a/PlayWallNative/src/de/tobias/playpad/Waveform.java b/PlayWallNative/src/de/tobias/playpad/Waveform.java
new file mode 100644
index 00000000..f01873a0
--- /dev/null
+++ b/PlayWallNative/src/de/tobias/playpad/Waveform.java
@@ -0,0 +1,7 @@
+package de.tobias.playpad;
+
+public class Waveform {
+
+	public static native float[] createWaveform(String path);
+
+}
diff --git a/PlayWallNative/src/de/tobias/playpad/view/WaveformView.java b/PlayWallNative/src/de/tobias/playpad/view/WaveformView.java
new file mode 100644
index 00000000..25029d49
--- /dev/null
+++ b/PlayWallNative/src/de/tobias/playpad/view/WaveformView.java
@@ -0,0 +1,39 @@
+package de.tobias.playpad.view;
+
+import javafx.scene.paint.Color;
+import javafx.scene.shape.LineTo;
+import javafx.scene.shape.MoveTo;
+import javafx.scene.shape.Path;
+
+public class WaveformView extends Path {
+
+	public WaveformView(float[] data) {
+		getElements().add(new MoveTo(0, 0));
+
+		double width2 = data.length / 1200.0;
+		int width = data.length / 10000;
+		System.out.println(data.length);
+		System.out.println(width);
+
+		int i = 0;
+		for (i = 0; i < data.length; i += width) {
+			if (i < data.length) {
+				LineTo lineTo = new LineTo(i / width2, data[i] * 50.0);
+				MoveTo moveTo = new MoveTo(i / width2, data[i] * 50.0);
+
+				getElements().addAll(lineTo, moveTo);
+			}
+		}
+		for (; i >= 0; i -= width) {
+			if (i >= 0 && i < data.length) {
+				LineTo lineTo = new LineTo(i / width2, -data[i] * 50.0);
+				MoveTo moveTo = new MoveTo(i / width2, -data[i] * 50.0);
+
+				getElements().addAll(lineTo, moveTo);
+			}
+		}
+		getElements().add(new LineTo(0, 0));
+		getElements().add(new MoveTo(0, 0));
+		setFill(Color.BLACK);
+	}
+}
diff --git a/PlayWallNative/src/de_tobias_playpad_NativeAudio.h b/PlayWallNative/src/de_tobias_playpad_NativeAudio.h
new file mode 100644
index 00000000..4bd71030
--- /dev/null
+++ b/PlayWallNative/src/de_tobias_playpad_NativeAudio.h
@@ -0,0 +1,85 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class de_tobias_playpad_NativeAudio */
+
+#ifndef _Included_de_tobias_playpad_NativeAudio
+#define _Included_de_tobias_playpad_NativeAudio
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    play
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_play
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    pause
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_pause
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    stop
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_stop
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    getVolume
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_de_tobias_playpad_NativeAudio_getVolume
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    setVolume
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_setVolume
+  (JNIEnv *, jclass, jint, jdouble);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    load
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_de_tobias_playpad_NativeAudio_load
+  (JNIEnv *, jclass, jint, jstring);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    dispose
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_dispose
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    getDuration
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_de_tobias_playpad_NativeAudio_getDuration
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     de_tobias_playpad_NativeAudio
+ * Method:    getPosition
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL Java_de_tobias_playpad_NativeAudio_getPosition
+  (JNIEnv *, jclass, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/PlayWallNative/src/de_tobias_playpad_Waveform.h b/PlayWallNative/src/de_tobias_playpad_Waveform.h
new file mode 100644
index 00000000..9d0e45dc
--- /dev/null
+++ b/PlayWallNative/src/de_tobias_playpad_Waveform.h
@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class de_tobias_playpad_Waveform */
+
+#ifndef _Included_de_tobias_playpad_Waveform
+#define _Included_de_tobias_playpad_Waveform
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     de_tobias_playpad_Waveform
+ * Method:    initialize
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_Waveform_initialize
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     de_tobias_playpad_Waveform
+ * Method:    createWaveform
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_de_tobias_playpad_Waveform_createWaveform
+  (JNIEnv *, jclass, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java b/PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java
new file mode 100644
index 00000000..0fe58a6c
--- /dev/null
+++ b/PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java
@@ -0,0 +1,20 @@
+package de.tobias.playpad;
+
+public class NativeAudioTest {
+	
+	public static void main(String[] args) {
+		System.load("/Users/tobias/Documents/Programmieren/Java/git/PlayWall/PlayWallNative/libNativeAudio.dylib");
+
+		NativeAudio.load(0, "/Users/tobias/Downloads/03%20Hymn%20For%20The%20Weekend.mp3.wav");
+		System.out.println(NativeAudio.getDuration(0));
+		NativeAudio.play(0);
+		
+		while (true) {
+			try {
+				Thread.sleep(100);
+			} catch (InterruptedException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+}
diff --git a/PlayWallNative/test/de/tobias/playpad/WaveformTest.java b/PlayWallNative/test/de/tobias/playpad/WaveformTest.java
new file mode 100644
index 00000000..704d8b6e
--- /dev/null
+++ b/PlayWallNative/test/de/tobias/playpad/WaveformTest.java
@@ -0,0 +1,38 @@
+package de.tobias.playpad;
+
+import de.tobias.playpad.view.WaveformView;
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.scene.image.ImageView;
+import javafx.scene.image.WritableImage;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+public class WaveformTest extends Application {
+
+	public static void main(String[] args) {
+		System.load("/Users/tobias/Documents/Programmieren/Java/git/PlayWall/PlayWallNative/libNativeAudio.dylib");
+
+		launch(args);
+	}
+
+	@Override
+	public void start(Stage primaryStage) throws Exception {
+		float[] data = Waveform.createWaveform("/Users/tobias/Music/iTunes/iTunes Media/Music/Coldplay/Mylo Xyloto/04 Charlie Brown.mp3");
+		float[] data2 = Waveform.createWaveform("/Users/tobias/Downloads/TNT-Loop.wav");
+		WaveformView view = new WaveformView(data);
+		WaveformView view2 = new WaveformView(data2);
+
+		WritableImage image = new WritableImage(1200, 150);
+		view.snapshot(null, image);
+		WritableImage image2 = new WritableImage(1200, 150);
+		view2.snapshot(null, image2);
+
+		VBox root = new VBox(new ImageView(image), new ImageView(image2));
+		Scene scene = new Scene(root);
+
+		primaryStage.setScene(scene);
+		primaryStage.show();
+	}
+
+}
-- 
GitLab