From 5c3e0bc2accc8b0e0ee7cde41cb12c68a310d6d2 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 29 Apr 2024 16:55:14 -0400 Subject: [PATCH 1/6] Added a new package `leads_audio` with three sounds: `DIRECTION_INDICATOR_ON`, `DIRECTION_INDICATOR_OFF`, and `WARNING`. --- leads_audio/__init__.py | 6 +++ .../assets/direction-indicator-off.mp3 | Bin 0 -> 9140 bytes leads_audio/assets/direction-indicator-on.mp3 | Bin 0 -> 9428 bytes leads_audio/assets/warning.mp3 | Bin 0 -> 21380 bytes leads_audio/prototype.py | 44 ++++++++++++++++++ leads_audio/system.py | 3 ++ setup.py | 1 + 7 files changed, 54 insertions(+) create mode 100644 leads_audio/__init__.py create mode 100644 leads_audio/assets/direction-indicator-off.mp3 create mode 100644 leads_audio/assets/direction-indicator-on.mp3 create mode 100644 leads_audio/assets/warning.mp3 create mode 100644 leads_audio/prototype.py create mode 100644 leads_audio/system.py diff --git a/leads_audio/__init__.py b/leads_audio/__init__.py new file mode 100644 index 00000000..a87101bc --- /dev/null +++ b/leads_audio/__init__.py @@ -0,0 +1,6 @@ +from importlib.util import find_spec as _find_spec + +if not _find_spec("sdl2"): + raise ImportError("Please install `PySDL2` to run this module\n>>>pip install PySDL2") + +from leads_audio.prototype import * diff --git a/leads_audio/assets/direction-indicator-off.mp3 b/leads_audio/assets/direction-indicator-off.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..16b7b37679e955ec56c9faa2a5adbeafc171c1ac GIT binary patch literal 9140 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

+!ePJ&2lWeqBxx$iUD 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 literal 0 HcmV?d00001 diff --git a/leads_audio/prototype.py b/leads_audio/prototype.py new file mode 100644 index 00000000..ca020512 --- /dev/null +++ b/leads_audio/prototype.py @@ -0,0 +1,44 @@ +from atexit import register as _register + +from sdl2 import AUDIO_S16 as _AUDIO_S16 +from sdl2.sdlmixer import Mix_Init as _init, Mix_OpenAudioDevice as _open_audio_device, MIX_INIT_MP3 as _MIX_INIT_MP3, \ + Mix_LoadMUS as _load_music, Mix_PlayMusic as _play_music, Mix_Music as _Music, \ + Mix_GetError as _get_error, Mix_FreeMusic as _free_music, Mix_CloseAudio as _close_audio + +from leads_audio.system import _ASSETS_PATH + + +def _ensure(flag: int) -> None: + if flag < 0: + raise RuntimeError(_get_error().decode()) + + +_init(_MIX_INIT_MP3) +_ensure(_open_audio_device(44100, _AUDIO_S16, 2, 2048, b"System", 1)) + + +@_register +def _release_resources() -> None: + _close_audio() + + +class _SoundEffect(object): + def __init__(self, name: str) -> None: + self._name: str = name + self._source: _Music | None = None + + def load_source(self) -> _Music: + if self._source is None: + self._source = _load_music(f"{_ASSETS_PATH}/{self._name}.mp3".encode()) + return self._source + + def play(self) -> None: + _ensure(_play_music(self.load_source(), 1)) + + def stop(self) -> None: + _ensure(_free_music(self.load_source())) + + +DIRECTION_INDICATOR_ON = _SoundEffect("direction-indicator-on") +DIRECTION_INDICATOR_OFF = _SoundEffect("direction-indicator-off") +WARNING = _SoundEffect("warning") diff --git a/leads_audio/system.py b/leads_audio/system.py new file mode 100644 index 00000000..b93966fb --- /dev/null +++ b/leads_audio/system.py @@ -0,0 +1,3 @@ +from os.path import abspath as _abspath + +_ASSETS_PATH: str = f"{_abspath(__file__)[:-9]}assets" diff --git a/setup.py b/setup.py index 0117c02b..593dc4b2 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ url="https://github.com/ProjectNeura/LEADS", packages=find_packages(), package_data={ + "leads_audio": ["assets/*"], "leads_gui": ["assets/*", "assets/icons/*"], "leads_vec": ["_bootloader/leads_vec.service.sh"] }, From e77a3324bc43e8505f7ed34d15b41a4afa31f070 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 29 Apr 2024 17:04:20 -0400 Subject: [PATCH 2/6] Docs. (#117) --- README.md | 4 ++-- leads_vec/__init__.py | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7252ed95..6a8b4584 100644 --- a/README.md +++ b/README.md @@ -71,12 +71,12 @@ Note that LEADS requires **Python >= 3.12**. To set up the environment on a Rasp command, see [Environment Setup](#environment-setup). ```shell -pip install Pillow customtkinter pynput pyserial lgpio gpiozero pynmea2 leads +pip install Pillow PySDL2 customtkinter gpiozero lgpio pynmea2 pynput pyserial leads ``` `numpy` and `pandas` will be automatically installed with `leads`. -`Pillow`, `customtkinter`, `pynput`, `pyserial`, `lgpio`, `gpiozero`, and `pynmea2` are optional. +`Pillow`, `PySDL2`, `customtkinter`, `gpiozero`, `lgpio`, `pynmea2`, `pynput`, and `pyserial` are optional. If you only want the framework, run the following. diff --git a/leads_vec/__init__.py b/leads_vec/__init__.py index 0e4b2ade..b8d21505 100644 --- a/leads_vec/__init__.py +++ b/leads_vec/__init__.py @@ -2,3 +2,7 @@ if not _find_spec("pynput"): raise ImportError("Please install `pynput` to run this module\n>>>pip install pynput") + +a = "customtkinter gpiozero lgpio Pillow pynput pyserial pynmea2 PySDL2".split() +a.sort() +print(" ".join(a)) From ce7464bebdb6be23658eb17554df17bf23ed0297 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 29 Apr 2024 16:55:14 -0400 Subject: [PATCH 3/6] Added a new package `leads_audio` with three sounds: `DIRECTION_INDICATOR_ON`, `DIRECTION_INDICATOR_OFF`, and `WARNING`. (#117) --- leads_audio/__init__.py | 6 +++ .../assets/direction-indicator-off.mp3 | Bin 0 -> 9140 bytes leads_audio/assets/direction-indicator-on.mp3 | Bin 0 -> 9428 bytes leads_audio/assets/warning.mp3 | Bin 0 -> 21380 bytes leads_audio/prototype.py | 44 ++++++++++++++++++ leads_audio/system.py | 3 ++ setup.py | 1 + 7 files changed, 54 insertions(+) create mode 100644 leads_audio/__init__.py create mode 100644 leads_audio/assets/direction-indicator-off.mp3 create mode 100644 leads_audio/assets/direction-indicator-on.mp3 create mode 100644 leads_audio/assets/warning.mp3 create mode 100644 leads_audio/prototype.py create mode 100644 leads_audio/system.py diff --git a/leads_audio/__init__.py b/leads_audio/__init__.py new file mode 100644 index 00000000..a87101bc --- /dev/null +++ b/leads_audio/__init__.py @@ -0,0 +1,6 @@ +from importlib.util import find_spec as _find_spec + +if not _find_spec("sdl2"): + raise ImportError("Please install `PySDL2` to run this module\n>>>pip install PySDL2") + +from leads_audio.prototype import * diff --git a/leads_audio/assets/direction-indicator-off.mp3 b/leads_audio/assets/direction-indicator-off.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..16b7b37679e955ec56c9faa2a5adbeafc171c1ac GIT binary patch literal 9140 zcmeHLdpK0>+Fvtf#tegD9LA8wI1M?BV|bO*&?w|o@%EM(M$Y6^D%FhhIfv4y6eUUY zA~{5vah5}cq+aC^a)^*h#C-I!zkOYM?{Dw#+WY(d@?6(i>v`5%bI0f5Vrdg7Q4QB_k_ok;xo@Xr%x+2OB7f4}SK>F2)oL}2aE2LPE^ zKtfKANYpnmv9daF;ION!k56D|=(%%|k#R{$sj2Dd8JU^au3gW`$<58nyIWXz|9(kX zSw%%vRZVRzo88dR+}hgS{;aF3r{~qHH~sws1H;23A3jV@PJj9|KmX;+x22_(70x=6 zHOQ_%A+HZMn=F|1XICcHV~;@yXSs(40N^IRgWHHKH~{eBvH{TckUgeV)8R${pcS$9 zGNSC-HAF;!iaIB*GP`EwJl+XrA zvy^uD*rt`sBK1=a0!{mIM=5V$(cmFvN(z^W5rG1R1GoU`I_8kl@iidX?0&KQHGi;&fV$Tb7Hd$XCcS@I7Oa!1r2!S{*W)(;m(MZo_ z(@Clj3_m)O3rBe!^%!m`O?R{b=)iU$h?~x`-6?R>@}ODT5f!1RVHyZX|By(|fgwYw z_}nxdXbielqF1k}RWBZ2x*z?@aarEhr^SsNcRzN?pH}hAqa=1jc7@CT(B$bCq}Xkf z01DpmX#t!K*>Q+jHk3ti$0RB;ad)wU158~E=A&w+DmO12T=xQZu02r@od^OYO7ZtF z0bg#EH=D>EE?=(XE5WSr2#{~R?uJt$ujSQMLSQRX(B!E1E!dl z4o8!~I(}X4V;3&Gv5LPL{I#<8Y?e9W8K3pJI#lWCCBb*+veRlaw||a#;x;d41%Lp+ zO6?sT3Q80@+o=qr&p+M4EWmI33M7e`@1)aZSoJ73g%+Ev=T&f4sEvg|I}vr$E8rTw z2P?t^9cJ~u3#lQ%T_MHqgZ)I0q$7CuOZe~o=!<}D=PX~O)zcT4hSu9p(0}TG5CEaI zIO^7;4{&Sxrvm_F#?8!97c9$=o+i^*6NlS@WS$_JxUmUWoxbTfG)<}SxnoM$Z^|V< z=si2&6}_uL3lgpNQcqHla2B1Nf67XYhtf&e-!8%)WFbQ=#pB>4UIpEn5IIk*>`hIL z#@2Y=M=nEc7aPj>A`vQfM5dBB@eF?V!zZ(OQ`VsjcZ+xBA1>)#^R~aJqx0nof1#Fa z!^_hFbkHm-cY7l`G5(%*Z8<#k@r`r3Jm%l#{o;P{oGV#z-tT|LVnLAe zgY(*VT2COu!s-pcx(G^?;evOkv?86%B3UF9QjWgZ&D6D&qqA6AGL|wR0xM?_4m7rz zw@`|Q;GrfeYKuB>3LUSSZLC~M)U%Po|2plfK-=4?EP4AVqSZ=D8l|7POSPRrVFU_9 z37F%0=>7;%Go|pc_~iJu>|VSMUT#EG9C!FBf0~RWr2n9s=-%AHde>h3I{$w_7J>~e zr>eac*Xs`efP`i{l>Ge_vN!l2c~ElHQGU0{ivOhlozE!J7djHea;U@f^YKK_z9LDq z3p0>P=1oWB%qj6u^KNY{RNloX6w~QZJ`rFBRfNdeU}cy^v4Uh?dZRI7Y!suc&$VlZ z#5-Xy%l7NQg=&A5iA&r#rJSo+EIW7J>uk%wD(9W`Qr1@`fC%j5L;@5I;0E&Gp=Y}kLD_N9Bd_1y znTw@(bU9Lr^HE|6@VvsZS_a+14@aOj3Bh*7*LUeHpAVm)6yG^|Pr_fTQO|DMv|bd~ zovcjdV{cBT3$^MU99GTfx@^8f7m?$HKA{Q>iy;gmNckSYZS+d4e6y{v^urm&-)U30 z0R_&UUS3WyD8kq?x+0*ZLa|U$Fe%$Jx;67%0xlI#Bb-puE(t8QX?~$?&CMWYli{H_ z3KwTNlJ*t3uwb}XqW? zjxcg>+q?3MBcx)t8=aPt3Aj$ZAhBfQYj<|es^Stn6*Dl@x>uwSVB1yvgA#Xg>=yyH~ceC$DnrLI}>InUpH3Q|hGR$U?u$OSsb_zl5YE1oS` z80wvz>F02kYpXxholF9=qbf1j9LDz|oNIV=N?n*Up9x91jt1uoc2YNiM0#QPcaA$U zb@5X0<|ZWf<1zTDOwMvJZ630qrn%3)I&D+WsM!vJ-;CAZhMs+3ZAgC6L%zCo@L65z zZgG=&=ZEO?+yk|IS5odRrTe;sF#<+Bb5W{Fg?7T%zvwJ<5Wb(g4Zl^`b@+{%X^G(5 z<<~7H;*rkFH5cBko_{QS{_VLDLk{OKr&9?a4deqnkZ74&_w@E=cbU9B2y^kGW6z&7 z2}j8f1Jpv3>?Q;7iDVbn;NU_XkvbKPD>s*FKnhzpS5djRD|rf0;GKKM#N=%n^1e%= zOGMT6txe64N`A)hDhe9I)px^K>p5&jF86LjJtX|44(T%=)oxx_`&4=5^7-u-dheg) zqy9u6_hzJ(=?=Bxd!`nLDgN3qIP0805$^qKWP9E zV2n$hmpkg5GUNK{t{EfNBe=u#8z96MSuCC79)ThA60|o0z zzRi5MxRGO+IqZvpfH4NeS6f;zG;AgkjkzL;A@czd>9^*PDqulIY`e|#*p{a=Aa_I$ zB^(q!I<7&CsD>S#)BdIu+TN!zMRw?QPM1T=BT{$YyWD3iWdGh2JA#xAF=U($)t{F>_Ln^YY{Z2}%qitn}Kq2qVcN>LBtGQd0<;SglF+(XA|& zSzs~k&~TpkXpd-R#}zU0jD17w%SQft#|E7=BZKcb-Tocx_&o<(`@rPKvmLl^HokrO zLj<>_-=n|frFu_M`vT&>amL+hIji$04+3iw-y_TG=LTiaordpES&C7dWg2Z6_?)Nq z)cZ=>W<3;ed?4jFvu|)Ce}Pkxx7ih=;;39I`8Vn~K@zj$mVBM`pddEE@rYI!I2Gse za@CVrADP$z8pBV+Km_ooD>7+c1FW!qb!lP_dDU~G$`Gs>q&KnGI7PUXZ;81xVTYa3 zu;`PJ71J9>I5+@OZ%}VuBj6AtiNxHt3k_vQvnlQ^Cb{+5$5F!Fwa2znp8%Iqi8?|wyL zb6`qC=uLk^8##Zk?c&QKyW~jFAx6n_IkB5kN-?|kg;j9!0SMBS)A4a_f-yO6l>Ugy z;BB%tE8*gT0rm9bHT5{6aaLaS=#UDglwfDQpbubT_xz~SJ$qP0UY!c#D~(a{c=3eQ zijKdGX$-d$aocxrQW?WDaZa*#1`Qd=Sdam5V&?$>`kabJd^S^fEQ523YK(a-0OL=;;{Xpl^nTY4I2{BeP>m)}@dd7Ymb#OEw|^QlKZn@ff?0T1M{mZH;)cAO2SP7jFJ+TZrH;{3U)-Az9wb+n2bSzq!{g838C( z#a9fl)8YHHRgv`XsG7`%QtQm|xg@lpU>xKM&t4y;GD|kd1kvaKiM;hYWYq3fOwcUM z(rK;60kbhH-H&0+?%Ksef$lboMR5Gv1Ye4*I4o>W^Y-aE!__D-PzU|ACf7c0wRVe< znTXV~PWpx7_H5EASsr~JWqB}yoltg?LK(SmeD)j{1Dree@$fD?i0O;9ZzYZPgYnr~zRCWI zy~hSWNO-2ieK)J@4Sw`9u?op7@luXdhj5lVIWShN@0ReCS2z?loA>S8A^AGg-e2`j z%Ur@4| z?U>p_2ucMra*EY63xN46CV37ltYECNh~h3#-VWX;CI+XHt-S3?cdZf4$%pvwBU*yL z1yq?H+%df5XX)BD+O4}Q{Gabkq{_>7rMHh|OZstq1rP(n~dlu2vLe%ZT%Gx%9 z3pf23)T<$jd1sHh(nmDBT{4!=c$(AsS}8KEr>-T`?jCa0^$)T6OUFuAI=PyS~6H;~T zc78v_lKXCuMt6;JH}^LJthx39PMK)YN%DA|SUwjIPvy%aL+2aCQx&oH8N@mTiWMp@ za_HTc?U$>|$Kw-}18P8L_P-LK_QLDQzbT?CzvV1z(N;k7+~SRAbaOm5aKidb(M9gSrmlYe*Z&i?bv)ldbNQ%-&yL}`8+f3) z+B}Iv9|#+9|4;e;ulU7T7N)I4%vtfVWgI;QH}G&Ztl_D-^AF?r*8u+sZ|n9a1ZD$x zjM+HB*bVz@OX*c$eUt4^o&UADzv=%A_J=Oa0)Xe5LHK{$&)u^Blgf4exA6rL+wGw}0oezx%t-+Q*4v z3I~ft)7#6-Zec480L(RbfA}hrp{b!UiS+g4-~L2%-v3bh>s`Odom&^q$SnNU0zjw$ zD!RHP(i#e7<3=B!AUZuNYHv);(W7y3iN}wpr=K{Hlb>H$SX^3KUVi4x*_xWVx(k;s zUA@}Sa6=$yYHDq5@9eyDr@OcJ!Gr$(C(oV&tp$fo4n53QB2_gPD)7F3ttf6qtvG#Pg7YTy#Pkl%+6XEnBSvUlc zG2(*pqZw;NpBHP`4Kl2Oak4DjDr3!OG7<_%hXA0-BC&>dLw8&nk47=Z)#O?cp?$$^ zc4F$G0TCPndl-(f309skc!?%d6I=dLBcuX>!>N-X5G@!koMa^fA?uOW!U)+^Qz=MS zp zDl7#ME%78q7Z<#2&Q`RCv6$WEkfC@|GJ#P$a0%cUlRYpBVf{UlM_cV{NsFNHQx`SM zD{`c|U!q=}N>GWR*u?}~Kr|cb8?;LZHeBvX?x0MhI#kq@j~E+TZCy@q(*Mc)3w_}I zDfiW*U#vtAq9D+en>;wY%gE@sD*ZO88*K$gYrc>QRppkxM)xS8T@<-!S+uHrOPr#! zYooN34qi-0K0`+%(W4kEVTMNvN`Q(0?{{?tl}2f_PHK)dy<;cs5Sd1>%jyVyDeHoC zi~8~`0tpW^NS}Y}qLbmKEYrKi$`%H+f z#Y}nvaon!sBiBPQxC&$3+e@`@A9?lZ=o^678f(Lfi6dMw%FhQwBfQYiUWu_mGzTWR zGSm!SOeYH+p$Sn_1`ODGsCK*_HiL-eXTupQJ#~@OBuVlC(OfCLg){Zg{qFKTjIa6^ z0?4vgGRAJB^|S^3FN^{B%EXoO_-=+gA79s_!#;9KZc~CSp0=i?MDZP;1=*bzuFRAo zCh@8$(cT+5n(F+Qy&pCbG6{9h?L@JGZ5&$gnDkgzX$C8P{5xe2EMuAsC6< za2{@ftk#MeK)7yb^TeLhf)k-lk~p=D#4tfKmI?i>#Logx+l0OI}F_x;f2^f}mlb4KLQ#?yF$EMG7rlzdA8X9sB zEczP&5QPenvD=ut@LT^j;XEggFs6Pr-RbI$C)!+tZDG-{IG}c{*~VNJo^=UhM30>K zb=7_~ZC4dBlBY7%ze^Uf`=u$ec6I{Nvs#ghGereeXCduVi~-pC`=7%zaO>0MYqCy;{qbC3Y7vw8dN( zBi17gGS+9?3v_(*G1B8VCrDt_2XYMzv2HYkf?|xqzx{fKm}>2ns@>Nv=Uq z(l)h-cNF|4VRSx&7!uHp9hZ=dhXF=C4g!iGWMIsx^-xabJ2ehatV4St0U8Ieev*oTf{`{)I_1^ z-U4BHD>j5j7TB5%p2oiIakNKdD<|ZVR%Bxi7OEsP=jUP$un9T)iz#5a7B)VQQ zvc-E}gx_!FV-M7)souB60s4T#jcR(Yr^9jDtj&<3%RAM2*~_uIURNMyeZ8ihF#SwQ zfs+KW4WSX<(%k$;X)S$JPcHfy!anM}MXwUYY3nn;H)}>JE>`7eY^vd*We>Aq5JK2gKB%b^yW)YL43{kX7R&9cwH2t#oZU*O9Gg2kZrD z8I95et!DofLwV0lN{?LJC5oZnzS?>I-1MBd??~mYtm!i+!kiz8LhXg*^dM%c{_5v= z$@Sh6YY%nZ*^gpdDy-hToS{YZU|yk__mDr0Bg8cD{qD z;VKHw@*S0a@t(X^lO}<{(f%x<4Ap9M=warEBk>+ zN|QgO*(l+frgpj^v=7_J%RTjyb^(|aZkWzMMjvz6qFZO3ey*=Id(CoWqJX^M(A2aq z3^)$YVy|hpmur?nv2i^~&Q2F;k%{d+mxab0;Ul){S>!m?zw16jf)&0NNQD^Jq4v1 z{L}IKVBwuB>GwAvAQdtVb6Pj%D4@xQwh!@Jb^6tUTEtr`&1$~YqfnU4)4J1>*?sTX;EYS6B#YwGBrqDC`fnfK4}>t(_dU%lN>%Guq^*D1-0TVcedD zUuWMyZW?Z>_ZgrE(KAbWwj_r6-Fh2wB3RF)z@$gc zwqI@d{5B2YInBEswcSejCl3Z}GoL&Q02yYk%Ll2gvKlA5qqgT+$F{&SSbGz>>s&X8 zb6JhT#3q|M2XQJ&OUxvA!*RU~{*IUr5_j$7=R7&Lu(diA`Axa|wV?!$`{{nXl<6`> zQD?N4#fcdWzw0d@S6zIV#GJJ$n;L5V?fK1t;uxPB4_8lI7~CR)IS0N0O8aa)%^E0o zG2Rq#ms^Q74#-xg%PV9@xpK7{O^W4YDBElt@^ybcVQth@9(=_7O0bNoxQt(wYrmx8 zeCxxw*{FQ~srJrK4MN%K-lGHVmz0mb!QX5w2wCLwmNBJ6avI4=U*aP}5$M%~RTq7m zj}nXaJ@ChtsS?X%IZ!C{-!iWvcE1rl#!dIjzO1D67xQ4OFQ2D+`L_ zJ$e5u8KvaDRm9p-1A!*Lby@j))CT~IQ{sZd9@ZBRA5Gr2Fpy;z`3%D+J4sI4b7Pjq zqg3fl!p^XbOZoxve{g_;f+6jfcfvby`+~QLTR>^krz0HuYAtpH{L5ImqG>ztVRpRA zofUg)+6z$*B?Bhb%~GM=j~Q>sMc4G-6+F)Dm6M+=*3VOaAJXSvEn1CzY0)=ka`*nl zVEBg}Qlmp`BpP7xqI#lac23@h+>{5@#$*i9Y3|oQ=L_j~g5@<))k}OlLEdPa)SSE7{L{w zTTpRzT(adj@#c=XTEhgSoAnB&^~SJxWg0J{7k0}f>SdL8IntCKnKeBZkl|(OKa>`~ z-od5GczXnzMY^imBdsW!qtoXhlQuZVgTJ;{eDiauh*bROYX{u7@s&)gx_o!S>TwYe z(`2ofSFgwNUhAzoJ#5p{nvgBdzITjO=vXc_gJY*Fxj>Mx&3^>(x~2VxZ1aI5!bkre zJ8PHW7UkCYEZ=3v;%8#Dw=^EG%RT-Ia*YJ!ASQ9w!Gbmg9b#R#qZ2ZjvMogn8L>8N z1wgF7}4zFIGcv4&aM57mu_%0uC9));`9qBtSjdy?E0lnzk8ptRkUiJ@+J3+OI zlSEq1zn^wGH%yN9)MT8QmxSxVyES3EjKz~#-5pISDYCYU&pV5n{E67QJqNSoCujwx za`gydNe@tp%_&SF{vI;VwtpYRe-|dXG9WDz&*3mOeZb4$E3Pj$SdnJ8#`om*H;P-O@fJA5tARM)BREb)t63#>Rww3>h9ymw zK^(p7)Lf_86~G?RR#*nuO3lhiRaKS5`w=G0%6UJS+505cuM;nd5rAM2{d#!>oSSDZ zjt1+zX%*v7*hV?4;!ui3D9vK&{@&sYM28$gn%5gX{J1FIcz>=X7{f~(>fp-j#BE(z zZ=ugHCzS~Hb1{F;FR0JV<)guoOV9hblImd&-&F~BdwhNQVM!kvRL7ouICP<3{7{s8 zP;=|w9X5ev5R|}#K`q|Nt~w1bO`xy!S`NJT=o0Cxg@at{4~hq;dsJrQJr#8BpL?2^ z(VfH?78WQxY}0Qz{s4Czmv{`!oLi~3j8X?3YZYv?)ijnrunZN})$WP>!ytb>7|>P= z+t%b8))gbl11n?(@{)a!7SY#XUl#jo3^LJ;vzv?g)88Z_n5v^;kwxG1d00P0_LzOx zp|%C?711SGR?mOk7gWPF!MWDw7V^C@ zojqq)1teZ`@hFv7JC-sleNd^k1V5c(xgp&>7Q272ODU=rKYVbpzrH{wPT=h4{QZ~w z9M#5D8dcu3G#;JXZZO7AXS!N%wEMce=JQ=y*(O1>N$zRv*y8H(n_qTd&Om{D<)2qq z{^#XCxK}hsq0d4le6e;1{q-Zh`3aI5jH#xdUeepYB=8@^|G&C-G0%^X32}MKL4W>| z?}-yUq>{DIFLD0b*8f9p|Jbf*jzFJBr2)(*<8b6rUL>v{``^e gdp&(u|6jkqeHZWh>W}!}6Zz-*4?h3Q#f3g4o#N0E| zPZckxB&UGK|L^Aic{@3_|9@Tm|9^D~2)RhV!%BZ?0)U+pfa2uj*nU|9S|BC85tX!keZs6m0Mg~R#sJ2+tAS5-1_KIcXwak)4{=!k@4}#>FL?o zR|^Zv%PT8uo10r(J3G6dKY#ghaCrFR$IqX~fByXad-9JGI?3MuBl+LO{~e-`mH+eA z&PmEI#q#8M!v_GsxdKxTtN=n@k1@Ei1|-gVUCVio1ePe?I#H|E$)^7SdYqVMk3=Gu zrs)?g`QKOub2L{QBbQB)-m=%<_VDN%$j>&naJ!>cMEi_WO2j-rSv=4{Z)Sa1{$OH~ zFg5hyB=zKPWqJZ{EPWpN~SM~1%b%?cdSJ7Lj}x*s7L)oA>=Y=C3RYxvi*E)uwI;UdT?n>`7SLB z`fXg9hGZoLjp!$t#||!yOJn??O z=lEfY_@h66Km7Ud_r$7M>qq47gwr32zwi&aft`!q0^8fY7f=53_%r3tcy)0%d*3)V zry~Y{0lE}ZbED|!`qOoZV~S<ir&=iJV!v;*723SW(WV zT*enBB5ESeoEG66o;2}Emt5nzbmiEE9Q7I-1r=`!15JXSiFw#sO^0)zvno58@iFBu| zWQNDBQ?8rw!_1PLGRiE=E&skTo@6g}!Cc*}C%L@+uqW!azX><@{8xhQq}cbPg75hJA59JV3O9h=dTc$2;@?ZPcS8h3(|Q>TM;&5!P6zC?|K@>rp)P9-|6S{P^XA-Zj^M2!%fI(>NB}H_^Zg3Q zh1uE2gv1D3#9EYyO-DF_^!gHrT^& zGHf|37@lXp7XtH@iij`;#=lB1gQS&?&rT3m{CHg8>KHh^Jv_>1;MM0 z%RxWvc#dOUkL;fGHU(UIA}{|}{`1MnU(Kg09>#P#B?(d#T>;6(QaI;6zJlDGToiql zgr>;Gtb#Q$>u`;98t*DrvI&9LmOkWp5-h^cn=Y?;29_oSm4*Ge6a0(9@4yiM{5*&N zKx+sOi0_&FI8vvBzuoccp{WNBIr*s)Ul8>b47oht`iPr|GYszebqm6;VqJ#JxeWH6^V{_%IgkL z3JU@sI=^57uC8BBWaA;pAbx2=c*8v3sF`LtM4lm1hV~1iH_dUG6IW-0^S3d76zauS zy>2usA?&}CfQl9XV@C!hp!L%@PL6AQ-h%QilxTKKGm@r>>9;Oh$g(Lv75yCW(UX7{ zm7=M*hYmeTq(#G!V^4@#Y;4HuF!MffltmhnfVox3ZeC`?&XLMs&R4*Vn9hOzzMFFzJ**kOFs)u z-d?$nFI_8+0+|XtUgLjXd3XBl-eClwj()lVa5%`5x$ZTDMn4}>_2aZ8Z|&(pBX#Zz z4X@S0lCZ&jSv+zb_Wm~_DL2f-xsspVH>nux@4>2RnuI4#-()F>`76it8*7xNV?S87 zg4$X3nOP{J346-eHz|s#Ddekag@r4me^isbw!@~sy9!*2E`EorzDzaLgi4$mX*whvblf*%9qBK zBhOF+(c8jx<>SQSi75WF2E}5LNl=n5#xq@iaA@!!e>Y+IhVmx8%d3*cBI$v2{<7{r z5xpGcQ^mw4rZQRI!IB6|M=;>0iQk5;D~BiSEo1Cu`Y%r=5XP?g0(qI2G6pfE(33=T zkz^&QN3HObNF1rsz<>GpO@Ws62chUd=lc!c1sXnU3y}~|?3yr6M3@DgfCo1v&0bT(9t#7QRm{GNv;sJdltN*jzvhWFOB2V8B(hX!1E~T&rdOXC@SZsW`hl5gIV+UwfA?1Wj^#JrNFH0< zu6Xy;=NZC6R=X}??$LC~eFM<+^7z}Yy=H++g;(C?IM3&j=#CVzKcx%72+?@jv|Y8o zO@HxV8|F(SnG?+?b)Rur5=s8azCDzU2-EC*&C)mfn2fp8g+w1&dtELzRP}M5!`}~J z94#U|ANWNDhRp@dxe^G&zq%}2yJZ$14qD0OnXd(LnJb~ypX>7?N0Xra+6gF#LH=;K z4;H{jaN!s9@W!|CLkxH-3Wf@F0-s8udJEFMDq1`EubBSHalX$_3a6v2(e33`X#>3m z>F_{Vw9_3SI)58vZuycSk#VM0~vb zIK+AtmqeVcOfRmfiapwHa(T3<^D?XQeV=*f$-D>^fb_3xD9n|f%}-Y5cTxM}t}I}I zUpj|x0kMnG*r6z0&{C}(ABl=y;6~^du^lF8X5G_wnlmb#GpXc%vis`Va+h-ezmKty z#m$7@Bmj*!6k1L56^*~QabDb$-HpLVamnYKk0DBG+Vd@gxWf8~SGC~#?nppP1l4iCPt^yEyh_WWe+&%749A#fUn+5j3#67WGkBgS(pMx%c zE0^P#g4tbla>JbsIUmv*s)BTc57)9eXXu);R*C9DAOf!KZwY#K&%;Mq5BeM79mx#H zmz9GLS!QI4;m;IwyO>zp<}MQouwxjFhVU1!a66yB8yn01p2|4c7kZPli7S?wFNL3dchhs%gEaV)UA_)YEG9~F`GMu2-s;026au9Kerl##b<`0$N0A7I z=g>M_X16U%4lw)|9_)$ya zJ6&GhQ@OrbmhcfU^Vu45LoBNwH(o z>X=6IZPxale&(%`^z{Dp;&&y6P{wNG@|&sKP5W?gtMEV=wm%2ur=ec!lotA_x`8~% zz{?2J8MpbTUvE+Q;vyrrm#!_I9cG&HrY;wM=Uq5&H)REtUPuwd^;N*7z3`LwG0TA61^jXhrLOAiPPe4;Z*v6Gj zXkr~$;L12)4AGNN?60mQc+PKW8d)lGJzeM&oWQIK95R3ZJt~ZOwpLsY0E#Ddj3hVW zG;50N8aVWo+eo*Jb>J3wB!=5i*-*TK3I5m6(EhZM)+s*&ovSn=h^KCYo)MX2&GebO zRBJQE`@}sGY(x!OKjKr!beq2*KC^#VdD(F38Q`{^{2X5Jv>oNGpED*icVHFzTW#$~+ur6{X)GN?G4t zl65O%YNeokHq#QB92HlG>e-*QzwwOK2NwQ}JjLZi$^Ocm=|bFK{@#^!IensC7>1i) zEUKm3b)DmVx)puEi7tk#`+nW7O@YI2mlzwTxnZ5AUQnP*pAAYlA7#pmoo;O8YHjS2 z+2qy{*kH*q3V3cT^LZzqT&jmZwLe(NL<0{X2G}|$5kgyYumjrnnvM@j8^ejpV{Fhv z%-GPk`q$Ro2c{GRf&{(7IW&@#1BQd4Ma5+GRW5zc>=&_yW+27PSRXq$5`x|B+-7|@ z7&kk^qFg5*_>J+rw3%(dAN%DV%JbQh>8vfqA#QxV0)82(-XV`yAu8$Y;lVn0$x_~1 z=kRFYKWThxdO*YsdJ0fGTY>Qh9BQ8Ey7MDR)+xqb(so)aB+Ao z@H$IEubP~T2+$5!Kt&8XPxjkJkK|5ofaXT4K+AqhmObU`LV!Xz8!-oy*z`(wgBsd) z@IpJ+i)u=HWy`Cg=A^UZxj3;0Ca+`9*9-V7lCn&CRVW|F6bBn|SI&aO=A zL0x7q`s68sXTc2XY{Pbrdb0q7jTFA~pMD)D=S2$|%`PuU8>}sy3BM$Zn!7IW&wpW% z8-mL<9XeO4zy>#;-C#<_1hdoLNy$DNNcF!-jqdY*$>@CN8&PwLVdgkr5Cx9>jWi~2 z4Ispju8g5?7i3Y$7tvF-skBE4Y5jBOC}6O_pfW!VHb5O&5;TQ7r7?_>)Tur^6gWU} z0;Ua9nu7*PG=jmT%9MoHj0QOXSsK#h>Z~uzblNJ$-P_ih|K7d1#WEWPxw|o`@ppaCkH#h)6( z^Sj?baDO=VbPKf$r9PUVxiZiIrBDrFgt2Cr{;(ZG+T<1C$^jynM0EwNP(y(F!S4(! z{qJBk6SwvICNkN-QOzNPN$8j9gQ!KG?B%AbS&qy#1EI|S@c)*c$IWMKx4gh->#aT> z#e5#M6(;Dg3*hXLYj1l=Pzoo#j(~vE9)bKvBo9zG1@X_&RkZ%8{c+LDRP0$#ZiYGt zH7RJrKZPba;A^Ta&XpwWy=ImoRE@?!QlKO#sk{Awcdqbz0(s0Bwn;$XeIW-7+2VLK z)HMaMqHB(H`5P~QFM_p$r(t*t=m8Y3hc^K$fw5S;FrWv+OW;|+cfkZkJOhB1WVms1 z@{>e_2@7*j2|V0|@(>VSiw|gr0)nETjq7eB5CC^VPYBm+A9cCUd)~Y&PsekgB&uUm z36TU>{}LhF15fEcIC*!}=Os{<)f*Ny^8jb?(D6tJ+b>=g`M-N7Ctr->PZhl|lsWhL z_kRkQvJAqvVpE0XH<6Dn(6i0|?-&emb6-l8v73EUd_yd!J3j9B4GEDee}Ax;zWW*5 zHafl@`NPh7_|Ev&*A$76h25X&zPme}_awrfHv9?ySAW|iu>@wD#NVKjT0cllKHo+Q z`d-)nLnBF@We$ky$c9GVqgyK|giNSP(XX_Y1o~fz&Y_&7O-gk2ia9wlSnB*4M}#xq z>%rjS&^q~)6`XcIV6M)9U*ebT&(Uv9!8KIt$5xhb-}7tG1r!PXp&J`G)X{8_{rvB&j6un$3-qlMxxki8JKg z8QYK2@8}pvwx%lmmR{Js@#x|IMWmCL@AAn_z77Il7Wuh

+!ePJ&2lWeqBxx$iUD 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 literal 0 HcmV?d00001 diff --git a/leads_audio/prototype.py b/leads_audio/prototype.py new file mode 100644 index 00000000..ca020512 --- /dev/null +++ b/leads_audio/prototype.py @@ -0,0 +1,44 @@ +from atexit import register as _register + +from sdl2 import AUDIO_S16 as _AUDIO_S16 +from sdl2.sdlmixer import Mix_Init as _init, Mix_OpenAudioDevice as _open_audio_device, MIX_INIT_MP3 as _MIX_INIT_MP3, \ + Mix_LoadMUS as _load_music, Mix_PlayMusic as _play_music, Mix_Music as _Music, \ + Mix_GetError as _get_error, Mix_FreeMusic as _free_music, Mix_CloseAudio as _close_audio + +from leads_audio.system import _ASSETS_PATH + + +def _ensure(flag: int) -> None: + if flag < 0: + raise RuntimeError(_get_error().decode()) + + +_init(_MIX_INIT_MP3) +_ensure(_open_audio_device(44100, _AUDIO_S16, 2, 2048, b"System", 1)) + + +@_register +def _release_resources() -> None: + _close_audio() + + +class _SoundEffect(object): + def __init__(self, name: str) -> None: + self._name: str = name + self._source: _Music | None = None + + def load_source(self) -> _Music: + if self._source is None: + self._source = _load_music(f"{_ASSETS_PATH}/{self._name}.mp3".encode()) + return self._source + + def play(self) -> None: + _ensure(_play_music(self.load_source(), 1)) + + def stop(self) -> None: + _ensure(_free_music(self.load_source())) + + +DIRECTION_INDICATOR_ON = _SoundEffect("direction-indicator-on") +DIRECTION_INDICATOR_OFF = _SoundEffect("direction-indicator-off") +WARNING = _SoundEffect("warning") diff --git a/leads_audio/system.py b/leads_audio/system.py new file mode 100644 index 00000000..b93966fb --- /dev/null +++ b/leads_audio/system.py @@ -0,0 +1,3 @@ +from os.path import abspath as _abspath + +_ASSETS_PATH: str = f"{_abspath(__file__)[:-9]}assets" diff --git a/setup.py b/setup.py index 0117c02b..593dc4b2 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ url="https://github.com/ProjectNeura/LEADS", packages=find_packages(), package_data={ + "leads_audio": ["assets/*"], "leads_gui": ["assets/*", "assets/icons/*"], "leads_vec": ["_bootloader/leads_vec.service.sh"] }, From 36837ae12aa2bcfbf493f6776074d2a217224672 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 29 Apr 2024 17:04:20 -0400 Subject: [PATCH 4/6] Docs. (#117) --- README.md | 4 ++-- leads_vec/__init__.py | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7252ed95..6a8b4584 100644 --- a/README.md +++ b/README.md @@ -71,12 +71,12 @@ Note that LEADS requires **Python >= 3.12**. To set up the environment on a Rasp command, see [Environment Setup](#environment-setup). ```shell -pip install Pillow customtkinter pynput pyserial lgpio gpiozero pynmea2 leads +pip install Pillow PySDL2 customtkinter gpiozero lgpio pynmea2 pynput pyserial leads ``` `numpy` and `pandas` will be automatically installed with `leads`. -`Pillow`, `customtkinter`, `pynput`, `pyserial`, `lgpio`, `gpiozero`, and `pynmea2` are optional. +`Pillow`, `PySDL2`, `customtkinter`, `gpiozero`, `lgpio`, `pynmea2`, `pynput`, and `pyserial` are optional. If you only want the framework, run the following. diff --git a/leads_vec/__init__.py b/leads_vec/__init__.py index 0e4b2ade..b8d21505 100644 --- a/leads_vec/__init__.py +++ b/leads_vec/__init__.py @@ -2,3 +2,7 @@ if not _find_spec("pynput"): raise ImportError("Please install `pynput` to run this module\n>>>pip install pynput") + +a = "customtkinter gpiozero lgpio Pillow pynput pyserial pynmea2 PySDL2".split() +a.sort() +print(" ".join(a)) From ccdf98811c065725e4f6e1db60af6343ae315289 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 29 Apr 2024 17:11:50 -0400 Subject: [PATCH 5/6] Bug fixed. --- leads_vec/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/leads_vec/__init__.py b/leads_vec/__init__.py index b8d21505..0e4b2ade 100644 --- a/leads_vec/__init__.py +++ b/leads_vec/__init__.py @@ -2,7 +2,3 @@ if not _find_spec("pynput"): raise ImportError("Please install `pynput` to run this module\n>>>pip install pynput") - -a = "customtkinter gpiozero lgpio Pillow pynput pyserial pynmea2 PySDL2".split() -a.sort() -print(" ".join(a)) From ba9bff43b0581564b1b147cd85c34fbfbf5802a8 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 29 Apr 2024 17:13:35 -0400 Subject: [PATCH 6/6] Fixed type hints. --- leads_audio/prototype.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/leads_audio/prototype.py b/leads_audio/prototype.py index ca020512..1dfd0899 100644 --- a/leads_audio/prototype.py +++ b/leads_audio/prototype.py @@ -39,6 +39,6 @@ def stop(self) -> None: _ensure(_free_music(self.load_source())) -DIRECTION_INDICATOR_ON = _SoundEffect("direction-indicator-on") -DIRECTION_INDICATOR_OFF = _SoundEffect("direction-indicator-off") -WARNING = _SoundEffect("warning") +DIRECTION_INDICATOR_ON: _SoundEffect = _SoundEffect("direction-indicator-on") +DIRECTION_INDICATOR_OFF: _SoundEffect = _SoundEffect("direction-indicator-off") +WARNING: _SoundEffect = _SoundEffect("warning")