編集履歴一覧に戻る
Hyodotのアイコン画像

Hyodot が 2025年12月02日13時40分48秒 に編集

コメント無し

本文の変更

# 外観 ![全体図](https://camo.elchika.com/11255ceb1f04090d7b248e8edb51918ba928d890/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f31383036616437642d666233352d346134642d616461642d386633366463383234323264/) ## ADSR入力例の動画 Facebookに紹介動画があります。(Facebookへのログインが必要です) https://www.facebook.com/toshikazu.hyodo/videos/1216092900384973?idorvanity=247733226639836 # 用途(課題) - この作品は、FM音源IC(YMF825)のパラメータをグラフィックに編集するための作品です。 FM音源のパラメータは、数値だけではイメージがつかみにくいものです。 - ADSRパラメータの編集は、ADSRの折れ線グラフのようなものを表示して、グラフの偏移点をつまんで操作できれば全体のイメージがつかみやすくなります。 - 音源のパラメータの選択肢もパラメータの番号ではなく、HzやdBなどで表されるパラメータを表示して選択できれば分かりやすくなります。 - ここでは、FM音源のパラメータ編集方法ですが、相互に関連するパラメータを設定する場面では参考になると思います。 # 編集画面の構成方法について - FM音源IC YMF825 には、16種類の楽器に相当する音源の設定ができます。 - 各音源にはBO、LFO、ALGという3つのパラメータと、17種類のパラメータをもつ4オペレータがあります。 - 4オペレータには、それぞれ SR、LOF、KSR、RR、DR、AR、SL、TL、KSL、DAM、EAM、DVB、EVB、MUL、DT、WS、FBという17種類のパラメータがあります。 - すなわち、1つの音源には、3 + 17 * 4 = 71のパラメータがあります。 パソコンであれば、大きな画面で、すべてのパラメータを表示して操作することが可能だと思いますが、今回利用したタッチパネル付きLCDは、画面が小さいので、4つのオペレータ別にパラメータを編集しています。 - シンセサイザーの中核の部分は、いわゆるADSR(AR DR SR RR)のパラメータですが、一つの画面で折れ線グラフを操作するようなイメージで編集します。YMF825には、SLというパラメータもありますので加えています。また、KSL、KSRというパラメータも含めました。 - WS(Wave Shapes):音源の波形の選択では、29の波形のイメージ表示してそれをタッチ選択するようにしました。 ALG(Algorithm):アルゴリズムは、4つのオペレータをどのような組み合わせるかの選択ですが、これも7つのアルゴリズムのイメージを表示して、タッチ選択できるようにしました。 - なお、素人の理解で作ったFM音源パラメータ編集プログラムです。間違いや勘違いがあると思います。ご利用される場合は自己責任でお願いします。 # 概要(作品全体の説明) - 2つのPicoが連携して動作します。PicoMainとPicoSubと呼びます。 - PicoMainは音源編集用、PicoSubはYMF825を接続してMIDI再生(発音)用です。 - PicoMainには、パラメータをグラフィックに編集するためにタッチパネル付き液晶(Waveshare 3.5型静電容量式タッチスクリーンディスプレイ 320 x 480 SPI接続)を接続しました。Waveshare社の商品名は、Pico-ResTouch-LCD-3.5です。 - PicoMainとPicoSubは、シリアル通信し、PicoMainで編集した音源のパラメータや発音のモードなどをPicoSubに送信します。 - PicoSubは、PicoMainから受信がないときは、MIDI端子から受信してYMF825で演奏するとともに、MIDI-OUT端子にも出力します。 - 紹介動画では、MIDI-OUT端子にポケット・ミクを接続しています。ポケット・ミクは、USB端子ですので変換アダプタを挟んでいます。 ポケット・ミクは、チャンネル0にミクの音声が固定されています、チャンネル0を出力しないでポケット・ミクが持つGM音源を伴奏に利用できるように工夫しました。 # 主要部品 |デバイス名|用途|接続方法| |:-------------------------|:--------------|:-------------|:----------------| |Pimoroni Pico Plus2| PicoMain:音源編集用|PicoSubとシリアル接続| |Waveshare 3.5型静電容量式タッチパネルLCD|編集画面表示・タッチ入力用| PicoMain にSPI接続| |Raspberry Pi Pico | PicoSub:YMF825制御用| PicoMainとシリアル接続| |YMF825(YAMAHA FM音源)|設定された音源でMIDI再生| PicoSub とSPI接続| |MIDIインターフェース|MIDI再生の入力と出力|PicoSubにシリアル接続| ## 入手先など(ご参考) Waveshare 3.5型静電容量式タッチパネルLCD Waveshare Pico-ResTouch-LCD-3.5 > https://www.waveshare.com/wiki/Pico-ResTouch-LCD-3.5 Pimoroni Pico Plus 2 > https://www.switch-science.com/products/9906 Raspberry Pi Pico > https://akizukidenshi.com/catalog/g/g116132/ YMF825(YAMAHA FM音源)・・・残念ながら販売終了です。 > https://akizukidenshi.com/catalog/g/g112414/ MIDIインターフェイス基板キット > https://akizukidenshi.com/catalog/g/g111112/ # 実体配線図 ![作品全体図](https://camo.elchika.com/576e246c417b22bed0a081606b5151dbd0a474be/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f32353665666334352d353564322d343737372d613433372d636462613733303737643433/) - PicoMain側は、Pico-ResTouch-LCD-3.5の背面にある40PinのPico用のソケットにPimoroni Pico Plus2を装着するだけです。ソケットに差し込めるよう、予めPimoroni Pico Plus2にヘッダーピンを半田付けする必要があるのと、PicoSub側とのシリアル通信の配線はありますが、追加したハードウェアはありません。 - PicoMainとPicoSubは、5Vの電源ラインも接続して、どちらかのUSB端子に電源供給されれば、PicoMainとPicoSub両方が動作します。 - Pico-ResTouch-LCD-3.5には、SDカードインターフェースも付属しています。編集した音源のパラメータをSD-Cardに保存・読み出しに利用しました。提供されているサンプルプログラムを参考にすると簡単に繋げました。 ## PicoMain とLCD、タッチパネル、SDカードとのSPIデバイス接続 - Pico-ResTouch-LCD-3.5の背面にある40PinのソケットにPicoMain(Pimoroni Pico Plus2)を装着すると、次の通りSPI接続されます。 - このSPI接続では、同じMOSI、MISO、SCKを使って、CS端子の仕様を、LCDの場合はLCD_CS、タッチパネルの場合はTP_CS、SD-Cardの場合はSD_CSに切り替えて使用する仕組みなっています。 ### Pico(Pimoroni Pico Plus2)と Pico-ResTouch-LCD-3.5 との gpio接続 |信号名|Pico gpio番号| |:-------------------------|:--------------| |LCD_DC |Pin(8, Pin.OUT)| |LCD_CS |Pin(9, Pin.OUT)| |LCD_SCK |Pin(10)| |LCD_MOSI |Pin(11)| |LCD_MISO |Pin(12)| |LCD_BL |Pin(13, Pin.OUT)| |LCD_RST |Pin(15, Pin.OUT)| |TP_CS |Pin(16, Pin.OUT)| |TP_IRQ |Pin(17, Pin.IN)| |SD_CS |Pin(22, Pin.OUT)| ## PicoSub側 のYMF825 および MIDI端子との接続 PicoSub(Raspberry Pi Pico)側では、FM音源IC(YMF825)をSPI接続して、MIDI端子をシリアル接続しています。 ![PicoSub と YMF825との接続 RUNスイッチ NoteOnLED](https://camo.elchika.com/1df844758d4c74d85a03e71988b725daafa23a41/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f66613636306261332d373566382d343830612d383830662d393535653937613736646137/) ### FM音源IC(YMF825)とのSPI接続 |PicoSub gpio name| (pin) |配線色|(pin)| YMF825| |:--------------|:----:|:----:|:---:|:---:| | gpio-17 SPI CS | (22) | 白 | (1) | SS | | gpio-19 SPI MOSI | (25) | 青 | (2) | MOSI | | gpio-16 SPI MISO | (21) | 緑 | (3) | MISO | | gpio-18 SPI CLK | (24) | 黄 | (4) | CLK | | GND | | 白 | (5) | GND | | 5V | | 橙 | (6) | VCC | | gpio-22 RESET | (29) | 紫 | (7) | RST | | No Connect | | | (8) | NC | ### YMF825 Monitor LED-BLUE(Note Onの期間中点灯) |PicoSub gpio name| (pin) |接続部品| GND | |:--------------|:----:|:----:|:---:|:---:| |gpio-28 | (34) |BLUE-LED Anode | BLUE-LED Cathode| ### PicoSub RUN スイッチ(PicoSubのリセット) |PicoSub gpio name| (pin) |接続部品| GND | |:--------------|:----:|:----:|:---:| |RUN | (30) | RUN Switch | RUN Switch | ### PicoSub とMIDI端子の接続 |PicoSub gpio name| (pin) |配線色|接続先| |:--------------|:----:|:----:|:---:|:---:| |gpio-1 UART0 TxD| (1) | 黄 |TX信号ドライブ回路の入力へ| |gpio-2 UART0 RxD| (2) | 緑 |カレント・ミラー回路の出力から| MIDI の受信(RXD)と送信(TXD)の信号波形改善のため、受信回路には2つのトランジスタでカレントミラー回路構成し、送信回路にはドライバーとして74HC04(インバータ)を入れました。 ![PicoSub 側 MIDIインターフェースとの接続](https://camo.elchika.com/308faeb751f9cd32144631f57511f6959e43e742/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f33336265613537652d663162632d346466332d386433302d383761383964626362336534/) ![MIDIインターフェース回路](https://camo.elchika.com/5e4af7860f4f9067e4ffc97ba2295aa705d93457/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f39626361633035332d373534612d343434632d393737642d373636393032346637366436/) # PicoMainとPicoSub との シリアル接続 | PicoMain| (pin) |配線色|配線色| (pin)| PicoSub| |:---------------|:-----:|:----:|:-----:|:----:|:----------------:| |gpio-2 respT |(4)| 紫 | 黄 |(4)| respT gpio-2| | | |ここでクロス| | | | |gpio-3 respR |(5)| 黄 | 紫 |(5)| respR gpio-3| ||||||| |gpio-4 TX |(6)| 緑 | 青 |(6)| TX gpio-4| | | |ここでクロス| | | | |gpio-5 RX |(7)| 青 | 緑 |(7)| RX gpio-5| ![PicoMain(Pimoroni Pico Plus2)側の配線](https://camo.elchika.com/22456f21f2697b2ac927bb65288d2db07c6875c2/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f32393565323533662d663861352d343362642d386537362d646664373834393864393837/) ![PicoSun(Raspberry Pi Pico)側の配線](https://camo.elchika.com/eb5102d0424c0d8dbfc9a5ed99bca7bbd2ef4877/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f31643435353539362d353935652d343139612d623264382d376437666130376264613738/) ### PicoMainからPicoSubへの送信手順 PicoSubは通常、MIDI信号を受信して再生(音出し)処理をしています。突然、PicoMainからデータが送られてきても対応できませんので、次のような手順で通信するようにプログラムしてします。 - PicoMainは、PicoSubへの送信データがあるなら、respTをLowにしてPicoSubに受信を要求します。 - PicoSubは、処理の合間にrespRをポーリングして、Lowを検知したら、受信モードに移行してrespTをLowにして、受信体制が整ったことをPicoMainに知らせます。 - PicoMainは、PicoSubからrespRが返ってきたら、TXを使って115200Kbpsでデータ送信し、PicoSubは受信します。 - 送信が終わったらPicoMainは、respTをHighにし、PicoSubも、respTをHighにして通信は終了します。 # PicoMainに「Pimoroni Pico Plus2」を採用した理由(読み飛ばし可) - Pico-ResTouch-LCD-3.5は、背面にある40PinのソケットにRaspberry Pi Pico2を装着するだけでMicroPythonのFramebufferを利用して、文字を描く、線を引く、点を打つ、四角を描くなどのプログラムが簡単に作れます。 - しかし、LCD 320 x 480 1画面分で307200バイトのメモリを必要としますので、Pico2(PicoではなくPico2)のメモリ(520KBのSRAM)でも、残りのメモリでは小さなプログラムしか動かせません。 Waveshare社のサイトで提供されているサンプルプログラムでは、画面の半分のバッファを用意して、プログラム領域を確保していますが、画面・半分だけのバッファではプログラムが煩雑になります。 - 今回、PicoMainにPimoroni Pico Plus2を採用したのは、メモリを気にすることなくプログラムするためです。Pimoroni Pico Plus2は、8MBのPSRAMを搭載していますので、Pico2よりも約16倍のメモリが使えます。 - ところがPimoroni Pico Plus2を利用すると嵌まり込む症状が出て解決するのに時間がかかりました。SPIの速度を、Pico2で動作していた40MHzから20MHzに変更したら症状は出なくなりました。SPIの動作を見ると、実際にはその60% 12MHzで動作しています。表示速度は落ちますが、大きなプログラムを作れるので良しとしました。 # プログラム開発環境(読み飛ばし可) - Raspberry Pi 4B にRaspberry Pi OSを標準でインストールするとThonnyが入ります。そのThonnyだけを使って開発しました。 - すべてのプログラム言語は、MicroPythonです。 - Pimoroni Pico Plus2 または Raspberry Pi Pico2をUSBケーブルでRaspberry Pi 4BにUSB接続して、Thonnyを起動させれば準備完了ですが、初めて接続する場合には、Pimoroni Pico Plus2 または Raspberry Pi Picoに、MicroPythonファームウェア(UF2 ファイル)を書き込む必要があります。ご存じない方は、ネットで検索してください。ファームウェアはMicroPython用を導入してください。 - Raspberry Pi Pico の場合はThonnyからインストールできますが、Pimoroni Pico Plus2は、専用のサイトからUF2ファイルをダウンロードする必要があります。 - Thonnyのシェル画面に表示されるシリアル出力のみでデバッグしました。 # プログラムの紹介 ## PicoMain側のプログラム PicoMainプログラムは、次のプログラムで構成されています。 ### main.py ```MicroPython:main.py ######################################################################## # 2025/11/06 Programed by Hyodot # PicoM_YMF825Edit-152.py # PicoSub 側 # PicoS_YMF825Midi-023.py # YMF825用のパラメータ設定用 PicoMain用のプログラムである。 # LCDタッチパネル WAVE SHARE Pico-ResTouch-LCD-3.5 を利用して # グラフィックな編集を実現する。ADSRなどの操作はわかりやすくなる。 ######################################################################## # # 2025/08/02 : ADSRの表示と入力、WSの表示、ALGの表示まで完成させた # main_YMF825_PicoM-047_AdsrTest.py # をベースに開発している。実行には、上記から関数群を分離した # tone_edit.py # を必要とする。 # # tone_edit.pyは、LCD表示とタッチセンス部分をライブラリとして独立させた # touch_lcd.py # を必要とする。 # touch_lcd.pyは、 # WAVE SHARE Pico-ResTouch-LCD-3.5 で用意された main_3inch5.py を改良した # touch_lcd-20250814-No3TouchLCD.py # をベースにしている。 # # 2025/08/14:Pico2は、RAMが520KB FrameBufferを使った大きなプログラムが # 作れないので、Pimoroni Pico Plus 2 PSRAM 8MB を利用する。 # PimoroniPicoPlus2で、WAVE SHARE Pico-ResTouch-LCD-3.5 を動作させると # はまり込む症状が出たが、SPIの周波数を40MHzから20MHzに変更すれば解決した。 # 20MHzを指定しても、実際の動作は6割の12MHzでしか動作していないが良しとする。 # # 設定した音源データ(ToneData)を SD-CARDに書き込み・読み込みができるようにした。 # SD-CARD への Read Write は、sdcard.py を利用する。 # sdcard.py では、touch_lcd.py で使用している SPI-1 を共有しているが、 # 特に意識して切り替えをしなくても問題なく動作している。よくわからないが良しとする。 # # YMF825 を搭載した PicoSub とシリアル通信で設定した Tone Data を送信する # # # # ######################################################################## from machine import Pin, SPI, PWM from micropython import const import time import utime import os import vfs # 仮想ファイルシステム import gc # メモリ利用状況表示用 import ymf825py as ymf825 import mojipy as moji # edit_tone.py から必要な関数をインポートする # import した「関数名」で利用できる。 print(f'Function Program Loading Start ... ') from tone_edit import spi_change2_lcd from tone_edit import dspFill from tone_edit import dspShow from tone_edit import dspColorlist from tone_edit import dspFillUpper from tone_edit import dspFillLower from tone_edit import dsp_menu from tone_edit import edit_menu from tone_edit import select_MainMenu from tone_edit import select_SubMenu from tone_edit import select_SubCom_tab from tone_edit import select_SubOp_tab from tone_edit import select_ALG from tone_edit import dsp_text_bar from tone_edit import dsp_ALGup from tone_edit import dsp_ALG_TN from tone_edit import wave_form from tone_edit import select_WS from tone_edit import edit_mul from tone_edit import edit_adsr from tone_edit import edit_dam from tone_edit import edit_bo from tone_edit import select_ToneNumber from tone_edit import select_SwapCh from tone_edit import edit_ToneName from tone_edit import select_Item from tone_edit import select_CanExe from tone_edit import edit_text # SD-Card from sdcard import SDCard print(f'Library Program Loading End') ######################################################################## print(f'main MicroPython Start ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## # UART PicoSub uartRespT = Pin(2, Pin.OUT) # Low True uartRespT.value(1) uartRespR = Pin(3, Pin.IN) # Low True # SD-Card sdcardCS = Pin(22, Pin.OUT) # main-tab sub-tab のタブ番号 tabGET = const(1) tabCOM = const(2) tabOP = const(3) tabPUT = const(4) tabALG = const(1) tabBO = const(2) tabLOF = const(3) tabWS = const(1) tabMUL = const(2) tabADSR = const(3) tabDAM = const(4) tabMR = const(1) tabYMF = const(1) tabSD = const(2) tabMODE = const(4) OP_max = const(0) OP1 = const(1) OP2 = const(2) OP3 = const(3) OP4 = const(4) # YMF825 より引用 # カラー設定を取り込み、カラー定数設定 lcd_color_list = dspColorlist() BLACK = lcd_color_list[0] RED = lcd_color_list[1] GREEN = lcd_color_list[2] BLUE = lcd_color_list[3] YELLOW = lcd_color_list[4] PURPLE = lcd_color_list[5] BLUEGREEN = lcd_color_list[6] GRAY = lcd_color_list[7] WHITE = lcd_color_list[8] # VOICE COMMON PARAMETER ROW s Number COM = const(0) BO = const(1) LFO = const(2) ALG = const(3) VOICE_COM_COL_NUM = const(4) # VOICE COMMON PARAMETER COLUMON s Number CM0 = const(0) # Oparator Name CM1 = const(1) # Edit CM2 = const(2) # Orig CM3 = const(3) # Max VOICE_COM_ROW_NUM = const(4) # 20240326 Change # VOICE OPTIONAL PARAMETER ROW s Number OPT = const(0) SR = const(1) XOF = const(2) KSR = const(3) RR = const(4) DR = const(5) AR = const(6) SL = const(7) TL = const(8) KSL = const(9) DAM = const(10) EAM = const(11) DVB = const(12) EVB = const(13) MUL = const(14) DT = const(15) WS = const(16) FB = const(17) VOICE_OP_ROW_NUM = const(18) # ymf825の音源(音色)について # Common は、音源(音色)毎に1つである com_BO = ymf825.Voice_Com_Edit[BO][CM1] com_LFO = ymf825.Voice_Com_Edit[LFO][CM1] com_ALG = ymf825.Voice_Com_Edit[ALG][CM1] # Operator # オペレーション・パラメータは、音源(音色)毎に4つのオペレータがある OP_num = 1 ''' YMF825 Tone Data には、 Tone_Com_Orig + Tone_Op_Orig # YAMAHA Original Tone_Com_Edit + Tone_Op_Edit # 編集用 があり、Tone_Com_Edit + Tone_Op_Edit を要素毎に分解した Voice_Com_Edit + Voice_Op_Edit # 要素編集用 がある。 # Common BO, LFO, ALG の最大値 Voice_Com_Max = [3, 3, 7] # Common SR, XOF, KSR, RR, DR, AR, SL, TL, KSL, DAM, EAM, DVB, EVB, MUL, DT,WS, FB の最大値 Voice_Op_Max = [15, 1, 1, 15, 15, 15, 15, 63, 3, 3, 1, 3, 1, 15, 7, 31, 7] 以下は、ymf825.serialOutVoiceData(putTN) により Voice_Com_Edit + Voice_Op_Edit をシリアル出力(プリント)したものである。 Voice Number = 0 : GRAND_PIANO Common : Edt| Org| Max| BO : 0| 0| 3| LFO : 1| 1| 3| ALG : 3| 3| 7| Operator : e1| e2| e3| e4| o1| o2| o3| o4| Mx| SR : 0| 2| 1| 2| 0| 2| 1| 2| 15| XOF : 0| 0| 0| 0| 0| 0| 0| 0| 1| KSR : 0| 1| 0| 1| 0| 1| 0| 1| 1| RR : 6| 3| 4| 6| 6| 3| 4| 6| 15| DR : 7| 3| 1| 2| 7| 3| 1| 2| 15| AR : 15| 14| 13| 13| 15| 14| 13| 13| 15| SL : 15| 2| 3| 4| 15| 2| 3| 4| 15| TL : 39| 40| 34| 0| 39| 40| 34| 0| 63| KSL : 1| 3| 0| 2| 1| 3| 0| 2| 3| DAM : 0| 0| 0| 0| 0| 0| 0| 0| 3| EAM : 0| 0| 0| 0| 0| 0| 0| 0| 1| DVB : 0| 0| 0| 0| 0| 0| 0| 0| 3| EVB : 0| 0| 1| 1| 0| 0| 1| 1| 1| MUL : 1| 5| 1| 1| 1| 5| 1| 1| 15| DT : 0| 0| 0| 0| 0| 0| 0| 0| 7| WS : 8| 0| 0| 0| 8| 0| 0| 0| 31| FB : 0| 0| 0| 0| 0| 0| 0| 0| 7| ''' # PicoSub' YMF825 MIDI Play Mode # PicoSub 側では、'Ch0_Waon+4sec' 'Ch0_Waon+Normal' いずれのモードでも # MIDI のプログラムチェンジを受け付けると Ch0 和音対応を解除して、MIDI信号に対応した発音にする。 mode_list = [ 'Init_YMF825', # YMF825 を初期設定する 'All_Note_Off', # すべてのチャンネルのノートオフ 'Ch0_Waon+4sec', # Ch0 和音対応 4秒維持 'Ch0_Waon+Normal', # Ch0 和音対応 4秒維持はしない 'With_Out_Ch0', # Ch0 を MIDI出力しない 'Swapping_Ch0>', # Ch0 を 指定した MIDI Ch に出力する ] ############################################################### # HandShake Send RTS & Recive CTS Cross Connection # PicoMain から PicoSub に respT(RTS) を 0 とすることで通信を要求し、 # PicoSub から PicoMain に respR(CTS) を 0 とすることで通信を開始する # PicoMain と PicoSub との接続 # <<< PicoMain >>> <<< PicoSub >>> # gpio-2 respT (4) --紫-- --黄-- (4) respT gpio-2 # X # gpio-3 respR (5) --黄-- --紫-- (5) respR gpio-3 # # gpio-4 TX (6) --緑-- --青-- (6) TX gpio-4 # X # gpio-5 RX (7) --青-- --緑-- (7) RX gpio-5 ############################################################### def waitCTS(rts, time, msg, cnt): global uart_timer if rts == 0: # Send RTS On uartRespT.value(0) uart_timer = time # Wait CTS On while uartRespR.value() == 1: # On == Low になるのを待つ if uart_timer == 0: print(msg) uart_timer = time if cnt > 0: cnt -= 1 else: break # Pico Sub と UART 通信できない utime.sleep_ms(10) else: # Send RTS Off uartRespT.value(1) uart_timer = time # Wait CTS Off while uartRespR.value() == 0: # Off == High になるのを待つ if uart_timer == 0: print(msg) uart_timer = time if cnt > 0: cnt -= 1 else: break # Pico Sub と UART 通信できない utime.sleep_ms(10) return cnt ####################################################################### def setToneDataPicoSub(edit_num, save_num): print('setToneDataPicoSub(edit_num)') # Sub Pico へ送信要求を送出 print('RTS On to Sub_Pico') cnt = 3 cnt = waitCTS(0, 1000, 'Wait Sub_Pico CTS On', cnt) if cnt > 0: # print('CTS On(0) from Sub_Pico') # ToneVoice をシリアル出力 ymf825.serialOutVoiceData(edit_num) # Tone_Com_Edit, Tone_Op_Edit を ASCII2文字の send_buffに変換 # ymf825.serialOutToneData(edit_num) # 20240727 Change 保存するときに ToneNumber を指定できるようにした ymf825.takeOutToneData2(edit_num, save_num) # send_buff を UART で送信 ymf825.uartOutToneData() utime.sleep_ms(10) # Sub Pico へ送信要求の解除を送出 print('RTS Off to Sub_Pico') cnt = 3 cnt = waitCTS(1, 1000, 'Wait Sub_Pico CTS Off', cnt) if cnt > 0: print('CTS Off(1) from Sub_Pico') print('ymf825.uartOutToneData() was performed') else: print() print('CTS Off(1) signal not comming from Sub-Pico') print('Check the connection with Sub-Pico') print() else: print() print('CTS On(0) signal not comming from Sub-Pico') print('ymf825.uartOutToneData() was not performed !!!') print('Check the connection with Sub-Pico') print() # Send RTS Off uartRespT.value(1) ####################################################################### # PicoSub MIDI Play Mode Set # [All_Note_Off] [Normal] [Ch0_Waon] [Ch0_Waon+Delay4] def setPlayModePicoSub(command): print('setPlayModePicoSub(command)') # Sub Pico へ送信要求を送出 print('RTS On to Sub_Pico') cnt = 3 cnt = waitCTS(0, 1000, 'Wait Sub_Pico CTS On', cnt) if cnt > 0: # print('CTS On(0) from Sub_Pico') ####################################################### ymf825.uart_write_multi(command) ####################################################### utime.sleep_ms(10) # Sub Pico へ送信要求の解除を送出 print('RTS Off to Sub_Pico') cnt = 3 cnt = waitCTS(1, 1000, 'Wait Sub_Pico CTS Off', cnt) if cnt > 0: print('CTS Off(1) from Sub_Pico') print('setPlayModePicoSub(command) was performed') else: print() print('CTS Off(1) signal not comming from Sub-Pico') print('Check the connection with Sub-Pico') print() else: print() print('CTS On(0) signal not comming from Sub-Pico') print('!!! setPlayModePicoSub(command) was not performed !!!') print('Check the connection with Sub-Pico') print() # Send RTS Off uartRespT.value(1) ####################################################################### def setToneTablePicoSub(): print('setToneTablePicoSub()') # Sub Pico へ送信要求を送出 print('RTS On to Sub_Pico') cnt = 3 cnt = waitCTS(0, 1000, 'Wait Sub_Pico CTS On', cnt) if cnt > 0: # print('CTS On(0) from Sub_Pico') # ToneTable を ASCII2文字の send_buffに変換 ymf825.takeOutToneTable() # ToneTableリストを UART に転送 ymf825.uartOutToneTable() utime.sleep_ms(10) # Sub Pico へ送信要求の解除を送出 print('RTS Off to Sub_Pico') cnt = 3 cnt = waitCTS(1, 1000, 'Wait Sub_Pico CTS Off', cnt) if cnt > 0: print('CTS Off(1) from Sub_Pico') print('ymf825.uartOutToneTable() was performed') else: print() print('CTS Off(1) signal not comming from Sub-Pico') print('Check the connection with Sub-Pico') print() else: print() print('CTS On(0) signal not comming from Sub-Pico') print('ymf825.uartOutToneTable() was not performed !!!') print('Check the connection with Sub-Pico') print() # Send RTS Off uartRespT.value(1) # SD-CARD のファイルリスト # Waveshare sdcard_demo.py より引用 def print_directory(path, tabs = 0): for file in os.listdir(path): stats = os.stat(path+"/"+file) filesize = stats[6] isdir = stats[0] & 0x4000 if filesize < 1000: sizestr = str(filesize) + " by" elif filesize < 1000000: sizestr = "%0.1f KB" % (filesize/1000) else: sizestr = "%0.1f MB" % (filesize/1000000) prettyprintname = "" for i in range(tabs): prettyprintname += " " prettyprintname += file if isdir: prettyprintname += "/" print('{0:<40} Size: {1:>10}'.format(prettyprintname, sizestr)) # recursively print directory contents if isdir: print_directory(path+"/"+file, tabs+1) # SD-CARD 指定パス直下のファイルリスト。ソートした結果を返す。 def sd_file_list(path): file_list = list() for file in os.listdir(path): stats = os.stat(path+"/"+file) filesize = stats[6] isdir = stats[0] & 0x4000 if not isdir: file_list.append(file) print() print(f'file_list = {file_list}') # リスト形式を タプル形式に変換 tpl_list = tuple(file_list) # タプル形式で、ソートを実施して、リストに戻す # tpl_list = tuple(sorted(tpl_list)) # これは、タプルに戻す場合 file_list = sorted(tpl_list) # 拡張子 .txt を取り除く(この処理、ファイル名の本体に .txt が無いことが前提) for i in range(len(file_list)): file_list[i] = file_list[i].replace('.txt', '') return file_list # SD-card から Tone Dataを読み込み # Tone Data は、100バイト、1行のみである def readToneData_fromSD(file_path): # 指定されたファイルを読み込み、ymf825.rcv_tone に展開する # この時点では、Tone Data として取り込むか否かは決定していない。 with open(file_path, 'r') as f: ymf825.rcv_buff = f.readline() if len(ymf825.rcv_buff) == 100: # Tone Data として取り込むには、ymf825.takeInToneData() を実行すればよいが、 # tone_num tone_name を取得して確認する tone_num = moji.asc2int(ymf825.rcv_buff[ymf825.TONE_HEADER:ymf825.TONE_HEADER +2]) print(f'tone_num = {tone_num}') ymf825.rcv_tone = [] for i in range(ymf825.UART_TONE_NUM): #42 ymf825.rcv_tone.append(moji.asc2int(ymf825.rcv_buff[ymf825.TONE_HEADER +i *2 : \ ymf825.TONE_HEADER +i *2 +2])) print(f'ymf825.rcv_tone = {ymf825.rcv_tone}') # tone_name の取得と更新 ymf825 1141行あたりの処理 tone_name = ymf825.rcv_buff[1:ymf825.TONE_HEADER].strip() # 末尾のスペースを取り除く print(f'Recive Data Tone Name = {tone_name}') else: print(f'len(ymf825.rcv_buff) = {len(ymf825.rcv_buff)} does not 100 bytes') tone_num = 0 tone_name ='' return len(ymf825.rcv_buff), tone_num, tone_name ######################################################################## # MicroPython Start ######################################################################## # カラー表示テスト ・・・ 不要であるが for i in range(len(lcd_color_list)): dspFill(lcd_color_list[i]) dspShow() utime.sleep_ms(100) # ToneNo 0-15 getTN = 0 putTN = 0 # 何も指定しなくても編集を開始できるように 0:GrandPiano を読み込んでおく # YMF825 Grand Piano Tone Data Set ymf825.copyTone2_Voice(getTN) # main-menu sub-menu の初期設定 tabM_num = 0 # MainTab 毎に SubTab があるので、管理しやすくするために # tabM_num 0, 1, 2, 3, 4 tabL = [0, 0, 0, 0, 0] tabS_num = tabL[tabM_num] # 直前の処理状況を edit_menu(tabM_num, tabS_num, processMsg) により画面表示する processMsg = 'Program Start' print(processMsg) # SD-CARD モジュール起動 # LCD TouchPanel と SPI が共通なのだが、特に切り替えをしなくても動作している spi = SPI(1, baudrate=60_000_000, sck=Pin(10), mosi=Pin(11), miso=Pin(12), \ polarity=0, phase=0) # from sdcard import SDCard ############################################################################ sd = SDCard(spi, Pin(22, Pin.OUT), 30_000_000) processMsg = 'sd = SDCard(spi, Pin(22, Pin.OUT), 30_000_000)' print(processMsg) # PicoM_YMF825Edit-136.py 以前では、 # Thonny による停止ボタン、起動ボタンでは2回目の起動で必ずエラーになる(タイムアウト) # 次のようにすることで回避できた。 # SD-Card 接続:vfs.mount(sd, '/sd') でエラーならば、vfs.umountを入れる。 # SD-Card 切断:vfs.umount('/sd') ではなく vfs.umount('/') を実行してから # SD-Card 接続:vfs.mount(sd, '/sd') すればよい。より確実と思われる方法にしてみた。 # vfs.mount() により、現在の接続情報が得られるが、リスト内にタプル形式で収納されている。 # print(f'vfs.mount() = {vfs.mount()}') print('command: mount_value = vfs.mount()') mount_value = vfs.mount() # mount_value は、リスト print('command: vfs_obl, mount_point = mount_value') vfs_obj, mount_point = mount_value[0] print(f'result: mount_point = {mount_point}') try: print("command: vfs.mount(sd, '/sd')") vfs.mount(sd, '/sd') except: print(f"Error On : vfs.mount(sd, '/sd')") print(f"command: vfs.umount({mount_point})") # vfs.umount('/sd') は NG vfs.umount('/') なら OK vfs.umount(mount_point) print("command: vfs.mount(sd, '/sd')") vfs.mount(sd, '/sd') print(f'vfs.mount() = {vfs.mount()}') # ############################################################################ ######################################## # main loop ######################################## while True: dsp_menu(tabM_num, tabL[tabM_num]) if tabM_num == tabGET: print(f'tab[GET] was selected') if tabL[tabM_num] == tabMR: print(f'tab[MR]:memory was selected') # getTN(Tone Number)選択 guide_msg1 = 'Get Tone Data' guide_msg2 = 'Select Tone Number' getTN_old = getTN # (btn, getTN) = select_ToneNumber(guide_msg, getTN_old) tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], btn, getTN) = \ select_ToneNumber(tabM_num, tabL[tabM_num], guide_msg1, guide_msg2, \ getTN_old, ymf825.ToneName) if getTN_old != getTN: print(f'Tone Number has changed') if btn == 'Execute': print(f'Execution Get Tone Data') ########################################################## # getTN で指定された YAMAHA の Tone Data を編集用にロードする ymf825.copyTone2_Voice(getTN) ########################################################## processMsg = 'Succeed Memory RD' print(processMsg) # main Menu 選択に移行 tabM_num = 0 elif btn == 'Cancel': processMsg = 'Cansel Memory RD' print(processMsg) getTN = getTN_old # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') getTN = getTN_old dspFillUpper(WHITE) elif tabL[tabM_num] == tabSD: print(f'tab[SD]:card was selected') # SD-CARD を読み込み ファイル一覧を表示、1つを選択してデータを読み込む # file_list を作成する file_list = sd_file_list("/sd") print() print(f'file_list = {file_list}') guide1 = 'Get Tone Data' guide2 = 'Select File Name' list_name = 'file name' # list を表示、 ひとつを選択する # btn, file_name = select_File(file_list, guide1, guide2, list_name) tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], btn, file_name) = \ select_Item(tabM_num, tabL[tabM_num], file_list, guide1, guide2, list_name) print() print(f'file_name = {file_name}') if btn == 'Execute': # 指定された file_name の file_path 生成 file_name = file_name.strip()+'.txt' file_path = '/sd/'+file_name print(f'file_path = {file_path}') if file_name not in os.listdir('/sd'): # 指定されたファイルがなければ? print('#################################################################') print(f'The file name ({file_name}) does not exist on the SD card.') print('#################################################################') # ありえないはず・・・何もしない else: # 指定のファイルがあれば SD-card の指定ファイルからデータ読み込む rcv_buff_size, tone_num, tone_name = readToneData_fromSD(file_path) if rcv_buff_size == 100: print('Tone Data') print(f'tone_num = {tone_num}') print(f'tone_name = {tone_name}') print(f'tone_data = {ymf825.rcv_tone}') # tone_number を指定して取り込む # getTN(Tone Number)選択 guide_msg1 = 'Get Tone Data' guide_msg2 = 'Select Tone Number' tone_num_old = tone_num # getTN_old = getTN # (btn, tone_num) = select_ToneNumber(guide_msg, tone_num_old) tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], btn, tone_num) = \ select_ToneNumber(tabM_num, tabL[tabM_num], guide_msg1, guide_msg2, \ tone_num_old, ymf825.ToneName) if tone_num_old != tone_num: print(f'Tone Number has changed') # Tone Number 変更 # ymf825.takeInToneData() では、ymf825.rcv_tone[0] から取り込まれる ymf825.rcv_tone[0] = tone_num print(f'ymf825.rcv_tone[0] = {ymf825.rcv_tone[0]}') if btn == 'Execute': print(f'Execution Get Tone Data') # 読み込もうとする場所の ToneVoice をシリアル出力(プリント) ymf825.serialOutVoiceData(getTN) ################### getTN = tone_num ################### # Tone Name 更新 ymf825.ToneName[getTN] = tone_name.strip() # 末尾のスペースを取り除く # rcv_tone から Tone Data へデータ変換 ymf825.takeInToneData() ########################################################## # getTN で指定された YAMAHA の Tone Data を編集用にロードする ymf825.copyTone2_Voice(getTN) ########################################################## # ToneVoice をシリアル出力(プリント) ymf825.serialOutVoiceData(getTN) processMsg = 'Succeed SDcard RD' print(processMsg) # DEBUG 書き込み具合を見たいとき # SDカードが見られる状態にするにはここで break # break # main Menu 選択に移行 tabM_num = 0 elif btn == 'Cancel': # select_ToneNumber で btn == 'Cancel' processMsg = 'Cansel SDcard RD' print(processMsg) # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') else: print('rcv_buff_size is not 100') processMsg = 'Not Tone Data' print(processMsg) elif btn == 'Cancel': processMsg = 'Cansel SDcard RD' print(processMsg) # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') dspFillUpper(WHITE) else: dspFillUpper(WHITE) tabS_num = 0 tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old]) = select_SubMenu(tabM_num, tabS_num) processMsg = '' ######################################################################## print(f'main Loop tab[GET] end ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## elif tabM_num == tabCOM: print(f'tab[COM] was selected') if tabL[tabM_num] == tabALG: print(f'tab[ALG] was selected') # ALG 選択 tabM_num_old = tabM_num print(f'ymf825.Voice_Com_Edit[ALG][CM1] = {ymf825.Voice_Com_Edit[ALG][CM1]}') (tabM_num, tabL[tabM_num_old], ymf825.Voice_Com_Edit[ALG][CM1]) = \ select_ALG(tabM_num, tabL[tabM_num], ymf825.Voice_Com_Edit[ALG][CM1], \ getTN, ymf825.ToneName[getTN]) processMsg = '[ALG] Edit end' print(processMsg) elif tabL[tabM_num] == tabBO or tabL[tabM_num] == tabLOF: print(f'tab[BO] or tab[LFO] was selected') # edit BO LFO tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], OP_num, ymf825.Voice_Com_Edit[BO][CM1],\ ymf825.Voice_Com_Edit[LFO][CM1]) = \ edit_bo(tabM_num, tabL[tabM_num], OP_num, ymf825.Voice_Com_Edit[BO][CM1], \ ymf825.Voice_Com_Edit[LFO][CM1], getTN, ymf825.ToneName[getTN]) processMsg = '[BO][LFO] Edit end' print(processMsg) else: dspFillUpper(WHITE) tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old]) = select_SubMenu(tabM_num, tabL[tabM_num]) processMsg = '' ######################################################################## print(f'main Loop tab[COM] end ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## elif tabM_num == tabOP: print(f'tab[OP] was selected') if tabL[tabM_num] == tabWS: print(f'tab[WS] was selected') # tabOP が選択されたら、選択されている getTN tone_name ALG を上段に表示する dsp_ALG_TN(ymf825.Voice_Com_Edit[ALG][CM1], OP_num, getTN, ymf825.ToneName[getTN]) # Select WS # OP_num は、変更されて返ってくることを前提にする OP_num_old = OP_num tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], OP_num, ymf825.Voice_Op_Edit[WS][OP_num_old]) = \ select_WS(tabM_num, tabL[tabM_num], OP_num, ymf825.Voice_Op_Edit[WS][OP_num]) processMsg = '[WS] Edit end' print(processMsg) elif tabL[tabM_num] == tabMUL: print(f'tab[MUL] was selected') # tabOP が選択されたら、選択されている getTN tone_name ALG を上段に表示する dsp_ALG_TN(ymf825.Voice_Com_Edit[ALG][CM1], OP_num, getTN, ymf825.ToneName[getTN]) # edit MUL DT FB XOF # OP_num は、変更されて返ってくることを前提にする OP_num_old = OP_num tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], OP_num, ymf825.Voice_Op_Edit[MUL][OP_num_old], \ ymf825.Voice_Op_Edit[DT][OP_num_old], ymf825.Voice_Op_Edit[FB][OP_num_old], \ ymf825.Voice_Op_Edit[XOF][OP_num_old]) = \ edit_mul(tabM_num, tabL[tabM_num], OP_num, ymf825.Voice_Op_Edit[MUL][OP_num], \ ymf825.Voice_Op_Edit[DT][OP_num], ymf825.Voice_Op_Edit[FB][OP_num], \ ymf825.Voice_Op_Edit[XOF][OP_num]) processMsg = '[MUL] Edit end' print(processMsg) elif tabL[tabM_num] == tabADSR: print(f'tab[ADSR] was selected') # tabOP が選択されたら、選択されている getTN tone_name ALG を上段に表示する dsp_ALG_TN(ymf825.Voice_Com_Edit[ALG][CM1], OP_num, getTN, ymf825.ToneName[getTN]) # WS 波形を表示する 上段・右下 z = [250, 180] color_back = GREEN color_wave = PURPLE wave_form(ymf825.Voice_Op_Edit[WS][OP_num], color_back, color_wave, z) # WS 波形番号を表示する text = f'WS{ymf825.Voice_Op_Edit[WS][OP_num]:>2}' zs = [250, 180 +36] chr_num = len(text) color_text = PURPLE dsp_text_bar(text, zs, chr_num, color_back, color_text) # edit ADSR 編集 # OP_num は、変更されて返ってくることを前提にする # 2025/11/03 ymf825.Voice_Op_Edit[MUL][OP_num] を追加、表示のみ OP_num_old = OP_num tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], OP_num, ymf825.Voice_Op_Edit[TL][OP_num_old], \ ymf825.Voice_Op_Edit[SL][OP_num_old], ymf825.Voice_Op_Edit[AR][OP_num_old], \ ymf825.Voice_Op_Edit[DR][OP_num_old], ymf825.Voice_Op_Edit[SR][OP_num_old], \ ymf825.Voice_Op_Edit[RR][OP_num_old], ymf825.Voice_Op_Edit[KSL][OP_num_old], \ ymf825.Voice_Op_Edit[KSR][OP_num_old]) = \ edit_adsr(tabM_num, tabL[tabM_num], OP_num, ymf825.Voice_Op_Edit[TL][OP_num], \ ymf825.Voice_Op_Edit[SL][OP_num], ymf825.Voice_Op_Edit[AR][OP_num], \ ymf825.Voice_Op_Edit[DR][OP_num], ymf825.Voice_Op_Edit[SR][OP_num], \ ymf825.Voice_Op_Edit[RR][OP_num], ymf825.Voice_Op_Edit[KSL][OP_num], \ ymf825.Voice_Op_Edit[KSR][OP_num], ymf825.Voice_Op_Edit[MUL][OP_num]) processMsg = '[ADSR] Edit end' print(processMsg) elif tabL[tabM_num] == tabDAM: print(f'tab[DAM] was selected') # tabOP が選択されたら、選択されている getTN tone_name ALG を上段に表示する dsp_ALG_TN(ymf825.Voice_Com_Edit[ALG][CM1], OP_num, getTN, ymf825.ToneName[getTN]) # edit DAM EAM DVB EVB 編集 # OP_num は、変更されて返ってくることを前提にする OP_num_old = OP_num tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], OP_num, ymf825.Voice_Op_Edit[DAM][OP_num_old], \ ymf825.Voice_Op_Edit[EAM][OP_num_old],ymf825.Voice_Op_Edit[DVB][OP_num_old], \ ymf825.Voice_Op_Edit[EVB][OP_num_old]) = \ edit_dam(tabM_num, tabL[tabM_num], OP_num, ymf825.Voice_Op_Edit[DAM][OP_num], \ ymf825.Voice_Op_Edit[EAM][OP_num], ymf825.Voice_Op_Edit[DVB][OP_num], \ ymf825.Voice_Op_Edit[EVB][OP_num]) processMsg = '[DAM] Edit end' print(processMsg) else: tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old]) = select_SubMenu(tabM_num, tabL[tabM_num]) processMsg = '' ######################################################################## print(f'main Loop tab[OP] end ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## elif tabM_num == tabPUT: print(f'tab[PUT] was selected') if tabL[tabM_num] == tabYMF: print(f"tab[YMF]:PicoSub's device YMF825 was selected") # getTN(Tone Number)選択 guide_msg1 = 'Get Tone Data' guide_msg2 = 'Select Tone Number' putTN = getTN putTN_old = putTN # (btn, putTN) = select_ToneNumber(guide_msg, putTN_old) tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], btn, putTN) = \ select_ToneNumber(tabM_num, tabL[tabM_num], guide_msg1, guide_msg2, \ putTN_old, ymf825.ToneName) if putTN_old != putTN: print(f'Tone Number has changed') if btn == 'Execute': print(f'Execution Put Tone Data') # ToneVoice をシリアル出力(プリント) ymf825.serialOutVoiceData(putTN) # 編集した内容を Tone Data に保存 ymf825.copyVoice2_Tone(putTN) #################################################################### # getTN で指定された Tone_Com_Edit と Tone_Op_Edit を # PicoSub の putTN で指定された Tone_Com_Edit と Tone_Op_Edit に保存する setToneDataPicoSub(getTN, putTN) #################################################################### processMsg = 'Succeed [YMF] WR' print(processMsg) # main Menu 選択に移行 tabM_num = 0 elif btn == 'Cancel': print('Cansel was selected') # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') dspFillUpper(WHITE) elif tabL[tabM_num] == tabSD: print(f'tab[SD]:card was selected') # SD-CARD に書き込む ファイル名は ymf825.ToneName に登録されているものを編集する。 # 15文字以下で、末尾の余白を取り除いたものにファイルの拡張子は「.txt」を付加する。 # file name 入力 loop = 1 # 正常処理が終われば flag_loop = 0 として書き込み動作に移る while loop == 1: digit_max = 15 # tone_name の最大桁数 exeName = ' OK ' tone_name = ymf825.ToneName[getTN] print(f'tone_name = {tone_name}') tone_name_old = tone_name tabM_num_old = tabM_num # (btn, tone_name) = edit_ToneName(tone_name_old, digit_max, exeName) (tabM_num, tabL[tabM_num_old], btn, tone_name) = \ edit_ToneName(tabM_num, tabL[tabM_num], tone_name_old, digit_max, exeName) if tone_name_old != tone_name: print(f'Tone Name has changed') print(f'tone_name = {tone_name}') if btn == exeName or btn == 'Enter': print(f'Execution Put Tone Data') # Tone Name 更新 ymf825.ToneName[getTN] = tone_name.strip() # 末尾のスペースを取り除く # ToneVoice をシリアル出力(プリント) ymf825.serialOutVoiceData(putTN) # 編集した内容を Tone Data に保存 ymf825.copyVoice2_Tone(putTN) # Tone_Com_Edit, Tone_Op_Edit を ASCII2文字の send_buffに変換 # puTNの指定(=Tone Number)の変更はなしとするので # ymf825.takeOutToneData2(getTN, putTN) は使用しない。 # Tone Number は、読み込むときに指定すれば良い。 ymf825.takeOutToneData(getTN) # file_name 生成 file_name = tone_name.strip()+'.txt' file_path = '/sd/'+file_name print(f'file_path = {file_path}') if file_name in os.listdir('/sd'): # 同じファイル名が存在すれば上書きするか確認のステップを入れる print('########################################################') print(f'The file name ({file_name}) exist on the SD card.') print('########################################################') # 上書きするか否か title = 'File name exists' guide1 = 'Want to OverWrite?' guide2 = 'Execute or Cancel' btn = select_CanExe(title, guide1, guide2) if btn == 'Execute': # while loop を抜けて書き込み実行 loop = 0 else: # file name = ToneName の再入力をするなら、while loop continue else: # 同じファイル名でなければ、while loop を抜けて書き込み実行 loop = 0 elif btn == 'Cancel': # edit_ToneName() で Cancel 選択ならば processMsg = 'Cansel SDcard WR' print(processMsg) print('Cansel was selected') # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 break # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') dspFillUpper(WHITE) break else: # while loop の外である。loop == 0 でここに来る 書き込み実行 with open(file_path, 'w') as f: f.write(ymf825.send_buff) processMsg = 'Succeed SDcard WR' print(processMsg) # main Menu 選択に移行 tabM_num = 0 # DEBUG print("Files on filesystem:") print("====================") print_directory("/sd") file_list = sd_file_list("/sd") print() print(f'file_list = {file_list}') # DEBUG 書き込み具合を見たいとき・・・SDカードが見られる状態にするにはここで break # break # break ならば ここに来る edit_ToneName() で Cancel 選択ならば elif tabL[tabM_num] == tabMODE: print(f'tab[MODE]:YMF825 Play Mode was selected') # PicoSub YMF825 のMIDI再生モードを指定する。 # 15文字以下で、再生コマンドを用意して、PicoSub と共有する。 # mode_list にモードリストを用意しておき、選択して PicoSub に送る。 guide1 = 'Set Play Mode' guide2 = 'Select Play Mode' list_name = 'Play Mode' # list を表示、 ひとつを選択する # btn, play_mode = select_File(mode_list, guide1, guide2, list_name) tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], btn, play_mode) = \ select_Item(tabM_num, tabL[tabM_num], mode_list, guide1, guide2, list_name) print() print(f'play_mode = {play_mode}') if btn == 'Execute': # plat_mode が 'Swapping_Ch0>' ならば、末尾にスワッピング・チャンネルを追加 if 'Swap'.lower() in play_mode.lower() and 'Ch0>'.lower() in play_mode.lower(): # tone_number を指定して取り込む # getTN(Tone Number)選択 guide_msg1 = 'Select Swapping Ch' guide_msg2 = 'Ch0 Swap to Ch?' default_ch = 14 tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old], btn, sw_ch) = \ select_SwapCh(tabM_num, tabL[tabM_num], guide_msg1, guide_msg2, \ default_ch) if btn == 'Execute': print(f'Selected Swap Ch0 to Ch{sw_ch}') # 指定された play_mode を PicoSub への送信データに構成する # 先頭の '2' は Play Mode であることを示す # 先頭に '2' に続けて play_mode を入れ、末尾にスペースを入れて16桁にする # play_mode = '2' + moji.strFixL_n(play_mode, 15) play_mode += str(sw_ch) print(f'play_mode = {play_mode}') play_mode = f'2{play_mode:<15}' print(f'setPlayModePicoSub play_mode = {play_mode}') ####################################################### setPlayModePicoSub(play_mode) ####################################################### # main Menu 選択に移行 tabM_num = 0 elif btn == 'Cancel': # select_ToneNumber で btn == 'Cancel' processMsg = 'Cansel Play Mode Set' print(processMsg) # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') else: # 指定された play_mode を PicoSub への送信データに構成する # 先頭の '2' は Play Mode であることを示す # 先頭に '2' に続けて play_mode を入れ、末尾にスペースを入れて16桁にする # play_mode = '2' + moji.strFixL_n(play_mode, 15) play_mode = f'2{play_mode:<15}' print(f'setPlayModePicoSub play_mode = {play_mode}') ####################################################### setPlayModePicoSub(play_mode) ####################################################### processMsg = 'SucceedSetPlayMode' print(processMsg) # main Menu 選択に移行 tabM_num = 0 elif btn == 'Cancel': processMsg = 'Cansel SetPlayMode' print(processMsg) # subMenu をリセット tabL[tabM_num] = 0 # main Menu 選択に移行 tabM_num = 0 # tabM_num or tabL[tabM_num] was Changed else: print('Tab was Changed') dspFillUpper(WHITE) else: dspFillUpper(WHITE) tabS_num = 0 tabM_num_old = tabM_num (tabM_num, tabL[tabM_num_old]) = select_SubMenu(tabM_num, tabS_num) processMsg = '' ######################################################################## print(f'main Loop tab[PUT] end ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## else: print(f'Nothing Selected main-tab') print(f'Before tabM_num = {tabM_num} tabL[tabM_num] = {tabL[tabM_num]}') # while tabM_num == 0 or tabL[tabM_num] == 0: # tabM_num_old = tabM_num # (tabM_num, tabL[tabM_num_old]) = edit_menu(tabM_num, tabL[tabM_num], processMsg) # 20251023 Change tabM_num = select_MainMenu(tabM_num, processMsg) print(f'After tabM_num = {tabM_num} tabL[tabM_num] = {tabL[tabM_num]}') ######################################################################## print(f'main MicroPython while ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## processMsg = '' ``` ### tone_edit.py ```MicroPython:tone_edit.py ######################################################################## # 2025/11/10 Programed by Hyodot # tone_edit_yyyymmdd-hhmm.py # LCDタッチパネル WAVE SHARE Pico-ResTouch-LCD-3.5 を利用した # PicoM_YMF825Edit.py # で使用する YMF825用のパラメータ編集用の関数群である。 ######################################################################## # 2025/08/02 : ADSRの表示と入力、WSの表示、ALGの表示まで完成させた # main_YMF825_PicoM-047_AdsrTest.py # から分離編集したものである。 # # WAVE SHARE Pico-ResTouch-LCD-3.5 で用意された main_3inch5.py を改良した # touch_lcd.py # および、表示座標を保存提供する # tab_cdn.py # を必要とする # # 2025/08/14:Pimoroni Pico Pi Plus 2 PSRAM 8MB を利用する # # ######################################################################## import math from micropython import const import time from touch_lcd import LCD_3inch5 from tab_cdn import TabCoordinate # タッチの誤動作を防止するためゾーンを複数回タッチした時に反応するようにした。 # ここで設定した回数を連続して検知した時に受け付ける。 TOUCH_TH = const(3) # この Pixel 分を上下左右に拡大したエリアをタッチ有効とする # 周辺部分では誤差が多いので、一部、この倍の領域にしている TOUCH = const(8) # 下半分表示の座標開始位置・・・この値は、ADSR 関連の関数で参照する ADSRxs = const(50) # x_start 30 ADSRys = const(270) # y_start # TAB 関連 TabCoordinate と同じもの Item = const(5) Mxs = const(0) Mys = const(0) Sxs = const(0) Sys = const(240) UPys = const(24) LWys = const(264) UPzs = [0, UPys] LWzs = [0, LWys] chr_n = const(4) # タブの文字数 chr_w = const(16) # 文字幅 chr_h = const(16) # 文字高さ txt_h = const(20) # 余白を含めた文字高さ xbt = const(4) # 縦線幅 x ybt = const(4) # 横線幅 y # tab の位置 tabGET = const(1) tabCOM = const(2) tabOP = const(3) tabPUT = const(4) tabALG = const(1) tabBO = const(2) tabLOF = const(3) tabWS = const(1) tabMUL = const(2) tabADSR = const(3) tabDAM = const(4) # YMF825 Grand Piano Tone Data Set # ToneNo 0-15 TN = 0 max_TN = const(15) # Common BO = 0 LFO = 1 ALG = 3 max_BO = const(3) max_LFO = const(3) max_ALG = const(7) # Operator # 以下は、オペレーション・パラメータで、それぞれ4つのオペレータがある。 # 0:Max,op1,op2,op3,op4 を OP_numで指定する。 # 0:Max 1 2 3 4 WS = [31, 8, 0, 0, 0] MUL = [15, 1, 5, 1, 1] DT = [ 7, 0, 0, 0, 0] FB = [ 7, 0, 0, 0, 0] XOF = [ 1, 0, 0, 0, 0] TL = [63,39,40,34, 0] SL = [15,15, 2, 3, 4] AR = [15,15,14,13,13] DR = [15, 7, 3, 1, 2] SR = [15, 0, 2, 1, 2] RR = [15, 6, 3, 4, 6] KSL = [ 3, 1, 3, 0, 2] KSR = [ 1, 0, 1, 0, 1] DAM = [ 3, 0, 0, 0, 0] EAM = [ 1, 0, 0, 0, 0] DVB = [ 3, 0, 0, 0, 0] EVB = [ 1, 0, 0, 1, 1] OP_num = 1 OP_max = const(0) max_WS = WS[OP_max] max_MUL = MUL[OP_max] max_DT = DT[OP_max] max_FB = FB[OP_max] max_XOF = XOF[OP_max] max_TL = TL[OP_max] -15 # YMF825 は 63 だが 実用的に 48 とする max_SL = SL[OP_max] max_AR = AR[OP_max] max_DR = DR[OP_max] max_SR = SR[OP_max] max_RR = RR[OP_max] max_KSL = KSL[OP_max] max_KSR = KSR[OP_max] max_DAM = DAM[OP_max] max_EAM = EAM[OP_max] max_DVB = DVB[OP_max] max_EVB = EVB[OP_max] # MF825_PicoM-047.py より移植 # BO, LOF, MUL, FB, XOF, DAM EAM, DVB, EVB タッチ座標の提供 # BO タッチ開始座標の設定 # 0 1 2 3 BOxs = [ 32, 32, 32, 32] # BOys = [190,170,150,130] BOys = [240+190, 240+170, 240+150, 240+130] BOcn = 5 # LFO タッチ開始座標の設定 # 0 1 2 3 LFOxs = [192,192,192,192] # LFOys = [190,170,150,130] LFOys = [240+190, 240+170, 240+150, 240+130] LFOcn = 5 # sign_XX は、スライダーの正負(X軸、Y軸の移動に対して取得数値が増大か?縮小か?) # MUL DT ともに上が大、下が小なので、-1 sign_MUL = -1 sign_DT = -1 # FB タッチ開始座標の設定 # 0 1 2 3 4 5 6 7 FBxs = [160,160,160,160,160,160,160,160] FBys = [430,410,390,370,350,330,310,290] FBcn = 5 # XOF タッチ開始座標の設定 # 0 1 XOFxs = [250,250] XOFys = [430,410] XOFcn = 3 # DAM タッチ開始座標の設定 # 0 1 2 3 DAMxs = [ 32, 32, 32, 32] DAMys = [350,330,310,290] DAMcn = 6 # DVB タッチ開始座標の設定 # 0 1 2 3 DVBxs = [192,192,192,192] DVBys = [350,330,310,290] DVBcn = 6 # EAM タッチ開始座標の設定 # 0 1 EAMxs = [ 32, 32] EAMys = [430,410] EAMcn = 6 # EVB タッチ開始座標の設定 # 0 1 EVBxs = [192,192] EVBys = [430,410] EVBcn = 6 # TN タッチ開始座標の設定 # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 TNxs = [ 64,112,160,208, 64,112,160,208, 64,112,160,208, 64,112,160,208] TNys = [390,390,390,390,360,360,360,360,330,330,330,330,300,300,300,300] TNcn = 3 # Full Key タッチ開始座標の設定 FKxb = const(0) # FKyb = const(266) FKyb = const(268 +20) FKcw = const(32) FKch = const(32) key_c = const(10) key_r = const(6) FKxs = [None] *key_c for i in range(key_c): FKxs[i] = i *FKcw # 0 1 2 3 4 5 6 7 8 9 # FKxs = [ 0, 32, 64, 96,128,160,192,224,256,288] FKys = [None] *key_r for i in range(key_r): # FKys[i] = i *FKch + 268 +20 FKys[i] = i *FKch +FKyb # 0 1 2 3 4 5 # FKys = [288,320,352,384,416,448] # Full Key タッチゾーンの設定 zone_FKs = [None, None] *key_c zone_FKe = [None, None] *key_c for i in range(key_c): zone_FKs[i] = [None] *key_r zone_FKe[i] = [None] *key_r for x in range(key_c): for y in range(key_r): zone_FKs[x][y] = [FKxs[x], FKys[y]] zone_FKe[x][y] = [FKxs[x]+FKcw, FKys[y]+FKch] # FKs[0][0]=[ 0,288] FKs[0][1]=[ 0,320] FKs[0][2]=[ 0,352] ... FKs[0][4]=[ 0,416] FKs[0][5]=[ 0,448] # FKs[1][0]=[32,288] FKs[1][1]=[32,320] FKs[1][2]=[32,352] ... FKs[1][4]=[32,416] FKs[1][5]=[32,448] # ・・・ # FKs[9][0]=[288,288] FKs[9][1]=[288,320] FKs[9][2]=[288,352] ... FKs[9][4]=[288,416] FKs[9][5]=[288,448] # No Shift ★★★ FKv0[FKy, FKx] ・・・ X軸、Y軸を入れ替えて指定すること FKv0 = [ # 0 1 2 3 4 5 6 7 8 9 ['!', '"', '#', '$', '%', '&', "'", '(', ')', ' '], ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ' '], ['z', 'x', 'c', 'v', 'b', 'n', 'm', ';', ':', ' '], [' ', ' ', ' ', ' ', ',', '.', '/', '|', '^', '|'] ] # Shift ★★★ FKv1[FKy, FKx] ・・・ X軸、Y軸を入れ替えて指定すること FKv1 = [ # 0 1 2 3 4 5 6 7 8 9 ['@', '+', '*', '-', '=', '{', "}", '[', ']', ' '], ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ' '], ['Z', 'X', 'C', 'V', 'B', 'N', 'M', '+', '*', ' '], [' ', ' ', ' ', ' ', '<', '>', '?', '_', '~', '|'] ] ################################################## # import した ライブラリ class の短縮名 LCD = LCD_3inch5() LCD.bl_ctrl(100) print(f'LCD.rotate = {LCD.rotate}') TAB = TabCoordinate() ################################################## # main program から LCD_3inch5 が実行できるように def spi_change2_lcd(): LCD.spi_change2_lcd() def dspFill(color): LCD.fill(color) def dspFill_rect(zs, w, h, color_back): LCD.fill_rect(zs[0], zs[1], w, h, color_back) def clearMainTab(color_back): LCD.fill_rect(0, 0, 320, 24, color_back) def clearSubTab(color_back): LCD.fill_rect(0,240, 320, 24, color_back) def dspFillUpper(color_back): (zs, w, h) = TAB.get_UpperAria() LCD.fill_rect(zs[0], zs[1], w, h, color_back) def dspFillLower(color_back): (zs, w, h) = TAB.get_LowerAria() LCD.fill_rect(zs[0], zs[1], w, h, color_back) def dspShow(): LCD.show() def dspColorlist(): return [LCD.BLACK, LCD.RED, LCD.GREEN, LCD.BLUE, LCD.YELLOW,\ LCD.PURPLE, LCD.BLUEGREEN, LCD.GRAY, LCD.WHITE] # X_Poin と Y_Point が 共に zoneS ~ zoneE の範囲内にあるか否か def in_zone(zoneS, zoneE, X_Point, Y_Point): if zoneS[0] <= X_Point and X_Point <= zoneE[0] \ and zoneS[1] <= Y_Point and Y_Point <= zoneE[1]: # X_Poin と Y_Point が 共に zoneS ~ zoneE の範囲内ならば True return True else: return False ######################################################################################## # 表示関係の関数 def select_main_tab(tabM_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() tabMain_text = TAB.get_tabMain_text() cnt_zone = [0, 0, 0, 0, 0] # zone0, zone1, zone2, zone3, zone4 # tabM_num != 0 で終了 while tabM_num == 0: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(1, Item): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cnt_zone[i] += 1 if cnt_zone[i] == TOUCH_TH: tabM_num = i print(f'main tab = {tabMain_text[tabM_num]}') else: time.sleep_ms(50) return tabM_num def select_SubCom_tab(tabM_num, tabS_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() tabMain_text = TAB.get_tabMain_text() cntM_zone = [0, 0, 0, 0, 0] # zone0, zone1, zone2, zone3, zone4 # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabCOM_text = TAB.get_tabCOM_text() cntS_zone = [0, 0, 0, 0, 0] # zone0, zone1, zone2, zone3, zone4 tabM_num_old = tabM_num # tabM_num_old != tabM_num または tabM_num != 0 で終了 while tabM_num_old == tabM_num and tabS_num == 0: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(1, Item): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cntM_zone[i] += 1 if cntM_zone[i] == TOUCH_TH: tabM_num = i print(f'main tab = {tabMain_text[tabM_num]}') for i in range(1, Item -1): # ALG BO LFO の3つ if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneStab[i] の周辺ならば # print(f'select zoneStab[{i}]') cntS_zone[i] += 1 if cntS_zone[i] == TOUCH_TH: tabS_num = i print(f'sub tab = {tabCOM_text[tabS_num]}') else: time.sleep_ms(50) return tabM_num, tabS_num def select_SubOp_tab(tabM_num, tabS_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() tabMain_text = TAB.get_tabMain_text() cntM_zone = [0, 0, 0, 0, 0] # zoneM0, zoneM1, zoneM2, zoneM3, zoneM4 # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabOP_text = TAB.get_tabOP_text() cntS_zone = [0, 0, 0, 0, 0] # zoneS0, zoneS1, zoneS2, zoneS3, zoneS4 tabM_num_old = tabM_num # tabM_num_old != tabM_num または tabM_num != 0 で終了 while tabM_num_old == tabM_num and tabS_num == 0: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(1, Item): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cntM_zone[i] += 1 if cntM_zone[i] == TOUCH_TH: tabM_num = i print(f'main tab = {tabMain_text[tabM_num]}') for i in range(1, Item): # WS MUL ADSR DAM の4つ if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneStab[i] の周辺ならば # print(f'select zoneStab[{i}]') cntS_zone[i] += 1 if cntS_zone[i] == TOUCH_TH: tabS_num = i print(f'sub tab = {tabOP_text[tabS_num]}') else: time.sleep_ms(50) return tabM_num, tabS_num def select_SubGet_tab(tabM_num, tabS_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() tabMain_text = TAB.get_tabMain_text() cntM_zone = [0, 0, 0, 0, 0] # zoneM0, zoneM1, zoneM2, zoneM3, zoneM4 # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabGET_text = TAB.get_tabOP_text() cntS_zone = [0, 0, 0, 0, 0] # zoneS0, zoneS1, zoneS2, zoneS3, zoneS4 tabM_num_old = tabM_num # tabM_num_old != tabM_num または tabM_num != 0 で終了 while tabM_num_old == tabM_num and tabS_num == 0: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(1, Item): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cntM_zone[i] += 1 if cntM_zone[i] == TOUCH_TH: tabM_num = i print(f'main tab = {tabMain_text[tabM_num]}') for i in range(1, Item): # Edit, Rfid, Orig の3つ if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneStab[i] の周辺ならば # print(f'select zoneStab[{i}]') cntS_zone[i] += 1 if cntS_zone[i] >= TOUCH_TH: tabS_num = i print(f'sub tab = {tabGET_text[tabS_num]}') else: time.sleep_ms(50) return tabM_num, tabS_num def select_SubPut_tab(tabM_num, tabS_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() tabMain_text = TAB.get_tabMain_text() cntM_zone = [0, 0, 0, 0, 0] # zoneM0, zoneM1, zoneM2, zoneM3, zoneM4 # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabPUT_text = TAB.get_tabOP_text() cntS_zone = [0, 0, 0, 0, 0] # zoneS0, zoneS1, zoneS2, zoneS3, zoneS4 tabM_num_old = tabM_num # tabM_num_old != tabM_num または tabM_num != 0 で終了 while tabM_num_old == tabM_num and tabS_num == 0: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(1, Item): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cntM_zone[i] += 1 if cntM_zone[i] == TOUCH_TH: tabM_num = i print(f'main tab = {tabMain_text[tabM_num]}') for i in range(1, Item): # Edit, Rfid の2つ if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneStab[i] の周辺ならば # print(f'select zoneStab[{i}]') cntS_zone[i] += 1 if cntS_zone[i] == TOUCH_TH: tabS_num = i print(f'sub tab = {tabPUT_text[tabS_num]}') else: time.sleep_ms(50) return tabM_num, tabS_num # 指定された 開始座標 zs から width, height, 太さ xbt # color_lineで指定された枠、color_backで指定された背景色を表示する。 # 中のテキスト行は、dsp_text_bar(text, zs, chr_num, color_back, color_text) を使う。 # 行は 20 Pixel単位、文字は 16 Pixel 単位になる def dsp_WindowFrame(zs, width, height, color_line, color_back): # zs: WindowFrame の開始座標 # xbt = 4 # line X 縦線の太さ(pixel数) # ybt = 4 # line Y 横線の太さ(pixel数) # 大きな四角の内側に小さな四角を描き、差分を枠線として表示する # zx zy w h color_line LCD.fill_rect(zs[0] , zs[1], width, height, color_line) LCD.fill_rect(zs[0] +xbt, zs[1] +ybt, width -xbt *2, height -ybt *2, color_back) # 指定された開始座標の内側に 背景と テキストを表示する ・・・ chr_num を指定する汎用タイプ # 20 Pixel 毎に行を構成することを前提 def dsp_text_bar(text, zs, chr_num, color_back, color_text): # zs: 開始座標 # chr_num: テキスト の文字幅 # chr_w = 16 # chr_h = 16 xbt2 = 2 # 文字背景の X 周囲(pixel数) ybt2 = 2 # 文字背景の X 周囲(pixel数) LCD.fill_rect(zs[0], zs[1], chr_w *chr_num +xbt2*2, chr_h +ybt2*2, color_back) LCD.text_scaled(text,zs[0] +xbt2, zs[1] +ybt2, color_text, 2) # 指定された開始座標の内側に 背景と テキストを表示して末尾の次にカーソルを表示する # 20 Pixel 毎に行を構成することを前提に、編集中の文字表示とカーソル表示をする def dsp_text_cursor(text, zs, chr_num, color_back, color_text, blink = 0): # text 編集中の文字 # zs: 開始座標 # chr_num: テキスト の文字幅 ・・・ 表示バーは +1 # chr_w = 16 # chr_h = 16 xbt2 = 2 # 文字背景の X 周囲(pixel数) ybt2 = 2 # 文字背景の X 周囲(pixel数) LCD.fill_rect(zs[0], zs[1], chr_w *(chr_num +1) +xbt2*2, chr_h +ybt2*2, color_back) # len(text) == 0 だとエラーになるのを回避するため スペースを表示する if len(text) > 0: LCD.text_scaled(text, zs[0] +xbt2, zs[1] +ybt2, color_text, 2) else: LCD.text_scaled(' ', zs[0] +xbt2, zs[1] +ybt2, color_text, 2) # カーソル表示 文字領域の左端 2 Pixel if blink == 0: LCD.fill_rect(zs[0] +chr_w *len(text) +xbt2, zs[1] +ybt2, xbt2*2, chr_h, LCD.BLACK) else: LCD.fill_rect(zs[0] +chr_w *len(text) +xbt2, zs[1] +ybt2, xbt2*2, chr_h, LCD.GRAY) # テキスト表示の外側に四角の枠を描き、中にテキストを表示する ・・・ chr_num を指定する汎用タイプ def dsp_text_frame(text, zs, chr_num, color_line, color_back, color_text): # zs:テキスト表示開始座標 # chr_num: テキスト の文字幅 # chr_w = 16 # chr_h = 16 # xbt = 4 # line X 縦線の太さ(pixel数) # ybt = 4 # line Y 横線の太さ(pixel数) # ZS 範囲外を是正 zs[0] = xbt *2 if zs[0] < xbt *2 else zs[0] zs[1] = ybt *2 if zs[1] < ybt *2 else zs[1] # 大きな四角の内側に少し小さな四角を描き、差分を枠線として表示する LCD.fill_rect(zs[0] -xbt*2, zs[1] -ybt*2, chr_w *chr_num +xbt*4, chr_h +ybt*4, color_line) LCD.fill_rect(zs[0] -xbt*1, zs[1] -ybt*1, chr_w *chr_num +xbt*2, chr_h +ybt*2, color_back) LCD.text_scaled(text,zs[0], zs[1], color_text, 2) # タブ の四角の枠とタブの名前を表示する ・・・ main-menu と sub-menu 表示に特化 def dsp_tab(tab_name, zs, color_line, color_back, color_text): # zs:TAB LABEL 開始座標 = 大きな外枠の開始座標 # 大きな四角の内側に小さな四角を描き、差分を枠線として表示する LCD.fill_rect(zs[0], zs[1], chr_w *chr_n +xbt*2, chr_h +ybt*2, color_line) LCD.fill_rect(zs[0] +xbt, zs[1] +ybt, chr_w *chr_n, chr_h, color_back) LCD.text_scaled(tab_name, zs[0] +xbt, zs[1] +ybt, color_text, 2) # main menu def dsp_menu_main(tabM_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() tabMain_text = TAB.get_tabMain_text() # Main Tab エリアのみ消去 # LCD.fill_rect(0, 0, 320, 24, LCD.BLACK) clearMainTab(LCD.BLACK) # Non High Light for i in range(1, Item): dsp_tab(tabMain_text[i] , zoneMtab_s[i], LCD.BLUE, LCD.GREEN, LCD.BLACK) # High Light if tabM_num > 0 and tabM_num < Item: dsp_tab(tabMain_text[tabM_num] , zoneMtab_s[tabM_num], LCD.YELLOW, LCD.WHITE, LCD.RED) LCD.show() # op-sub-menu def dsp_menu_op(tabS_num): # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabOP_text = TAB.get_tabOP_text() # Sub Tab エリアのみ消去 # LCD.fill_rect(0,240, 320, 24, LCD.BLACK) clearSubTab(LCD.BLACK) # Non High Light for i in range(1, Item): dsp_tab(tabOP_text[i] , zoneStab_s[i], LCD.BLUE, LCD.GREEN, LCD.BLACK) # High Light --- tabS_num 1:WS 2:MUL 3:ADSR 4:DAM if tabS_num > 0 and tabS_num < Item: dsp_tab(tabOP_text[tabS_num] , zoneStab_s[tabS_num], LCD.YELLOW, LCD.WHITE, LCD.RED) LCD.show() # get-sub-menu def dsp_menu_get(tabS_num): # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabGET_text = TAB.get_tabGET_text() # Sub Tab エリアのみ消去 # LCD.fill_rect(0,240, 320, 24, LCD.BLACK) clearSubTab(LCD.BLACK) # Non High Light for i in range(1, Item): dsp_tab(tabGET_text[i] , zoneStab_s[i], LCD.BLUE, LCD.GREEN, LCD.BLACK) # High Light --- tabS_num 1:WS 2:MUL 3:ADSR 4:DAM if tabS_num > 0 and tabS_num < Item: dsp_tab(tabGET_text[tabS_num] , zoneStab_s[tabS_num], LCD.YELLOW, LCD.WHITE, LCD.RED) LCD.show() # put-sub-menu def dsp_menu_put(tabS_num): # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() tabPUT_text = TAB.get_tabPUT_text() # Sub Tab エリアのみ消去 # LCD.fill_rect(0,240, 320, 24, LCD.BLACK) clearSubTab(LCD.BLACK) # Non High Light for i in range(1, Item): dsp_tab(tabPUT_text[i] , zoneStab_s[i], LCD.BLUE, LCD.GREEN, LCD.BLACK) # High Light --- tabS_num 1:WS 2:MUL 3:ADSR 4:DAM if tabS_num > 0 and tabS_num < Item: dsp_tab(tabPUT_text[tabS_num] , zoneStab_s[tabS_num], LCD.YELLOW, LCD.WHITE, LCD.RED) LCD.show() # com-sub-menu def dsp_menu_com(tabS_num): # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() tabCOM_text = TAB.get_tabCOM_text() # Sub Tab エリアのみ消去 # LCD.fill_rect(0,240, 320, 24, LCD.BLACK) clearSubTab(LCD.BLACK) # Non High Light for i in range(1, Item): dsp_tab(tabCOM_text[i] , zoneStab_s[i], LCD.BLUE, LCD.GREEN, LCD.BLACK) # High Light --- tabS_num 1:ALG 2:BO 3:LFO if tabS_num > 0 and tabS_num < Item: dsp_tab(tabCOM_text[tabS_num] , zoneStab_s[tabS_num], LCD.YELLOW, LCD.WHITE, LCD.RED) LCD.show() def dsp_menu_sub(tabM_num, tabS_num): # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() if tabM_num == 1: dsp_menu_get(tabS_num) elif tabM_num == 2: dsp_menu_com(tabS_num) elif tabM_num == 3: dsp_menu_op(tabS_num) elif tabM_num == 4: dsp_menu_put(tabS_num) else: # Sub Tab エリアのみ消去 # LCD.fill_rect(0,240, 320, 24, LCD.BLACK) clearSubTab(LCD.BLACK) # 無地で空欄を表示 for i in range(1, Item): dsp_tab(' ' , zoneStab_s[i], LCD.BLUE, LCD.GREEN, LCD.BLACK) LCD.show() # 20250914-2118 Change タブ表示のみ def dsp_menu(tabM_num, tabS_num): # 現在の設定内容を表示 dsp_menu_main(tabM_num) dsp_menu_sub(tabM_num, tabS_num) LCD.show() # タブ表示と不備なら編集 def edit_menu(tabM_num, tabS_num, processMsg = ''): # 現在の設定内容を表示 dsp_menu_main(tabM_num) dsp_menu_sub(tabM_num, tabS_num) # main-tab が設定されていない(tabM_num == 0)なら設定画面を表示し設定する while tabM_num == 0: dspFillUpper(LCD.WHITE) dspFillLower(LCD.WHITE) LCD.show() # display 'Select Main Tab' at the upper zs = [10, 60] text = processMsg chr_num = len(processMsg) if chr_num > 0: dsp_text_bar(text, zs, chr_num, LCD.YELLOW, LCD.RED) text = ' Select Main Tab !' chr_num = len(text) # text 表示開始座標を設定 zs = [None] *2 zs[0] = UPzs[0] +10 zs[1] = UPzs[1] +100 dsp_text_frame(text, zs, chr_num, LCD.RED, LCD.YELLOW, LCD.RED) LCD.show() (tabM_num) = select_main_tab(tabM_num) dspFillUpper(LCD.WHITE) LCD.show() # 現在の設定内容を表示 dsp_menu_main(tabM_num) dsp_menu_sub(tabM_num, tabS_num) tabM_num_old = tabM_num # sub-tab が設定されていない(tabS_num == 0)なら設定画面を表示し設定する # main_tab 変更も受け付ける while tabS_num == 0 and tabM_num_old == tabM_num: dspFillLower(LCD.WHITE) LCD.show() # display 'Select Sub Tab' at the lower text = ' Select Sub Tab !' chr_num = len(text) # text 表示開始座標を設定 zs = [None] *2 zs[0] = LWzs[0] +10 zs[1] = LWzs[1] +80 dsp_text_frame(text, zs, chr_num, LCD.RED, LCD.YELLOW, LCD.RED) LCD.show() if tabM_num == 1: (tabM_num, tabS_num) = select_SubGet_tab(tabM_num, tabS_num) elif tabM_num == 2: (tabM_num, tabS_num) = select_SubCom_tab(tabM_num, tabS_num) elif tabM_num == 3: (tabM_num, tabS_num) = select_SubOp_tab(tabM_num, tabS_num) elif tabM_num == 4: (tabM_num, tabS_num) = select_SubPut_tab(tabM_num, tabS_num) dspFillLower(LCD.WHITE) LCD.show() # 現在の設定内容を表示 dsp_menu_main(tabM_num) dsp_menu_sub(tabM_num, tabS_num) return (tabM_num, tabS_num) # tabM_num == 0 の時に実行させる def select_MainMenu(tabM_num, processMsg = ''): dspFillUpper(LCD.WHITE) dspFillLower(LCD.WHITE) text = processMsg chr_num = len(processMsg) if chr_num > 0: zs = [10, 60] dsp_text_bar(text, zs, chr_num, LCD.YELLOW, LCD.RED) # display 'Select Main Tab' at the upper text = ' Select Main Tab !' chr_num = len(text) # text 表示開始座標を設定 # zs = [None] *2 zs = [UPzs[0] +10, UPzs[1] +100] dsp_text_frame(text, zs, chr_num, LCD.RED, LCD.YELLOW, LCD.RED) LCD.show() # main-tab が設定されていない(tabM_num == 0)なら設定画面を表示し設定する while tabM_num == 0: # main tab の選択 (tabM_num) = select_main_tab(tabM_num) dspFillUpper(LCD.WHITE) LCD.show() # 現在の設定内容を表示 dsp_menu_main(tabM_num) # dsp_menu_sub(tabM_num, tabS_num) return tabM_num # tabS_num == 0 の時に実行させる def select_SubMenu(tabM_num, tabS_num): tabM_num_old = tabM_num # sub-tab が設定されていない(tabS_num == 0)なら設定画面を表示し設定する # main_tab 変更も受け付ける while tabS_num == 0 and tabM_num_old == tabM_num: dspFillLower(LCD.WHITE) text = ' Select Sub Tab !' chr_num = len(text) # text 表示開始座標を設定 zs = [None] *2 zs[0] = LWzs[0] +10 zs[1] = LWzs[1] +80 dsp_text_frame(text, zs, chr_num, LCD.RED, LCD.YELLOW, LCD.RED) LCD.show() if tabM_num == 1: (tabM_num, tabS_num) = select_SubGet_tab(tabM_num, tabS_num) elif tabM_num == 2: (tabM_num, tabS_num) = select_SubCom_tab(tabM_num, tabS_num) elif tabM_num == 3: (tabM_num, tabS_num) = select_SubOp_tab(tabM_num, tabS_num) elif tabM_num == 4: (tabM_num, tabS_num) = select_SubPut_tab(tabM_num, tabS_num) dspFillLower(LCD.WHITE) LCD.show() # 現在の設定内容を表示 dsp_menu_main(tabM_num) dsp_menu_sub(tabM_num, tabS_num) return tabM_num, tabS_num ######################################################################################## def dspWS(now_WS): xs = 0 ys = 264 # 240~259:[WS]Tab 260~263:Line w = 64 # セルの全体幅 h = 36 # セルの全体高さ zx = xs +w *4 # 256 zy = ys +h *5 # 444 tx = zx +16 ty = zy +10 # WS 数値表示 文字領域を 緑色にしてから表示 LCD.fill_rect(zx, zy, w, h, LCD.GREEN) LCD.text_scaled(f'{now_WS:>2}', tx, ty, LCD.PURPLE, 2) # AR TL SL DR SR RR の数値を表示する(編集中に再表示するので集約した) def dspAR(now_AR): # AR 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect( 10,ADSRys+160,16*5,20, LCD.WHITE) LCD.text_scaled(f'AR:{now_AR}', 10,ADSRys+160,LCD.PURPLE, 2) def dspRR(now_RR): # RR 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(240,ADSRys+160,16*5,20, LCD.WHITE) LCD.text_scaled(f'RR:{now_RR}',240,ADSRys+160,LCD.PURPLE, 2) def dspTL(now_TL): # TL 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(120, ADSRys+180, 16*5,20, LCD.WHITE) LCD.text_scaled(f'TL:{now_TL}', 120, ADSRys+180,LCD.PURPLE, 2) def dspDR(now_DR): # DR 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(230, ADSRys+10,16*5,20, LCD.WHITE) LCD.text_scaled(f'DR:{now_DR}',230, ADSRys+10,LCD.PURPLE, 2) def dspSL(now_SL): # SL 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(230, ADSRys+30,16*5,20, LCD.WHITE) LCD.text_scaled(f'SL:{now_SL}',230, ADSRys+30,LCD.PURPLE, 2) def dspSR(now_SR): # SR 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(240, ADSRys+50,16*5,20, LCD.WHITE) LCD.text_scaled(f'SR:{now_SR}',240, ADSRys+50,LCD.PURPLE, 2) def dsp_KSL(now_KSL): # KSL 数値表示 背景を黄色にし、文字色は紫色 if now_KSL == 3: LCD.fill_rect(10,ADSRys+70,16*3,20, LCD.YELLOW) # KSL = 3 LCD.text_scaled(f'6.0', 10,ADSRys+70 +2,LCD.PURPLE, 2) # KSL=3 elif now_KSL == 1: LCD.fill_rect(10,ADSRys+90,16*3,20, LCD.YELLOW) # KSL = 1 LCD.text_scaled(f'3.0', 10,ADSRys+90 +2,LCD.PURPLE, 2) # KSL=1 elif now_KSL == 2: LCD.fill_rect(10,ADSRys+110,16*3,20, LCD.YELLOW) # KSL = 2 LCD.text_scaled(f'1.5', 10,ADSRys+110 +2,LCD.PURPLE, 2) # KSL=2 else: LCD.fill_rect(10,ADSRys+130,16*3,20, LCD.YELLOW) # KSL = 0 LCD.text_scaled(f'0.0', 10,ADSRys+130 +2,LCD.PURPLE, 2) # KSL=0 def dsp_KSR(now_KSR): # KSR 数値表示 背景を黄色にし、文字色は紫色 if now_KSR == 1: LCD.fill_rect(260,ADSRys+100,16*3,20, LCD.YELLOW) # KSR = 1 LCD.text_scaled(f'on ',260,ADSRys+100 +2,LCD.PURPLE, 2) # KSR=1 else: LCD.fill_rect(260,ADSRys+120,16*3,20, LCD.YELLOW) # KSR = 0 LCD.text_scaled(f'off',260,ADSRys+120 +2,LCD.PURPLE, 2) # KSR=0 # ADSR 編集画面に表示 def dspMUL2(now_MUL): # MUL 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(10, ADSRys +3, 16 *3, 20 *2, LCD.GRAY) LCD.text_scaled(f'MUL', 10, ADSRys +5, LCD.WHITE, 2) LCD.text_scaled(f'{now_MUL:>2}', 18, ADSRys +25, LCD.WHITE, 2) def dspMUL(now_MUL): # MUL 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(8, 270, 16*4, 20, LCD.WHITE) LCD.text_scaled(f'{now_MUL:>2}', 24, 270 +2, LCD.BLACK, 2) # 右寄せ表示 def dspDT(now_DT): # DT 数値表示 文字領域を 白色にしてから表示 # LCD.fill_rect(80+16, ys+70,16*3,20, LCD.WHITE) # LCD.text_scaled(f'{now_DT}', 80+24, ys+70+2, LCD.BLACK, 2) LCD.fill_rect(80+16, 340, 16*3, 20, LCD.WHITE) LCD.text_scaled(f'{now_DT}', 80+32, 340+2, LCD.BLACK, 2) def dsp_FB(now_FB, color_back, color_text): # FB 数値表示 背景を黄色にし、文字色は紫色 # 0 1 2 3 4 5 6 7 text_FB = [' 0 ', 'pi/16', 'pi/ 8', 'pi/ 4', 'pi/ 2', 'pi ', 'pi *2', 'pi *4'] if now_FB >= 0 and now_FB <= 7: # LCD.fill_rect(160-2, 430 -20*now_FB, 16*5 +4, 20, color_back) # LCD.text_scaled(text_FB[now_FB], 160, 430+2 -20*now_FB, color_text, 2) LCD.fill_rect(FBxs[now_FB]-2, FBys[now_FB], 16*FBcn +4, 20, color_back) LCD.text_scaled(text_FB[now_FB], FBxs[now_FB], FBys[now_FB]+2, color_text, 2) def dsp_XOF(now_XOF, color_back, color_text): # XOF 数値表示 背景を黄色にし、文字色は紫色 # 0 1 text_XOF = ['off', 'on '] if now_XOF >= 0 and now_XOF <= 1: # LCD.fill_rect(250-2, 430 -20*now_XOF, 16*3 +4, 20, color_back) # LCD.text_scaled(text_XOF[now_XOF], 250, 430+2 -20*now_XOF, color_text, 2) LCD.fill_rect(XOFxs[now_XOF]-2, XOFys[now_XOF], 16*XOFcn +4, 20, color_back) LCD.text_scaled(text_XOF[now_XOF], XOFxs[now_XOF], XOFys[now_XOF]+2, color_text, 2) def dsp_DAM(now_DAM, color_back, color_text): # DAM 数値表示 背景を黄色にし、文字色は紫色 # 0 1 2 3 text_DAM = [' 1.3dB', ' 2.8dB', ' 5.8dB', '11.8dB'] if now_DAM >= 0 and now_DAM <= 3: # LCD.fill_rect(32-2, 350 -20*now_DAM, 16*6 +4, 20, color_back) # LCD.text_scaled(text_DAM[now_DAM], 32, 350+2 -20*now_DAM, color_text, 2) LCD.fill_rect(DAMxs[now_DAM]-2, DAMys[now_DAM], 16*DAMcn +4, 20, color_back) LCD.text_scaled(text_DAM[now_DAM], DAMxs[now_DAM], DAMys[now_DAM]+2, color_text, 2) def dsp_DVB(now_DVB, color_back, color_text): # DVB 数値表示 背景を黄色にし、文字色は紫色 # 0 1 2 3 text_DVB = [' 3.4%', ' 6.7%', ' 13.5%', ' 26.8%'] if now_DVB >= 0 and now_DVB <= 3: # LCD.fill_rect(192-2, 350 -20*now_DVB, 16*6 +4, 20, color_back) # LCD.text_scaled(text_DVB[now_DVB], 192, 350+2 -20*now_DVB, color_text, 2) LCD.fill_rect(DVBxs[now_DVB]-2, DVBys[now_DVB], 16*DVBcn +4, 20, color_back) LCD.text_scaled(text_DVB[now_DVB], DVBxs[now_DVB], DVBys[now_DVB]+2, color_text, 2) def dsp_EAM(now_EAM, color_back, color_text): # EAM 数値表示 背景を黄色にし、文字色は紫色 # 0 1 text_EAM = ['off', 'on '] if now_EAM >= 0 and now_EAM <= 1: # LCD.fill_rect(32-2, 430 -20*now_EAM, 16*6 +4, 20, color_back) # LCD.text_scaled(text_EAM[now_EAM], 32, 430+2 -20*now_EAM, color_text, 2) LCD.fill_rect(EAMxs[now_EAM]-2, EAMys[now_EAM], 16*EAMcn +4, 20, color_back) LCD.text_scaled(text_EAM[now_EAM], EAMxs[now_EAM], EAMys[now_EAM]+2, color_text, 2) def dsp_EVB(now_EVB, color_back, color_text): # EVB 数値表示 背景を黄色にし、文字色は紫色 # 0 1 text_EVB = ['off', 'on '] if now_EVB >= 0 and now_EVB <= 1: # LCD.fill_rect(192-2, 430 -20*now_EVB, 16*6 +4, 20, color_back) # LCD.text_scaled(text_EVB[now_EVB], 192, 430+2 -20*now_EVB, color_text, 2) LCD.fill_rect(EVBxs[now_EVB]-2, EVBys[now_EVB], 16*EVBcn +4, 20, color_back) LCD.text_scaled(text_EVB[now_EVB], EVBxs[now_EVB], EVBys[now_EVB]+2, color_text, 2) def dsp_BO(now_BO, color_back, color_text): # BO 数値表示 背景を黄色にし、文字色は紫色 # 0 1 2 3 # 20251006 Change # text_BO = [' 2 ', ' 1 ', ' 1/2 ', ' 1/4 '] # 20251023 Change text_BO = [' 0 ', ' -1 ', ' -2 ', ' -3 '] if now_BO >= 0 and now_BO <= max_BO: LCD.fill_rect(BOxs[now_BO]-2, BOys[now_BO], 16*BOcn +4, 20, color_back) LCD.text_scaled(text_BO[now_BO], BOxs[now_BO], BOys[now_BO]+2, color_text, 2) def dsp_LFO(now_LFO, color_back, color_text): # LFO 数値表示 背景を黄色にし、文字色は紫色 # 0 1 2 3 text_LFO = ['1.8Hz', '4.0Hz', '5.9Hz', '7.0Hz'] if now_LFO >= 0 and now_LFO <= max_LFO: LCD.fill_rect(LFOxs[now_LFO]-2, LFOys[now_LFO], 16*LFOcn +4, 20, color_back) LCD.text_scaled(text_LFO[now_LFO], LFOxs[now_LFO], LFOys[now_LFO]+2, color_text, 2) def dsp_TN(now_TN, color_back, color_text): LCD.fill_rect(TNxs[now_TN], TNys[now_TN], 16*TNcn , 30, color_back) LCD.text_scaled(f'{now_TN:>2}', TNxs[now_TN]+8, TNys[now_TN]+7, color_text, 2) # Full Keyboard Button 表示 def dsp_FullKeyboard(mode_Shift, color_back, color_text): LCD.fill_rect(FKxb, FKyb, FKcw *key_c , FKch *key_r, color_back) xbt2 = 2 # 文字背景の X 周囲(pixel数) ybt2 = 2 # 文字背景の X 周囲(pixel数) xb = 8 yb = 8 # Key Top 文字表示 for y in range(key_r): for x in range(key_c): if mode_Shift == 0: # Lower LCD.text_scaled(FKv0[y][x], zone_FKs[x][y][0] +xb, zone_FKs[x][y][1] +yb, color_text, 2) else: # Upper LCD.text_scaled(FKv1[y][x], zone_FKs[x][y][0] +xb, zone_FKs[x][y][1] +yb, color_text, 2) # BS : Back Space col = 9 row = 0 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw, FKch, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw -xbt2 *2, FKch -ybt2 *2, LCD.WHITE) LCD.text_scaled('<', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) # Enter col = 9 row = 3 # chr_h = 16 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw, FKch *2, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw -xbt2 *2, FKch *2 -ybt2 *2, LCD.WHITE) LCD.text_scaled('E', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) LCD.text_scaled('n', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb +chr_h, LCD.RED, 2) LCD.text_scaled('t', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb +chr_h *2 +ybt2, LCD.RED, 2) # Shift col = 0 row = 5 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw *2, FKch, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw *2 -xbt2 *2, FKch -ybt2 *2, LCD.WHITE) LCD.text_scaled('sft', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) # Space col = 2 row = 5 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw *2, FKch, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw *2 -xbt2 *2, FKch -ybt2 *2, LCD.WHITE) LCD.text_scaled('spc', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) # 押されているボタンを 指定された背景色、文字色で表示する def dsp_btn(mode_Shift, btn, col, row, color_back, color_text): xbt2 = 2 # 文字背景の X 周囲(pixel数) ybt2 = 2 # 文字背景の X 周囲(pixel数) xb = 8 yb = 8 # 背景 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw , FKch, color_back) # 文字表示 row col が入れ替わることに留意 if mode_Shift == 0: # Lower LCD.text_scaled(FKv0[row][col], zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, color_text, 2) else: # Upper LCD.text_scaled(FKv1[row][col], zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, color_text, 2) if btn == 'BS': col = 9 row = 0 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw, FKch, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw -xbt2 *2, FKch -ybt2 *2, LCD.YELLOW) LCD.text_scaled('<', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) elif btn == 'Enter': col = 9 row = 3 # chr_h = 16 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw, FKch *2, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw -xbt2 *2, FKch *2 -ybt2 *2, LCD.YELLOW) LCD.text_scaled('E', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) LCD.text_scaled('n', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb +chr_h, LCD.RED, 2) LCD.text_scaled('t', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb +chr_h *2 +ybt2, LCD.RED, 2) elif btn == 'Shift': col = 0 row = 5 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw *2, FKch, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw *2 -xbt2 *2, FKch -ybt2 *2, LCD.YELLOW) LCD.text_scaled('sft', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) elif btn == 'Space': col = 2 row = 5 LCD.fill_rect(zone_FKs[col][row][0], zone_FKs[col][row][1], FKcw *2, FKch, LCD.RED) LCD.fill_rect(zone_FKs[col][row][0] +xbt2, zone_FKs[col][row][1] +ybt2, FKcw *2 -xbt2 *2, FKch -ybt2 *2, LCD.YELLOW) LCD.text_scaled('spc', zone_FKs[col][row][0] +xb, zone_FKs[col][row][1] +yb, LCD.RED, 2) def bold_pixel(x, y, color, scale): if scale >= 2: s = int(scale /2) x = 0 if (x -s) < 0 else x -s y = 0 if (y -s) < 0 else y -s LCD.fill_rect(x, y, scale, scale, color) # 座標ポイント zs ze で指定された2点のPixel および、その周囲の8点同士を線で描く def bold_line(zs, ze, color): for x in range(-1,2): for y in range(-1,2): LCD.line(zs[0] +x, zs[1] +y, ze[0] +x, ze[1] +y, color) # 座標ポイント で指定された2点のPixel および、右側と下側 4点同士を線で描く def bold_line2(zs, ze, color): for x in range(2): for y in range(2): LCD.line(zs[0] +x, zs[1] +y, ze[0] +x, ze[1] +y, color) # 2025/09/16-20:06 Add # OP1, OP2, OP3, OP4 の開始座標を、TAB = TabCoordinate() に書き込む # 存在しない OP3 や OP4 は [0, 0] として登録 def alg_zs_save(zl1, zl2, zl3, zl4): op_max = 5 # zlOP を保存 zlOP = [None] *op_max zlOP[0] = [0, 0] zlOP[1] = zl1 zlOP[2] = zl2 zlOP[3] = zl3 zlOP[4] = zl4 # 上段に表示する OP1 ~ OP4 の中心線の開始座標である # alg_patarn(alg, stage, color_line, color_back, color_text) の使用を前提 TAB.alg_zlOP_save(zlOP) # タッチ領域用の座標生成 scale = 2 xb = 2 # line X の太さ(pixel数) yb = 2 # line Y の太さ(pixel数) w = 8 *3 *scale +xb*2 # 52 =文字幅 8 pixel 文字 x 3文字 × 2 +4 h = 8 *scale +yb*2 # 20 =文字高さ 8 pixel × 2 +4 if zl1[0] == 0 and zl1[1] == 0: zOP1s = zl1 zOP1e = zl1 else: zOP1s = [zl1[0], zl1[1] -5*scale] zOP1e = [zOP1s[0] +w, zOP1s[1] +h] if zl2[0] == 0 and zl2[1] == 0: zOP2s = zl2 zOP2e = zl2 else: zOP2s = [zl2[0], zl2[1] -5*scale] zOP2e = [zOP2s[0] +w, zOP2s[1] +h] if zl3[0] == 0 and zl3[1] == 0: zOP3s = zl3 zOP3e = zl3 else: zOP3s = [zl3[0], zl3[1] -5*scale] zOP3e = [zOP3s[0] +w, zOP3s[1] +h] if zl4[0] == 0 and zl4[1] == 0: zOP4s = zl4 zOP4e = zl4 else: zOP4s = [zl4[0], zl4[1] -5*scale] zOP4e = [zOP4s[0] +w, zOP4s[1] +h] # タッチ領域用の座標保存 TAB.alg_zOP_save(zOP1s, zOP1e, zOP2s, zOP2e, zOP3s, zOP3e, zOP4s, zOP4e) # ALG op(オペレーション)の四角の枠と数値を表示する def alg_op(op_num_text, zl, fb,color_line, color_back, color_text, scale): xb = 2 # line X の太さ(pixel数) yb = 2 # line Y の太さ(pixel数) xf = 7 # FB line の位置 x差分 yf = 11 # FB line の位置 y差分 xt = 2 # Text の開始位置 x差分 yt = -3 # Text の開始位置 y差分 if scale == 2: zt = [zl[0] +xt*scale, zl[1] +yt*scale] zs = [zl[0] , zl[1] -5*scale] zf = [zl[0] -xf*scale, zl[1] -yf*scale] w_op = 24*scale # 文字幅 8 pixel 文字 x 3文字 h_op = 8*scale # 文字高さ else: zt = [zl[0] +xt, zl[1] +yt] zs = [zl[0] , zl[1] -5] zf = [zl[0] -xf, zl[1] -yf] w_op = 24 # 文字幅 8 pixel 文字 x 3文字 h_op = 8 # 文字高さ if scale == 2: if fb ==1: # フィードバックの枠線を描く、中抜き方式 LCD.fill_rect(zf[0], zf[1], w_op +xb*2 +xf*2*scale, yf*scale +yb ,color_line) LCD.fill_rect(zf[0] +xb, zf[1] +yb, w_op +xf*2*scale, yf*scale -yb ,LCD.WHITE) LCD.fill_rect(zs[0], zs[1], w_op +xb*2, h_op +yb*2, color_line) LCD.fill_rect(zs[0] +xb, zs[1] +yb, w_op, h_op, color_back) # LCD.text(op_num_text, zt[0], zt[1], color_text) LCD.text_scaled(op_num_text, zt[0], zt[1], color_text, scale) else: if fb ==1: # フィードバックの枠線を描く、中抜き方式 LCD.fill_rect(zf[0], zf[1], w_op +xb*2 +xf*2, yf +yb ,color_line) LCD.fill_rect(zf[0] +xb, zf[1] +yb, w_op +xf*2, yf -yb ,LCD.WHITE) LCD.fill_rect(zs[0], zs[1], w_op +xb*2, h_op +yb*2, color_line) LCD.fill_rect(zs[0] +xb, zs[1] +yb, w_op, h_op, color_back) LCD.text(op_num_text, zt[0], zt[1], color_text) # ALG Label を下段の alg表示の左側に表示 def alg_label(alg, color_back, color_text): # text 開始座標の取得 if alg >= 0 and alg <= 7: zALGs = TAB.get_zALGs() zt = zALGs[alg] LCD.fill_rect(zt[0], zt[1], 24, 32, color_back) LCD.text('ALG', zt[0], zt[1], color_text) LCD.text_scaled(f'{alg}', zt[0], zt[1] +10, color_text, 2) # 選択された alg-labelをハイライト表示するとともに、上段にも表示する def alg_label_HL(alg): alg_max = 8 for i in range(alg_max): alg_label(i, LCD.BLUEGREEN, LCD.RED) # ハイライト表示 alg_label(alg, LCD.GREEN, LCD.RED) # 表示領域の指定(mainで定義済みだが) ONLY_DOWN = 0 # 下段のみに表示 ONLY_UP = 1 # 上段のみに表示 BOTH = 2 # 上段と下段の両方に表示 # 上段の表示域をクリア dspFillUpper(LCD.WHITE) alg_on_stage = alg # 拡大して上半分に表示したい alg番号 stage = alg_on_stage *3 + ONLY_UP # 暗号化 alg_patarn(alg, stage, LCD.BLACK, LCD.YELLOW, LCD.RED) # 選択された algを 上段に表示。選択された op_num を High Light表示。 # def alg_op_HL(alg, op_num): を改名 def dsp_ALGup(alg, op_num): # 表示領域の指定(mainで定義済みだが) ONLY_DOWN = 0 # 下段のみに表示 ONLY_UP = 1 # 上段のみに表示 BOTH = 2 # 上段と下段の両方に表示 # 上段の表示域をクリア dspFillUpper(LCD.WHITE) # 指定された alg を上段に表示する alg_on_stage = alg # 拡大して上半分に表示したい alg番号 stage = alg_on_stage *3 + ONLY_UP # 暗号化 alg_patarn(alg, stage, LCD.BLACK, LCD.YELLOW, LCD.RED) # ALG OP の表示用の座標を取得 zlOP = TAB.get_zlOP() # ALG op(オペレーション)の四角の枠と数値を表示する # alg_op(op_num_text, zl, fb, color_line, color_back, color_text, scale) if alg == 0 or alg == 1: for i in range(1, 3): op_num_text = f' {i} ' zl = zlOP[i] fb = 0 # FB Line なし if i == op_num: # High Light 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.GREEN, LCD.RED, 2) else: # Normal 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.YELLOW, LCD.RED, 2) else: for i in range(1, 5): op_num_text = f' {i} ' zl = zlOP[i] fb = 0 # FB Line なし if i == op_num: # High Light 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.GREEN, LCD.RED, 2) else: # Normal 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.YELLOW, LCD.RED, 2) # 上段に、ToneNumber ToneNmae および 選択された alg を表示 def dsp_ALG_TN(alg, op_num, tone_num, tone_name): # 表示領域の指定(mainで定義済みだが) ONLY_DOWN = 0 # 下段のみに表示 ONLY_UP = 1 # 上段のみに表示 BOTH = 2 # 上段と下段の両方に表示 # 上段の表示域をクリア dspFillUpper(LCD.WHITE) alg_on_stage = alg # 拡大して上半分に表示したい alg番号 stage = alg_on_stage *3 + ONLY_UP # 暗号化 alg_patarn(alg, stage, LCD.BLACK, LCD.YELLOW, LCD.RED) # ALG OP の表示用の座標を取得 zlOP = TAB.get_zlOP() # ALG op(オペレーション)の四角の枠と数値を表示する # alg_op(op_num_text, zl, fb, color_line, color_back, color_text, scale) if alg == 0 or alg == 1: for i in range(1, 3): op_num_text = f' {i} ' zl = zlOP[i] fb = 0 # FB Line なし if i == op_num: # High Light 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.GREEN, LCD.RED, 2) else: # Normal 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.YELLOW, LCD.RED, 2) else: for i in range(1, 5): op_num_text = f' {i} ' zl = zlOP[i] fb = 0 # FB Line なし if i == op_num: # High Light 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.GREEN, LCD.RED, 2) else: # Normal 表示 alg_op(op_num_text, zl, fb, LCD.BLACK, LCD.YELLOW, LCD.RED, 2) # ToneNumber ToneNmae を上段に表示する alg番号部分に上書き text = f'{tone_num:2}:{tone_name}' chr_num = len(text) zs = [10, 35] # dsp_text_bar(text, zs, chr_num, color_back, color_text) dsp_text_bar(text, zs, chr_num, LCD.WHITE, LCD.RED) # ALG を上段と下段の決まった位置に表示する。 # 上段に表示する場合は 2倍に拡大表示する。 # 上段のみ、下段のみ、両方の選択は def alg_patarn(alg, stage, color_line, color_back, color_text): # scale == 2 の場合は、2倍に拡大して上段に表示する。その位置の設定 zl_algS = [10, 40] # 拡大して表示する場合の開始位置 # 下半分の決まった位置に表示する各アルゴリズム基準となる OP左端の上下中心点の設定 zl_alg0 = [173 +28, 245 +12+16 +5] zl_alg1 = [ 31 +28, 245 +12+16 +5] zl_alg2 = [ 31 +28, 245 +12+16*3 +22 +3] zl_alg3 = [173, 245 +12+16*3 +3] zl_alg4 = [173, 245 +12+16*5 +22] zl_alg5 = [173 +28, 245 +12+16*7 +22] zl_alg6 = [173, 245 +12+16*9 +22*2] zl_alg7 = [ 31, 245 +12+16*5 +22*4] alg_max = 8 alg_LBs = [None] *alg_max alg_LBe = [None] *alg_max # ALG タイトル表示開始座標 alg_textS = [10, 35] # 拡大して表示する場合の開始位置 alg_LBs[0] = [165 -27, 245 +12 +10] alg_LBs[1] = [ 5, 245 +12 +10] alg_LBs[2] = [ 5, 245 +12+16*2 +22 +30] alg_LBs[3] = [165 -27, 245 +12+16*2 +10 +3] alg_LBs[4] = [165 -27, 245 +12+16*4 +22] alg_LBs[5] = [165 -27, 245 +12+16*6 +22 +10] alg_LBs[6] = [165 -27, 245 +12+16*8 +22*2 +10] alg_LBs[7] = [ 5, 245 +12+16*4 +22*4 +20] # ALG タイトル表示終末座標 text_w = 8 *3 text_h = 32 for i in range(alg_max): alg_LBe[i] = [alg_LBs[i][0] +text_w, alg_LBs[i][1] +text_h] # ALG タイトル表示座標の保存 TAB.alg_zALG_save(alg_LBs, alg_LBe) # 暗号化された stage を復号 alg_on_stage = int(stage /3) only_down = False only_up = False both = False if stage %3 == 0: only_down = True # 下半分のみ表示 elif stage %3 == 1: only_up = True # 上半分のみ表示 else: # stage %3 == 2 both = True # 両方表示 if alg == 0: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0] +28 +14 , z_op1[1]] z_je = [z_op2[0] +28 +14 , z_op2[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_je = [z_je[0]*2, z_je[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 z_op3 = [0, 0] z_op4 = [0, 0] alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg0 z_op2 = [z_op1[0] +28 +14 , z_op1[1]] z_je = [z_op2[0] +28 +14 , z_op2[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 1: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0], z_op1[1] +22] z_je = [z_op1[0] +28 +14*2, z_op1[1]] z_j1 = [z_op1[0] +28 +14 , z_op1[1]] z_j2 = [z_op2[0] +28 +14 , z_op2[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_je = [z_je[0]*2, z_je[1]*2] z_j1 = [z_j1[0]*2, z_j1[1]*2] z_j2 = [z_j2[0]*2, z_j2[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j2, color_line) bold_line2(z_j1 , z_j2, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 z_op3 = [0, 0] z_op4 = [0, 0] alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg1 z_op2 = [z_op1[0], z_op1[1] +22] z_je = [z_op1[0] +28 +14*2, z_op1[1]] z_j1 = [z_op1[0] +28 +14 , z_op1[1]] z_j2 = [z_op2[0] +28 +14 , z_op2[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j2, color_line) bold_line2(z_j1 , z_j2, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 2: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0], z_op1[1] +22] z_op3 = [z_op1[0], z_op1[1] +22*2] z_op4 = [z_op1[0], z_op1[1] +22*3] z_je = [z_op1[0] +28 +14*2, z_op1[1]] z_j1 = [z_op1[0] +28 +14 , z_op1[1]] z_j2 = [z_op2[0] +28 +14 , z_op2[1]] z_j3 = [z_op3[0] +28 +14 , z_op3[1]] z_j4 = [z_op4[0] +28 +14 , z_op4[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_op3 = [z_op3[0]*2, z_op3[1]*2] z_op4 = [z_op4[0]*2, z_op4[1]*2] z_je = [z_je[0]*2, z_je[1]*2] z_j1 = [z_j1[0]*2, z_j1[1]*2] z_j2 = [z_j2[0]*2, z_j2[1]*2] z_j3 = [z_j3[0]*2, z_j3[1]*2] z_j4 = [z_j4[0]*2, z_j4[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j2, color_line) bold_line2(z_op3, z_j3, color_line) bold_line2(z_op4, z_j4, color_line) bold_line2(z_j1 , z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) alg_op(' 3 ', z_op3, 1, color_line, color_back, color_text, 2) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg2 z_op2 = [z_op1[0], z_op1[1] +22] z_op3 = [z_op1[0], z_op1[1] +22*2] z_op4 = [z_op1[0], z_op1[1] +22*3] z_je = [z_op1[0] +28 +14*2, z_op1[1]] z_j1 = [z_op1[0] +28 +14 , z_op1[1]] z_j2 = [z_op2[0] +28 +14 , z_op2[1]] z_j3 = [z_op3[0] +28 +14 , z_op3[1]] z_j4 = [z_op4[0] +28 +14 , z_op4[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j2, color_line) bold_line2(z_op3, z_j3, color_line) bold_line2(z_op4, z_j4, color_line) bold_line2(z_j1 , z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) alg_op(' 3 ', z_op3, 1, color_line, color_back, color_text, 1) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 3: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0] , z_op1[1] +22] z_op3 = [z_op1[0] +28 +14 , z_op1[1] +22] z_op4 = [z_op1[0] +28*2 +14*3 , z_op1[1]] z_je = [z_op4[0] +28 +14 , z_op4[1]] z_j1 = [z_op1[0] +28*2 +14*2 , z_op1[1]] z_j3 = [z_op3[0] +28 +14 , z_op3[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_op3 = [z_op3[0]*2, z_op3[1]*2] z_op4 = [z_op4[0]*2, z_op4[1]*2] z_je = [z_je[0]*2, z_je[1]*2] z_j1 = [z_j1[0]*2, z_j1[1]*2] z_j3 = [z_j3[0]*2, z_j3[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j3, color_line) bold_line2(z_j1, z_j3, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 2) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg3 z_op2 = [z_op1[0] , z_op1[1] +22] z_op3 = [z_op1[0] +28 +14 , z_op1[1] +22] z_op4 = [z_op1[0] +28*2 +14*3 , z_op1[1]] z_je = [z_op4[0] +28 +14 , z_op4[1]] z_j1 = [z_op1[0] +28*2 +14*2 , z_op1[1]] z_j3 = [z_op3[0] +28 +14 , z_op3[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j3, color_line) bold_line2(z_j1, z_j3, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 1) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 4: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0] +28 +14 , z_op1[1]] z_op3 = [z_op2[0] +28 +7 , z_op1[1]] z_op4 = [z_op3[0] +28 +7 , z_op1[1]] z_je = [z_op4[0] +28 +14 , z_op2[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_op3 = [z_op3[0]*2, z_op3[1]*2] z_op4 = [z_op4[0]*2, z_op4[1]*2] z_je = [z_je[0]*2, z_je[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) # op 表示 # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 2) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg4 z_op2 = [z_op1[0] +28 +14 , z_op1[1]] z_op3 = [z_op2[0] +28 +7 , z_op1[1]] z_op4 = [z_op3[0] +28 +7 , z_op1[1]] z_je = [z_op4[0] +28 +14 , z_op2[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 1) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 5: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0] +28 +14 , z_op1[1]] z_op3 = [z_op1[0] , z_op1[1] +22] z_op4 = [z_op2[0] , z_op2[1] +22] z_je = [z_op2[0] +28 +14*2 , z_op2[1]] z_j2 = [z_op2[0] +28 +14 , z_op2[1]] z_j4 = [z_op4[0] +28 +14 , z_op4[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_op3 = [z_op3[0]*2, z_op3[1]*2] z_op4 = [z_op4[0]*2, z_op4[1]*2] z_je = [z_je[0]*2, z_je[1]*2] z_j2 = [z_j2[0]*2, z_j2[1]*2] z_j4 = [z_j4[0]*2, z_j4[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op3, z_j4, color_line) bold_line2(z_j2, z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) alg_op(' 3 ', z_op3, 1, color_line, color_back, color_text, 2) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg5 z_op2 = [z_op1[0] +28 +14 , z_op1[1]] z_op3 = [z_op1[0] , z_op1[1] +22] z_op4 = [z_op2[0] , z_op2[1] +22] z_je = [z_op2[0] +28 +14*2 , z_op2[1]] z_j2 = [z_op2[0] +28 +14 , z_op2[1]] z_j4 = [z_op4[0] +28 +14 , z_op4[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op3, z_j4, color_line) bold_line2(z_j2, z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) alg_op(' 3 ', z_op3, 1, color_line, color_back, color_text, 1) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 6: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op1 = zl_algS z_op2 = [z_op1[0] , z_op1[1] +22] z_op3 = [z_op2[0] +28 +14 , z_op2[1]] z_op4 = [z_op3[0] +28 +7 , z_op3[1]] z_je = [z_op1[0] +28*2 +7 +14*5 , z_op1[1]] z_j1 = [z_op1[0] +28*2 +7 +14*4 , z_op1[1]] z_j4 = [z_op4[0] +28 +14 , z_op4[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_op3 = [z_op3[0]*2, z_op3[1]*2] z_op4 = [z_op4[0]*2, z_op4[1]*2] z_je = [z_je[0]*2, z_je[1]*2] z_j1 = [z_j1[0]*2, z_j1[1]*2] z_j4 = [z_j4[0]*2, z_j4[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j4, color_line) bold_line2(z_j1, z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 2) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op1 = zl_alg6 z_op2 = [z_op1[0] , z_op1[1] +22] z_op3 = [z_op2[0] +28 +14 , z_op2[1]] z_op4 = [z_op3[0] +28 +7 , z_op3[1]] z_je = [z_op1[0] +28*2 +7 +14*5 , z_op1[1]] z_j1 = [z_op1[0] +28*2 +7 +14*4 , z_op1[1]] z_j4 = [z_op4[0] +28 +14 , z_op4[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j4, color_line) bold_line2(z_j1, z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 1) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) elif alg == 7: if alg == alg_on_stage and (only_up or both): # 上半分に描く 描画ポイントの設定 z_op2 = [zl_algS[0], zl_algS[1] +22] # op2 を起点にする z_op1 = [z_op2[0] +35, z_op2[1] -22] z_op3 = [z_op2[0] +28 +14, z_op2[1]] z_op4 = [z_op1[0] , z_op1[1] +22*2] z_je = [z_op1[0] +28 +21 +14, z_op1[1]] z_j1 = [z_op1[0] +28 +21 , z_op1[1]] z_j3 = [z_op3[0] +28 +14 , z_op3[1]] z_j4 = [z_op4[0] +28 +21 , z_op4[1]] # 描画ポイントを拡張する z_op1 = [z_op1[0]*2, z_op1[1]*2] z_op2 = [z_op2[0]*2, z_op2[1]*2] z_op3 = [z_op3[0]*2, z_op3[1]*2] z_op4 = [z_op4[0]*2, z_op4[1]*2] z_je = [z_je[0]*2, z_je[1]*2] z_j1 = [z_j1[0]*2, z_j1[1]*2] z_j3 = [z_j3[0]*2, z_j3[1]*2] z_j4 = [z_j4[0]*2, z_j4[1]*2] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j3, color_line) bold_line2(z_op4, z_j4, color_line) bold_line2(z_j1 , z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 2) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 2) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 2) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 2) # op1 ~ op4 座標登録 alg_zs_save(z_op1, z_op2, z_op3, z_op4) # ALG 表示(共通) zt = alg_textS LCD.text_scaled(f'ALG: {alg}', zt[0], zt[1], color_text, 2) if alg != alg_on_stage or (alg == alg_on_stage and (only_down or both)): # 下半分に描く 描画ポイントの設定 z_op2 = [zl_alg7[0], zl_alg7[1] +22] # op2 を起点にする z_op1 = [z_op2[0] +35, z_op2[1] -22] z_op3 = [z_op2[0] +28 +14, z_op2[1]] z_op4 = [z_op1[0] , z_op1[1] +22*2] z_je = [z_op1[0] +28 +21 +14, z_op1[1]] z_j1 = [z_op1[0] +28 +21 , z_op1[1]] z_j3 = [z_op3[0] +28 +14 , z_op3[1]] z_j4 = [z_op4[0] +28 +21 , z_op4[1]] # 横線を描く bold_line2(z_op1, z_je, color_line) bold_line2(z_op2, z_j3, color_line) bold_line2(z_op4, z_j4, color_line) bold_line2(z_j1 , z_j4, color_line) # op 表示 alg_op(' 1 ', z_op1, 1, color_line, color_back, color_text, 1) alg_op(' 2 ', z_op2, 0, color_line, color_back, color_text, 1) alg_op(' 3 ', z_op3, 0, color_line, color_back, color_text, 1) alg_op(' 4 ', z_op4, 0, color_line, color_back, color_text, 1) # ALG 表示 alg_label(alg, LCD.BLUEGREEN, color_text) def select_ALG(tabM_num, tabS_num, ALG_num, tone_num, tone_name): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # 上段表示エリアの開始座標と終末座標を取得 zUPs = TAB.get_zUPs() zUPe = TAB.get_zUPe() # 下段表示エリアの開始座標と終末座標を取得 zLWs = TAB.get_zLWs() zLWe = TAB.get_zLWe() ALG_max = 8 # 表示領域の指定(mainで定義済みだが) ONLY_DOWN = 0 # 下段のみに表示 ONLY_UP = 1 # 上段のみに表示 BOTH = 2 # 上段と下段の両方に表示 dspFillLower(LCD.WHITE) # ALG 全パターンの表示 ★★★ zALGs zALGe がセットされる for i in range(ALG_max): dspFillUpper(LCD.WHITE) alg = i alg_on_stage = alg # 拡大して上半分に表示したい alg番号 stage = alg_on_stage *3 + ONLY_DOWN # 暗号化 ONLY_DOWN alg_patarn(alg, stage, LCD.BLACK, LCD.YELLOW, LCD.RED) dspShow() # 選択された ALG のラベル番号の背景色変更と上段への表示 alg_label_HL(ALG_num) LCD.show() # ALG0 ~ ALG7 のラベルの座標リストを取得 ★★★ alg_patarn() を事前に実行しておくこと zALGs = TAB.get_zALGs() zALGe = TAB.get_zALGe() # cnt_zone{n] の初期化 cnt_zone = [None] * ALG_max for i in range(ALG_max): cnt_zone[i] = 0 # cnt_tabM cnt_tabS の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num # tabM_num または tabS_num が直前の状態と違うものが選択されたら終了 while tabM_num_old == tabM_num and tabS_num_old == tabS_num: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] # タッチは下段表示エリアか? if in_zone(zLWs, zLWe, X_Point, Y_Point): for i in range(ALG_max): if in_zone(zALGs[i], zALGe[i], X_Point, Y_Point): # zALG[i] の周辺ならば print(f'select zALG[{i}]') cnt_zone[i] += 1 if cnt_zone[i] >= TOUCH_TH: ALG_num = i print(f'ALG Select = {ALG_num}') # 選択された ALG のラベル番号の背景色変更と上段への表示 alg_label_HL(ALG_num) LCD.show() # mainTab のタッチで終了 if in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] >= TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 if in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] >= TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') else: # ToneNumber ToneNmae を上段の末尾に表示する alg番号部分に上書き text = f'{tone_num:2}:{tone_name}' chr_num = len(text) zs = [10, 220] # dsp_text_bar(text, zs, chr_num, color_back, color_text) dsp_text_bar(text, zs, chr_num, LCD.WHITE, LCD.RED) # cnt_zone{n] の初期化 for i in range(ALG_max): cnt_zone[i] = 0 # cnt_tabM cnt_tabS の初期化 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 LCD.show() return (tabM_num, tabS_num, ALG_num) def one_write_line(zl, color_wave): # zl[[zs], [z1], [z2], [z3], [z4], ] if len(zl) >= 2: z_end = zl[0] for i in range(1, len(zl)): z_start = z_end # y軸は、反転することに注意 z_end =[zl[0][0] +zl[i][0], zl[0][1] -zl[i][1]] bold_line(z_start, z_end, color_wave) # WS 波形をLCD下半分の決まった位置に表示する def wave_form(ws, color_back, color_wave, z=None): WS_max = 31 xs = 0 xb = 8 # 枠の幅 x ys = 264 # 240~259:[WS]Tab 260~263:Line yl = ys +18 # 240~259:[WS]Tab 260~263:Line 中央の線 yb = 3 # 枠の幅 y w = 64 # セルの全体幅 wx = 48 # セルの波形幅 h = 36 # セルの全体高さ hy = 15 # セルの波形高さの半分 sin価数を利用するため 1/2 にしている # ws 番号から描画開始位置を決めるためのテーブル # ws=0, 1, 2, 3, 4, zone_xs = [xs +w*0, xs +w*1, xs +w*2, xs +w*0, xs +w*3, \ # ws=5, 6, 7, 8, 9, xs +w*4, xs +w*0, xs +w*4, xs +w*0, xs +w*1, \ # ws=10, 11, 12, 13, 14, xs +w*2, xs +w*1, xs +w*3, xs +w*4, xs +w*1, \ # ws=15, 16, 17, 18, 19, xs +w*4, xs +w*0, xs +w*1, xs +w*2, xs +w*2, \ # ws=20, 21, 22, 23, 24, xs +w*3, xs +w*4, xs +w*2, xs +w*4, xs +w*0, \ # ws=25, 26, 27, 28, 29, 30, xs +w*1, xs +w*2, xs +w*3, xs +w*3, xs +w*4, xs +w*3] # ws=0, 1, 2, 3, 4, zone_ys = [ys +h*0, ys +h*0, ys +h*0, ys +h*5, ys +h*0, \ # ws=5, 6, 7, 8, 9, ys +h*0, ys +h*4, ys +h*4, ys +h*1, ys +h*1, \ # ws=10, 11, 12, 13, 14, ys +h*1, ys +h*5, ys +h*1, ys +h*1, ys +h*4, \ # ws=15, 16, 17, 18, 19, ys +h*5, ys +h*2, ys +h*2, ys +h*2, ys +h*5, \ # ws=20, 21, 22, 23, 24, ys +h*2, ys +h*2, ys +h*4, ys +h*5, ys +h*3, \ # ws=25, 26, 27, 28, 29, 30, ys +h*3, ys +h*3, ys +h*5, ys +h*3, ys +h*3, ys +h*4] # 波形の Y軸 0 line 上下中心線 zone_yl = [yl +h*0, yl +h*0, yl +h*0, yl +h*5, yl +h*0, \ yl +h*0, yl +h*4, yl +h*4, yl +h*1, yl +h*1, \ yl +h*1, yl +h*5, yl +h*1, yl +h*1, yl +h*4, \ yl +h*0, yl +h*2, yl +h*2, yl +h*2, yl +h*5, \ yl +h*2, yl +h*2, yl +h*4, yl +h*0, yl +h*3, \ yl +h*3, yl +h*3, yl +h*5, yl +h*3, yl +h*3, yl +h*4] # タッチ領域の開始座標 と 終末座標 zWSs = [None] * WS_max zWSe = [None] * WS_max for i in range(WS_max): zWSs[i] = [zone_xs[i], zone_ys[i]] zWSe[i] = [zone_xs[i] + w, zone_ys[i] + h] # 2025/09/16-20:06 Add # WS:0 ~ WS:31 の開始座標と終末座標を、TAB = TabCoordinate() に書き込む TAB.zWS_save(zWSs, zWSe) # 表示位置 z を指定すれば、その場所に表示できる。 if z != None: zone_xs[ws] = z[0] # 250 zone_ys[ws] = z[1] # 180 zone_yl[ws] = zone_ys[ws] +18 # color_back = LCD.GREEN # color_wave = LCD.PURPLE if ws == 0: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) for i in range(wx): xp = zone_xs[ws] +i +xb # 円周360度を 60分割してサイン波形をプロットする yp = zone_yl[ws] -int(math.sin(math.radians(i *(360/wx))) *hy) bold_pixel(xp, yp, color_wave, 3) elif ws == 1: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) for i in range(int(wx/2)+1): xp = zone_xs[ws] +i +xb # 円周360度を 60分割してサイン波形をプロットする yp = zone_yl[ws] -int(math.sin(math.radians(i *(360/wx))) *hy) bold_pixel(xp, yp, color_wave, 3) # 直線部分を描く xp = zone_xs[ws] +xb +24 yp = zone_yl[ws] # 起点 1 2 3 4 5 6 7 8 zl = [[xp,yp], [+24,0]] one_write_line(zl, color_wave) elif ws == 2: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) for i in range(wx): xp = zone_xs[ws] +i +xb # 円周360度を 60分割してサイン波形をプロットする yp = zone_yl[ws] -int(abs(math.sin(math.radians(i *(360/wx))) *hy)) bold_pixel(xp, yp, color_wave, 3) elif ws == 3: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形の 1/4 をプロットする for i in range(0, 12): xp = zone_xs[ws] +i +xb yp = zone_yl[ws] -int(abs(math.sin(math.radians(i *(360/wx))) *hy)) bold_pixel(xp, yp, color_wave, 3) # 円周360度を 60分割してサイン波形の 3/4 をプロットする for i in range(24, 36): xp = zone_xs[ws] +i +xb yp = zone_yl[ws] -int(abs(math.sin(math.radians(i *(360/wx))) *hy)) bold_pixel(xp, yp, color_wave, 3) # 直線部分を描く z1 = [zone_xs[ws] +xb +12, zone_ys[ws] +yb +0] z2 = [zone_xs[ws] +xb +12, zone_ys[ws] +yb +hy] z3 = [zone_xs[ws] +xb +24, zone_ys[ws] +yb +hy] bold_line(z1, z2, color_wave) bold_line(z2, z3, color_wave) z4 = [zone_xs[ws] +xb +36, zone_ys[ws] +yb +0] z5 = [zone_xs[ws] +xb +36, zone_ys[ws] +yb +hy] z6 = [zone_xs[ws] +xb +48, zone_ys[ws] +yb +hy] bold_line(z4, z5, color_wave) bold_line(z5, z6, color_wave) elif ws == 4: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(30+1): xp = zone_xs[ws] +i +xb *2 yp = zone_yl[ws] -int(math.sin(math.radians(i *(360/30))) *hy) bold_pixel(xp, yp, color_wave, 3) elif ws == 5: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(30+1): xp = zone_xs[ws] +i +xb *2 yp = zone_yl[ws] -int(abs(math.sin(math.radians(i *(360/30))) *hy)) bold_pixel(xp, yp, color_wave, 3) elif ws == 6: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [0,+hy], [24,+hy], [24,-hy], [48,-hy], [48,0]] one_write_line(zl, color_wave) elif ws == 7: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # サイン波形の 180~270 をプロットする for i in range(0, 24): xp = zone_xs[ws] +i +xb yp = zone_ys[ws] +yb +int(hy*2 - (abs(math.sin(math.radians(i *(360/(wx*2)) +180))) *(-1) *hy +hy*2)) bold_pixel(xp, yp, color_wave, 3) # サイン波形の 270~360 をプロットする for i in range(24, 48): xp = zone_xs[ws] +i +xb yp = zone_ys[ws] +yb +int(hy*2 - (abs(math.sin(math.radians(i *(360/(wx*2)) +0))) *hy)) bold_pixel(xp, yp, color_wave, 3) # 直線部分を描く z1 = [zone_xs[ws] +xb +0, zone_ys[ws] +yb +0] z2 = [zone_xs[ws] +xb +0, zone_ys[ws] +yb +hy] z3 = [zone_xs[ws] +xb +48, zone_ys[ws] +yb +hy*2] z4 = [zone_xs[ws] +xb +48, zone_ys[ws] +yb +hy] bold_line(z1, z2, color_wave) bold_line(z3, z4, color_wave) elif ws == 8: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(wx): xp = zone_xs[ws] +i +xb y = -int(math.sin(math.radians(i *(360/wx))) *hy) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) elif ws == 9: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(int(wx/2)+1): xp = zone_xs[ws] +i +xb y = -int(math.sin(math.radians(i *(360/wx))) *hy) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) z1 = [zone_xs[ws] +xb +24, zone_ys[ws] +yb +hy] z2 = [zone_xs[ws] +xb +48, zone_ys[ws] +yb +hy] bold_line(z1, z2, color_wave) elif ws == 10: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(wx): xp = zone_xs[ws] +i +xb y = -int(abs(math.sin(math.radians(i *(360/wx))) *hy)) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) elif ws == 11: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形の 1/4 をプロットする for i in range(0, 12): xp = zone_xs[ws] +i +xb y = -int(abs(math.sin(math.radians(i *(360/wx))) *hy)) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) # 円周360度を 60分割してサイン波形の 3/4 をプロットする for i in range(24, 36): xp = zone_xs[ws] +i +xb y = -int(abs(math.sin(math.radians(i *(360/wx))) *hy)) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) # 直線部分を描く z1 = [zone_xs[ws] +xb +12, zone_ys[ws] +yb +5] z2 = [zone_xs[ws] +xb +12, zone_ys[ws] +yb +hy] z3 = [zone_xs[ws] +xb +24, zone_ys[ws] +yb +hy] bold_line(z1, z2, color_wave) bold_line(z2, z3, color_wave) z4 = [zone_xs[ws] +xb +36, zone_ys[ws] +yb +5] z5 = [zone_xs[ws] +xb +36, zone_ys[ws] +yb +hy] z6 = [zone_xs[ws] +xb +48, zone_ys[ws] +yb +hy] bold_line(z4, z5, color_wave) bold_line(z5, z6, color_wave) elif ws == 12: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(30+1): xp = zone_xs[ws] +i +xb *2 y = -int(math.sin(math.radians(i *(360/30))) *hy) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) elif ws == 13: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 円周360度を 60分割してサイン波形をプロットする for i in range(30+1): xp = zone_xs[ws] +i +xb *2 y = -int(abs(math.sin(math.radians(i *(360/30))) *hy)) # 上限・下限を設ける if y > 11: y = 11 elif y < -11: y = -11 yp = zone_yl[ws] +y bold_pixel(xp, yp, color_wave, 3) elif ws == 14: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [0,+hy], [24,+hy], [24,0], [48,0]] one_write_line(zl, color_wave) elif ws == 15: # Notthing pass elif ws == 16: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [12,+hy], [36,-hy], [48,0]] one_write_line(zl, color_wave) elif ws == 17: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [12,+hy], [24,0], [48,0]] one_write_line(zl, color_wave) elif ws == 18: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [12,+hy], [24,0], [36,+hy], [48,0]] one_write_line(zl, color_wave) elif ws == 19: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [12,+hy], [12,0], [24,0], [36,+hy], [36,0], [48,0]] one_write_line(zl, color_wave) elif ws == 20: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb*2 yp = zone_yl[ws] zl = [[xp,yp], [7,+hy], [21,-hy], [28,0]] one_write_line(zl, color_wave) elif ws == 21: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb*2 yp = zone_yl[ws] zl = [[xp,yp], [7,+hy], [14,0], [21,+hy], [28,0]] one_write_line(zl, color_wave) elif ws == 22: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] # 起点 1 2 3 4 5 6 7 8 zl = [[xp,yp], [0,+hy], [12,+hy], [12,0], [24,0], [24,+hy], [36,+hy], [36,0], [48,0]] one_write_line(zl, color_wave) elif ws == 23: # Notthing pass elif ws == 24: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [24,+hy], [24,-hy], [48,0]] one_write_line(zl, color_wave) elif ws == 25: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [24,+hy], [24,0], [48,0]] one_write_line(zl, color_wave) elif ws == 26: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [24,+hy], [24,0], [48,+hy], [48,0]] one_write_line(zl, color_wave) elif ws == 27: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb yp = zone_yl[ws] zl = [[xp,yp], [12,+hy], [12,0], [24,0], [36,+hy], [36,0], [48,0]] one_write_line(zl, color_wave) elif ws == 28: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb*2 yp = zone_yl[ws] zl = [[xp,yp], [14,+hy], [14,-hy], [28,0]] one_write_line(zl, color_wave) elif ws == 29: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb*2 yp = zone_yl[ws] zl = [[xp,yp], [14,+hy], [14,0], [28,+hy], [28,0]] one_write_line(zl, color_wave) elif ws == 30: # 指定のセル枠を指定色で埋める LCD.fill_rect(zone_xs[ws],zone_ys[ws], w, h, color_back) # 直線部分を描く xp = zone_xs[ws] +xb*2 yp = zone_yl[ws] zl = [[xp,yp], [0,+hy], [12,+hy], [12,0], [36,0]] one_write_line(zl, color_wave) elif ws == 31: # Nothing pass def select_WS(tabM_num, tabS_num, OP_num, WS_num): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # ALG op1 ~ op4 の座標リストを取得 zOPs = TAB.get_zOPs() zOPe = TAB.get_zOPe() # 上段表示エリアの開始座標と終末座標を取得 zUPs = TAB.get_zUPs() zUPe = TAB.get_zUPe() # 下段表示エリアの開始座標と終末座標を取得 zLWs = TAB.get_zLWs() zLWe = TAB.get_zLWe() WS_max = 31 # 下段の表示領域をクリア dspFillLower(LCD.WHITE) # ws 全波形の表示 ★★★ zWSs zWSe がセットされる for ws in range(WS_max): wave_form(ws, LCD.WHITE, LCD.BLACK) # WS_num をハイライト wave_form(WS_num, LCD.YELLOW, LCD.BLACK) LCD.show() # WS:0 ~ WS:30 の座標リストを取得 ★★★ wave_form() を先に」実行すること zWSs = TAB.get_zWSs() zWSe = TAB.get_zWSe() # cnt_zone{n] の初期化 cnt_zone = [None] * WS_max for i in range(WS_max): cnt_zone[i] = 0 # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 cnt_OP = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 WS_num_old = WS_num # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num OP_num_old = OP_num while tabM_num_old == tabM_num and tabS_num_old == tabS_num and OP_num_old == OP_num: # 右下に WS 番号を表示 dspWS(WS_num) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] # 下段表示エリアか? if in_zone(zLWs, zLWe, X_Point, Y_Point): for i in range(WS_max): if in_zone(zWSs[i], zWSe[i], X_Point, Y_Point): # zWS[i] の周辺ならば # print(f'select zWS[{i}]') cnt_zone[i] += 1 if cnt_zone[i] == TOUCH_TH: WS_num = i print(f'WS Select = {WS_num}') if not(WS_num >= WS_max or WS_num == 15 or WS_num == 23): # 直前の WS の表示をハイライトではない表示に wave_form(WS_num_old, LCD.WHITE, LCD.BLACK) # 選択された WS をハイライト表示 wave_form(WS_num, LCD.YELLOW, LCD.RED) # 右下に WS 番号を表示 dspWS(WS_num) WS_num_old = WS_num # mainTab のタッチで終了 if in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば cnt_tabM[i] += 1 if cnt_tabM[i] == TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 if in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば cnt_tabS[i] += 1 if cnt_tabS[i] == TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') # OP のタッチで終了 # 上段表示エリアか? if in_zone(zUPs, zUPe, X_Point, Y_Point): for i in range(1, 5): if in_zone(zOPs[i], zOPe[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば cnt_OP[i] += 1 if cnt_OP[i] == TOUCH_TH: OP_num = i # 現在の OP 以外を選択なら表示する。現在の OP を選択なら表示しない。 if OP_num_old != OP_num: print(f'ALG OP Select = {OP_num}') else: # cnt_zone{n] の初期化 for i in range(WS_max): cnt_zone[i] = 0 # cnt_tabM cnt_tabS cntOP の初期化 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 LCD.show() return (tabM_num, tabS_num, OP_num, WS_num) # ADSR 編集 # 2025/11/03 ymf825.Voice_Op_Edit[MUL][OP_num] を追加、表示のみ def edit_adsr(tabM_num, tabS_num, OP_num, now_TL, now_SL, now_AR, now_DR, now_SR, now_RR, \ now_KSL, now_KSR, now_MUL): # 座標リストの取得 # Main Tab zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # ALG op1 ~ op4 zOPs = TAB.get_zOPs() zOPe = TAB.get_zOPe() # 上段表示エリアの開始座標と終末座標を取得 zUPs = TAB.get_zUPs() zUPe = TAB.get_zUPe() # 下段表示エリアの開始座標と終末座標を取得 zLWs = TAB.get_zLWs() zLWe = TAB.get_zLWe() # 使用するゾーンリストの生成 zone_ARTLs = [None] *2 zone_ARTLe = [None] *2 zone_DRSLs = [None] *2 zone_DRSLe = [None] *2 zone_SRs = [None] *2 zone_SRe = [None] *2 zone_RRs = [None] *2 zone_RRe = [None] *2 guide_ARTLs = [None] *2 guide_ARTLe = [None] *2 guide_DRSLs = [None] *2 guide_DRSLe = [None] *2 guide_SRs = [None] *2 guide_SRe = [None] *2 guide_RRs = [None] *2 guide_RRe = [None] *2 cnt_ARTL = 0 cnt_SL = 0 cnt_DRSL = 0 cnt_SR = 0 cnt_RR = 0 cnt_KSL0 = 0 cnt_KSL1 = 0 cnt_KSL2 = 0 cnt_KSL3 = 0 cnt_KSR0 = 0 cnt_KSR1 = 0 # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 cnt_OP = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num OP_num_old = OP_num edt_mode = '' flag_begin = 1 while tabM_num_old == tabM_num and tabS_num_old == tabS_num and OP_num_old == OP_num: # 下面の編集 # スライダーポイントの座標設定(Pixcel単位):縮小値 pos_KEYON = [0, 63] # pos_KEYON = [0, 63] pos_ARTL = [23 -now_AR, now_TL] # pos_DRSL = [47 -now_DR, now_TL +now_SL] # pos_ARTL と重ならないよう右に 4 Pixel シフト pos_DRSL = [(23 -now_AR) + (15 -now_DR) +4, now_TL +now_SL] pos_SR = [55, now_TL +now_SL +now_SR] pos_RR = [79 -now_RR, 63] # 座標位置を3倍の位置に展開 pos_KEYON = [ADSRxs +pos_KEYON[0] *3, ADSRys +pos_KEYON[1] *3] pos_ARTL = [ADSRxs +pos_ARTL[0] *3, ADSRys +pos_ARTL[1] *3] pos_DRSL = [ADSRxs +pos_DRSL[0] *3, ADSRys +pos_DRSL[1] *3] pos_SR = [ADSRxs +pos_SR[0] *3, ADSRys +pos_SR[1] *3] pos_RR = [ADSRxs +pos_RR[0] *3, ADSRys +pos_RR[1] *3] # タッチペンで触れた時に反応するゾーンの設定 zone_ARTLs[0] = 0 if pos_ARTL[0] < TOUCH else pos_ARTL[0] - TOUCH zone_ARTLs[1] = 0 if pos_ARTL[1] < TOUCH else pos_ARTL[1] - TOUCH zone_ARTLe[0] = 319 if (pos_ARTL[0] + TOUCH) >= 320 else pos_ARTL[0] + TOUCH zone_ARTLe[1] = 479 if (pos_ARTL[1] + TOUCH) >= 480 else pos_ARTL[1] + TOUCH zone_DRSLs[0] = 0 if pos_DRSL[0] < TOUCH else pos_DRSL[0] - TOUCH zone_DRSLs[1] = 0 if pos_DRSL[1] < TOUCH else pos_DRSL[1] - TOUCH zone_DRSLe[0] = 319 if (pos_DRSL[0] + TOUCH) >= 320 else pos_DRSL[0] + TOUCH zone_DRSLe[1] = 479 if (pos_DRSL[1] + TOUCH) >= 480 else pos_DRSL[1] + TOUCH zone_SRs[0] = 0 if pos_SR[0] < TOUCH else pos_SR[0] - TOUCH zone_SRs[1] = 0 if pos_SR[1] < TOUCH else pos_SR[1] - TOUCH zone_SRe[0] = 319 if (pos_SR[0] + TOUCH) >= 320 else pos_SR[0] + TOUCH zone_SRe[1] = 479 if (pos_SR[1] + TOUCH) >= 480 else pos_SR[1] + TOUCH # パネルの周囲は精度が出ないので倍の大きさにする。 zone_RRs[0] = 0 if pos_RR[0] < TOUCH *2 else pos_RR[0] - TOUCH *2 zone_RRs[1] = 0 if pos_RR[1] < TOUCH *2 else pos_RR[1] - TOUCH *2 zone_RRe[0] = 319 if (pos_RR[0] + TOUCH *2) >= 320 else pos_RR[0] + TOUCH *2 zone_RRe[1] = 479 if (pos_RR[1] + TOUCH *2) >= 480 else pos_RR[1] + TOUCH *2 ######################################################################## # AR TL 操作可能エリア slide_ARTLs = [23 -max_AR, 0] # slide_ARTLe = [23 +2, max_TL +2] slide_ARTLe = [23, max_TL] # DR SL 操作可能エリア pos_ARTL と重ならないよう右に 4 Pixel シフト slide_DRSLs = [(23 -now_AR) +4, now_TL] # slide_DRSLe = [(23 -now_AR) +4 +max_DR +2, now_TL +max_SL +2] slide_DRSLe = [(23 -now_AR) +4 +max_DR, now_TL +max_SL] # SR 直線上の設定範囲 slide_SRs = [55, now_TL +now_SL] slide_SRe = [55, now_TL +now_SL +max_SR +2] # RR 直線上の設定範囲 slide_RRs = [63, 63] slide_RRe = [63 +max_RR, 63] # 操作ガイドを3倍の位置に展開 slide_ARTLs = [ADSRxs +slide_ARTLs[0] *3, ADSRys +slide_ARTLs[1] *3] slide_ARTLe = [ADSRxs +slide_ARTLe[0] *3, ADSRys +slide_ARTLe[1] *3] slide_ARTLw = slide_ARTLe[0] - slide_ARTLs[0] slide_ARTLh = slide_ARTLe[1] - slide_ARTLs[1] slide_DRSLs = [ADSRxs +slide_DRSLs[0] *3, ADSRys +slide_DRSLs[1] *3] slide_DRSLe = [ADSRxs +slide_DRSLe[0] *3, ADSRys +slide_DRSLe[1] *3] slide_DRSLw = slide_DRSLe[0] - slide_DRSLs[0] slide_DRSLh = slide_DRSLe[1] - slide_DRSLs[1] slide_SRs = [ADSRxs +slide_SRs[0] *3, ADSRys +slide_SRs[1] *3] slide_SRe = [ADSRxs +slide_SRe[0] *3, ADSRys +slide_SRe[1] *3] slide_RRs = [ADSRxs +slide_RRs[0] *3, ADSRys +slide_RRs[1] *3] slide_RRe = [ADSRxs +slide_RRe[0] *3, ADSRys +slide_RRe[1] *3] # 長方形の操作可能範囲 16 Pixcel guide_ARTLs[0] = 0 if slide_ARTLs[0] < TOUCH else slide_ARTLs[0] - TOUCH guide_ARTLs[1] = 0 if slide_ARTLs[1] < TOUCH else slide_ARTLs[1] - TOUCH guide_ARTLe[0] = 319 if (slide_ARTLe[0] + TOUCH) >= 320 else slide_ARTLe[0] + TOUCH guide_ARTLe[1] = 479 if (slide_ARTLe[1] + TOUCH) >= 480 else slide_ARTLe[1] + TOUCH guide_DRSLs[0] = 0 if slide_DRSLs[0] < TOUCH else slide_DRSLs[0] - TOUCH guide_DRSLs[1] = 0 if slide_DRSLs[1] < TOUCH else slide_DRSLs[1] - TOUCH guide_DRSLe[0] = 319 if (slide_DRSLe[0] + TOUCH) >= 320 else slide_DRSLe[0] + TOUCH guide_DRSLe[1] = 479 if (slide_DRSLe[1] + TOUCH) >= 480 else slide_DRSLe[1] + TOUCH guide_SRs[0] = 0 if slide_SRs[0] < TOUCH *2 else slide_SRs[0] - TOUCH *2 guide_SRs[1] = 0 if slide_SRs[1] < TOUCH else slide_SRs[1] - TOUCH guide_SRe[0] = 319 if (slide_SRe[0] + TOUCH) >= 320 else slide_SRe[0] + TOUCH guide_SRe[1] = 479 if (slide_SRe[1] + TOUCH) >= 480 else slide_SRe[1] + TOUCH guide_RRs[0] = 0 if slide_RRs[0] < TOUCH *2 else slide_RRs[0] - TOUCH *2 guide_RRs[1] = 0 if slide_RRs[1] < TOUCH *2 else slide_RRs[1] - TOUCH *2 guide_RRe[0] = 319 if (slide_RRe[0] + TOUCH) >= 320 else slide_RRe[0] + TOUCH guide_RRe[1] = 479 if (slide_RRe[1] + TOUCH) >= 480 else slide_RRe[1] + TOUCH dspFillLower(LCD.WHITE) # AR TL 操作ガイドを表示 LCD.fill_rect(slide_ARTLs[0], slide_ARTLs[1], slide_ARTLw, slide_ARTLh, LCD.YELLOW) # SR SL 操作ガイドを表示 LCD.fill_rect(slide_DRSLs[0], slide_DRSLs[1], slide_DRSLw, slide_DRSLh, LCD.BLUEGREEN) # slide Line 水平方向のガイド(水平方向に5回線を引く) # RR for y in range(5): # LCD.line(slide_RRs[0], slide_RRs[1]+y, slide_RRe[0]+4, slide_RRe[1]+y, LCD.GREEN) LCD.line(slide_RRs[0] -2, slide_RRs[1]+y -2, slide_RRe[0] +2, slide_RRe[1]+y -2, LCD.GREEN) # slide Line 垂直方向のガイド(垂直方向に5回線を引く) # SR for x in range(5): # LCD.line(slide_SRs[0]+x, slide_SRs[1], slide_SRe[0]+x, slide_SRe[1]+4, LCD.GREEN) LCD.line(slide_SRs[0]+x -2, slide_SRs[1] -2, slide_SRe[0]+x -2, slide_SRe[1] +2, LCD.GREEN) # ADSR Line for x in range(-2, 3): for y in range(-2, 3): LCD.line(pos_KEYON[0]+x, pos_KEYON[1]+y, pos_ARTL[0]+x, pos_ARTL[1]+y, LCD.BLUE) LCD.line(pos_ARTL[0]+x, pos_ARTL[1]+y, pos_DRSL[0]+x, pos_DRSL[1]+y, LCD.BLUE) LCD.line(pos_DRSL[0]+x, pos_DRSL[1]+y, pos_SR[0]+x, pos_SR[1]+y, LCD.BLUE) LCD.line(pos_SR[0]+x, pos_SR[1]+y, pos_RR[0]+x, pos_RR[1]+y, LCD.BLUE) # AR・TL DR・SL SR RR の操作ポイント(サイズ 8x8)を表示する LCD.fill_rect(pos_ARTL[0] -4, pos_ARTL[1] -4, TOUCH, TOUCH, LCD.RED) LCD.fill_rect(pos_DRSL[0] -4, pos_DRSL[1] -4, TOUCH, TOUCH, LCD.RED) LCD.fill_rect(pos_SR[0] -4, pos_SR[1] -4, TOUCH, TOUCH, LCD.RED) LCD.fill_rect(pos_RR[0] -4, pos_RR[1] -4, TOUCH, TOUCH, LCD.RED) # AR TL SL DR SR RR の数値を表示する(編集中に再表示することに留意) dspAR(now_AR) dspRR(now_RR) dspTL(now_TL) dspDR(now_DR) dspSL(now_SL) dspSR(now_SR) # 2025/11/03 MUL 表示追加(編集はしない) dspMUL2(now_MUL) # KSL タッチゾーンの設定 zone_KSL0s = [10,ADSRys+130] zone_KSL0e = [zone_KSL0s[0] +16*3,zone_KSL0s[1]+20] zone_KSL1s = [10,ADSRys+90] zone_KSL1e = [zone_KSL1s[0] +16*3,zone_KSL1s[1]+20] zone_KSL2s = [10,ADSRys+110] zone_KSL2e = [zone_KSL2s[0] +16*3,zone_KSL2s[1]+20] zone_KSL3s = [10,ADSRys+70] zone_KSL3e = [zone_KSL3s[0] +16*3,zone_KSL3s[1]+20] # KSL の表示 LCD.text_scaled(f'KSL', 10,320,LCD.BLACK, 2) # KSL 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 LCD.fill_rect(10,ADSRys+70,16*3,20*4, LCD.GREEN) LCD.text_scaled(f'6.0', 10,ADSRys+70 +2,LCD.GRAY, 2) # KSL=3 LCD.text_scaled(f'3.0', 10,ADSRys+90 +2,LCD.GRAY, 2) # KSL=1 LCD.text_scaled(f'1.5', 10,ADSRys+110 +2,LCD.GRAY, 2) # KSL=2 LCD.text_scaled(f'0.0', 10,ADSRys+130 +2,LCD.GRAY, 2) # KSL=0 # KSL 設定値の表示 dsp_KSL(now_KSL) # KSR タッチゾーンの設定 zone_KSR0s = [260,ADSRys+120] zone_KSR0e = [zone_KSR0s[0] +16*3,zone_KSR0s[1]+20] zone_KSR1s = [260,ADSRys+100] zone_KSR1e = [zone_KSR1s[0] +16*3,zone_KSR1s[1]+20] # KSR エリアの表示 LCD.text_scaled(f'KSR',260,ADSRys+80,LCD.BLACK, 2) # KSR 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 LCD.fill_rect(260,ADSRys+100,16*3,20*2, LCD.GREEN) LCD.text_scaled(f'on',260,ADSRys+100,LCD.GRAY, 2) # KSR=1 LCD.text_scaled(f'off',260,ADSRys+120,LCD.GRAY, 2) # KSR=0 dsp_KSR(now_KSR) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] if edt_mode == '': if in_zone(zone_ARTLs, zone_ARTLe, X_Point, Y_Point): # AR・TL ポイント周辺ならば # print('zone_ARTL') cnt_ARTL += 1 if cnt_ARTL == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point edt_mode = 'ARTL' print("edt_mode = 'ARTL'") elif in_zone(zone_DRSLs, zone_DRSLe, X_Point, Y_Point): # DR・SL ポイント周辺ならば # print('zone_DRSL') cnt_DRSL += 1 if cnt_DRSL == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point edt_mode = 'DRSL' print("edt_mode = 'DRSL'") elif in_zone(zone_RRs, zone_RRe, X_Point, Y_Point): # RR ポイント周辺ならば # print('zone_RR') cnt_RR += 1 if cnt_RR == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point edt_mode = 'RR' print("edt_mode = 'RR'") elif in_zone(zone_SRs, zone_SRe, X_Point, Y_Point): # SR ポイント周辺ならば # print('zone_SR') cnt_SR += 1 if cnt_SR == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point edt_mode = 'SR' print("edt_mode = 'SR'") elif in_zone(zone_KSL0s, zone_KSL0e, X_Point, Y_Point): # KSL0 ポイントならば # print('zone_KSL0') cnt_KSL0 += 1 if cnt_KSL0 == TOUCH_TH: now_KSL = 0 print('select_KSL0') # KSL 数値表示 背景を黄色にし、文字色は紫色 dsp_KSL(now_KSL) elif in_zone(zone_KSL1s, zone_KSL1e, X_Point, Y_Point): # KSL1 ポイントならば # print('zone_KSL1') cnt_KSL1 += 1 if cnt_KSL1 == TOUCH_TH: now_KSL = 1 print('select_KSL1') # KSL 数値表示 背景を黄色にし、文字色は紫色 dsp_KSL(now_KSL) elif in_zone(zone_KSL2s, zone_KSL2e, X_Point, Y_Point): # KSL2 ポイントならば # print('zone_KSL2') cnt_KSL2 += 1 if cnt_KSL2 == TOUCH_TH: now_KSL = 2 print('select_KSL2') # KSL 数値表示 背景を黄色にし、文字色は紫色 dsp_KSL(now_KSL) elif in_zone(zone_KSL3s, zone_KSL3e, X_Point, Y_Point): # KSL3 ポイントならば # print('zone_KSL3') cnt_KSL3 += 1 if cnt_KSL3 == TOUCH_TH: now_KSL = 3 print('select_KSL3') # KSL 数値表示 背景を黄色にし、文字色は紫色 dsp_KSL(now_KSL) elif in_zone(zone_KSR0s, zone_KSR0e, X_Point, Y_Point): # KSR0 ポイントならば # print('zone_KSR0') cnt_KSR0 += 1 if cnt_KSR0 == TOUCH_TH: now_KSR = 0 print('select_KSR0') # KSL 数値表示 背景を黄色にし、文字色は紫色 dsp_KSR(now_KSR) elif in_zone(zone_KSR1s, zone_KSR1e, X_Point, Y_Point): # KSR1 ポイントならば # print('zone_KSR1') cnt_KSR1 += 1 if cnt_KSR1 == TOUCH_TH: now_KSR = 1 print('select_KSR1') # KSL 数値表示 背景を黄色にし、文字色は紫色 dsp_KSR(now_KSR) # mainTab のタッチで終了 elif in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] >= TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 elif in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] >= TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') # OP のタッチで終了 # 上段表示エリアか? elif in_zone(zUPs, zUPe, X_Point, Y_Point): for i in range(1, 5): if in_zone(zOPs[i], zOPe[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zOP[{i}]') cnt_OP[i] += 1 if cnt_OP[i] >= TOUCH_TH: OP_num = i print(f'ALG OP Select = {OP_num}') elif edt_mode == 'RR': if in_zone(guide_RRs, guide_RRe, X_Point, Y_Point): # RR 編集ゾーンならば # print('edt_mode RR') if edt_Xs != X_Point: # 操作感度を上げる edt_def = int((X_Point - edt_Xs) /3) now_RR -= edt_def # 範囲に収める処理 now_RR = 0 if now_RR < 0 else now_RR now_RR = 15 if now_RR > 15 else now_RR # RR ポジション更新 計算方法は項目ごとに異なるので注意 pos_RR = [79 -now_RR, 63] # 座標位置を3倍の位置に展開 pos_RR = [ADSRxs +pos_RR[0] *3, ADSRys +pos_RR[1] *3] # RR ポインタ 倍角で表示 LCD.fill_rect(pos_RR[0] -TOUCH, pos_RR[1] -TOUCH, TOUCH *2, TOUCH *2, LCD.PURPLE) # RR 数値表示 文字領域を 白色にしてから表示 dspRR(now_RR) # edt_Xs 更新 edt_Xs = pos_RR[0] elif edt_mode == 'SR': if in_zone(guide_SRs, guide_SRe, X_Point, Y_Point): # SR 編集ゾーンならば # print('edt_mode SR') if edt_Ys != Y_Point: # 操作感度を上げる edt_def = int((Y_Point - edt_Ys) /3) now_SR += edt_def # 範囲に収める処理 now_SR = 0 if now_SR < 0 else now_SR now_SR = 15 if now_SR > 15 else now_SR # SR ポジション更新 計算方法は項目ごとに異なるので注意 pos_SR = [55, now_TL +now_SL +now_SR] # 座標位置を3倍の位置に展開 pos_SR = [ADSRxs +pos_SR[0] *3, ADSRys +pos_SR[1] *3] # SR ポインタ 倍角で表示 LCD.fill_rect(pos_SR[0] -TOUCH, pos_SR[1] -TOUCH, TOUCH *2, TOUCH *2, LCD.PURPLE) # SR 数値表示 文字領域を 白色にしてから表示 dspSR(now_SR) # edt_Xs 更新 edt_Ys = pos_SR[1] elif edt_mode == 'DRSL': if in_zone(guide_DRSLs, guide_DRSLe, X_Point, Y_Point): # DR 編集ゾーンならば # print('edt_mode DRSL') if edt_Ys != Y_Point: # 操作感度を下げる edt_def_X = int((X_Point - edt_Xs) /3) edt_def_Y = int((Y_Point - edt_Ys) /3) now_DR -= edt_def_X now_SL += edt_def_Y # 範囲に収める処理 now_DR = 0 if now_DR < 0 else now_DR now_DR = 15 if now_DR > 15 else now_DR now_SL = 0 if now_SL < 0 else now_SL now_SL = 15 if now_SL > 15 else now_SL # DR ポジション更新 計算方法は項目ごとに異なるので注意 # pos_DRSL = [(23 -now_AR) + (15 -now_DR), now_TL +now_SL] pos_DRSL = [(23 -now_AR) + (15 -now_DR) +4, now_TL +now_SL] # 座標位置を3倍の位置に展開 pos_DRSL = [ADSRxs +pos_DRSL[0] *3, ADSRys +pos_DRSL[1] *3] # DR ポインタ 倍角で表示 # LCD.fill_rect(pos_DRSL[0], pos_DRSL[1], 16, 16, LCD.PURPLE) LCD.fill_rect(pos_DRSL[0] -TOUCH, pos_DRSL[1] -TOUCH, TOUCH *2, TOUCH *2, LCD.PURPLE) # SL 数値表示 文字領域を 白色にしてから表示 dspSL(now_SL) # DR 数値表示 文字領域を 白色にしてから表示 dspDR(now_DR) # edt_Xs 更新 edt_Xs = pos_DRSL[0] edt_Ys = pos_DRSL[1] ######################################################################## elif edt_mode == 'ARTL': if in_zone(guide_ARTLs, guide_ARTLe, X_Point, Y_Point): # DR 編集ゾーンならば # print('edt_mode ARTL') if edt_Ys != Y_Point: # 操作感度を下げる edt_def_X = int((X_Point - edt_Xs) /3) edt_def_Y = int((Y_Point - edt_Ys) /3) now_AR -= edt_def_X now_TL += edt_def_Y # 範囲に収める処理 now_AR = 0 if now_AR < 0 else now_AR now_AR = 15 if now_AR > 15 else now_AR now_TL = 0 if now_TL < 0 else now_TL now_TL = max_TL if now_TL > max_TL else now_TL # ARTL ポジション更新 計算方法は項目ごとに異なるので注意 pos_ARTL = [23 -now_AR, now_TL] # 座標位置を3倍の位置に展開 pos_ARTL = [ADSRxs +pos_ARTL[0] *3, ADSRys +pos_ARTL[1] *3] # AR・TL ポインタ 倍角で表示 # LCD.fill_rect(pos_ARTL[0], pos_ARTL[1], 8, 8, LCD.PURPLE) LCD.fill_rect(pos_ARTL[0] -TOUCH, pos_ARTL[1] -TOUCH, TOUCH *2, TOUCH *2, LCD.PURPLE) # AR 数値表示 文字領域を 白色にしてから表示 dspAR(now_AR) # TL 数値表示 文字領域を 白色にしてから表示 dspTL(now_TL) # edt_Xs 更新 edt_Xs = pos_ARTL[0] edt_Ys = pos_ARTL[1] ######################################################################## else: # get == None edt_mode = '' # 最初は必ず表示する。以降はタッチがなければ、表示するように変更 flag_begin = 0 cnt_ARTL = 0 cnt_SL = 0 cnt_DRSL = 0 cnt_SR = 0 cnt_RR = 0 cnt_KSL0 = 0 cnt_KSL1 = 0 cnt_KSL2 = 0 cnt_KSL3 = 0 cnt_KSR0 = 0 cnt_KSR1 = 0 # cnt_tabM cnt_tabS cntOP の初期化 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 LCD.show() return(tabM_num, tabS_num, OP_num, now_TL, now_SL, now_AR, now_DR, now_SR, now_RR, now_KSL, now_KSR) # MUL DT FB XOF の編集 def edit_mul(tabM_num, tabS_num, OP_num, now_MUL, now_DT, now_FB, now_XOF): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # ALG op1 ~ op4 の座標リストを取得 zOPs = TAB.get_zOPs() zOPe = TAB.get_zOPe() # 上段表示エリアの開始座標と終末座標を取得 zUPs = TAB.get_zUPs() zUPe = TAB.get_zUPe() # 下段表示エリアの開始座標と終末座標を取得 zLWs = TAB.get_zLWs() zLWe = TAB.get_zLWe() cnt_MUL = 0 cnt_DT = 0 # FB タッチゾーンの設定 # FB タッチ開始座標は、main で設定したものを利用する zone_FBsi = [None, None] *(max_FB +1) zone_FBei = [None, None] *(max_FB +1) for i in range(max_FB +1): zone_FBsi[i] = [FBxs[i], FBys[i]] zone_FBei[i] = [FBxs[i]+16*6, FBys[i]+20] # FB カウンタの設定 cnt_FBi = [None] *(max_FB +1) for i in range(max_FB +1): cnt_FBi[i] = 0 # XOF タッチゾーンの設定 # XOF タッチ開始座標は、冒頭で設定したものを利用する zone_XOFsi = [None, None] *(max_XOF +1) zone_XOFei = [None, None] *(max_XOF +1) for i in range(max_XOF +1): zone_XOFsi[i] = [XOFxs[i], XOFys[i]] zone_XOFei[i] = [XOFxs[i]+16*6, XOFys[i]+20] # XOF カウンタの設定 cnt_XOFi = [None] *(max_XOF +1) for i in range(max_XOF +1): cnt_XOFi[i] = 0 # MUL DT 座標更新 # MUL DT スライダーポイントの座標設定(Pixcel単位):絶対値 pos_MUL = [ 40, 445 - now_MUL *10] # MUL:0~15 pos_DT = [120, 445 - now_DT *10] # DT:0~7 # MUL DT タッチゾーン設定 16 Pixcel四方 ---> 24 Pixcel四方 zone_MULs = [None] *2 zone_MULs[0] = 0 if pos_MUL[0] < TOUCH *2 else pos_MUL[0] - TOUCH *2 zone_MULs[1] = 0 if pos_MUL[1] < TOUCH *2 else pos_MUL[1] - TOUCH *2 zone_MULe = [None] *2 zone_MULe[0] = 319 if (pos_MUL[0] + TOUCH) >= 320 else pos_MUL[0] + TOUCH zone_MULe[1] = 479 if (pos_MUL[1] + TOUCH) >= 480 else pos_MUL[1] + TOUCH zone_DTs = [None] *2 zone_DTs[0] = 0 if pos_DT[0] < TOUCH *2 else pos_DT[0] - TOUCH *2 zone_DTs[1] = 0 if pos_DT[1] < TOUCH *2 else pos_DT[1] - TOUCH *2 zone_DTe = [None] *2 zone_DTe[0] = 319 if (pos_DT[0] + TOUCH) >= 320 else pos_DT[0] + TOUCH zone_DTe[1] = 479 if (pos_DT[1] + TOUCH) >= 480 else pos_DT[1] + TOUCH ######################################################################## # MUL 直線上の設定範囲(Pixcel単位):絶対値 slide_MULs = [ 40, 445 - max_MUL *10] slide_MULe = [ 40, 445] # DT 直線上の設定範囲(Pixcel単位):絶対値 slide_DTs = [120, 445 - max_DT *10] slide_DTe = [120, 445] # 長方形の操作可能範囲 16 Pixcel guide_MULs = [None] *2 # 2025/07/21 Change # guide_MULs[0] = 0 if slide_MULs[0] < TOUCH else slide_MULs[0] - TOUCH guide_MULs[0] = 0 if slide_MULs[0] < TOUCH *2 else slide_MULs[0] - TOUCH *2 guide_MULs[1] = 0 if slide_MULs[1] < TOUCH else slide_MULs[1] - TOUCH guide_MULe = [None] *2 guide_MULe[0] = 319 if (slide_MULe[0] + TOUCH) >= 320 else slide_MULe[0] + TOUCH guide_MULe[1] = 479 if (slide_MULe[1] + TOUCH) >= 480 else slide_MULe[1] + TOUCH guide_DTs = [None] *2 # 2025/07/21 Change # guide_DTs[0] = 0 if slide_DTs[0] < TOUCH else slide_DTs[0] - TOUCH guide_DTs[0] = 0 if slide_DTs[0] < TOUCH *2 else slide_DTs[0] - TOUCH *2 guide_DTs[1] = 0 if slide_DTs[1] < TOUCH else slide_DTs[1] - TOUCH guide_DTe = [None] *2 guide_DTe[0] = 319 if (slide_DTe[0] + TOUCH) >= 320 else slide_DTe[0] + TOUCH guide_DTe[1] = 479 if (slide_DTe[1] + TOUCH) >= 480 else slide_DTe[1] + TOUCH # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 cnt_OP = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num OP_num_old = OP_num edt_mode = '' while tabM_num_old == tabM_num and tabS_num_old == tabS_num and OP_num_old == OP_num: # MUL DT 座標更新 # MUL DT スライダーポイントの座標設定(Pixcel単位):絶対値 pos_MUL = [ 40, 445 - now_MUL *10] # MUL:0~15 pos_DT = [120, 445 - now_DT *10] # DT:0~7 # MUL DT タッチゾーン更新 16 Pixcel四方 ---> 24 Pixcel四方 # pos_MUL と pos_DT は、タッチで更新される zone_MULs[0] = 0 if pos_MUL[0] < TOUCH *2 else pos_MUL[0] - TOUCH *2 zone_MULs[1] = 0 if pos_MUL[1] < TOUCH *2 else pos_MUL[1] - TOUCH *2 zone_MULe[0] = 319 if (pos_MUL[0] + TOUCH) >= 320 else pos_MUL[0] + TOUCH zone_MULe[1] = 479 if (pos_MUL[1] + TOUCH) >= 480 else pos_MUL[1] + TOUCH zone_DTs[0] = 0 if pos_DT[0] < TOUCH *2 else pos_DT[0] - TOUCH *2 zone_DTs[1] = 0 if pos_DT[1] < TOUCH *2 else pos_DT[1] - TOUCH *2 zone_DTe[0] = 319 if (pos_DT[0] + TOUCH) >= 320 else pos_DT[0] + TOUCH zone_DTe[1] = 479 if (pos_DT[1] + TOUCH) >= 480 else pos_DT[1] + TOUCH dspFillLower(LCD.WHITE) # slide Line 垂直方向のガイド(垂直方向に5回線を引く) # MUL DT for x in range(-2, 3): # -2, -1, 0, 1, 2 : 38, 39, 40, 41, 42 : 118, 119, 120, 121, 122 LCD.line(slide_MULs[0]+x, slide_MULs[1], slide_MULe[0]+x, slide_MULe[1]+4, LCD.GREEN) LCD.line(slide_DTs[0]+x, slide_DTs[1], slide_DTe[0]+x, slide_DTe[1]+4, LCD.GREEN) # MUL DT の操作ポイントを、サイズ TOUCH(8x8)で再表示する LCD.fill_rect(pos_MUL[0] -4, pos_MUL[1] -4, TOUCH, TOUCH, LCD.RED) LCD.fill_rect(pos_DT[0] -4, pos_DT[1] -4, TOUCH, TOUCH, LCD.RED) # MUL のタイトル表示 LCD.text_scaled(f'MUL', 0 +16, 455, LCD.BLACK, 2) # DT のタイトル表示 LCD.text_scaled(f'DT', 80 +24, 455, LCD.BLACK, 2) # MUL DT の数値を表示する(編集中にも表示することに留意) dspMUL(now_MUL) dspDT(now_DT) # FB のタイトル表示 LCD.text_scaled(f'FB', 160+24, 455, LCD.BLACK, 2) # FB 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for fb in range(max_FB +1): # FB 設定内容の表示 dsp_FB(fb, LCD.GREEN, LCD.GRAY) # FB 設定値の表示 dsp_FB(now_FB, LCD.YELLOW, LCD.PURPLE) # XOF のタイトル表示 LCD.text_scaled(f'XOF',250, 455, LCD.BLACK, 2) # XOF 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for xof in range(max_XOF +1): # XOF 設定内容の表示 dsp_XOF(xof, LCD.GREEN, LCD.GRAY) # XOF 設定値の表示 dsp_XOF(now_XOF, LCD.YELLOW, LCD.PURPLE) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] if edt_mode == '': if in_zone(zone_MULs, zone_MULe, X_Point, Y_Point): # MUL ポイント周辺ならば # print('zone_MUL') cnt_MUL += 1 if cnt_MUL == TOUCH_TH: print('select_MUL') # 差分検出用に現在値を記録(Pixcel値) edt_Ys = Y_Point edt_mode = 'MUL' elif in_zone(zone_DTs, zone_DTe, X_Point, Y_Point): # DT ポイント周辺ならば # print('zone_DT') cnt_DT += 1 if cnt_DT == TOUCH_TH: print('select_DT') # 差分検出用に現在値を記録(Pixcel値) edt_Ys = Y_Point edt_mode = 'DT' for i in range(max_FB +1): if in_zone(zone_FBsi[i], zone_FBei[i], X_Point, Y_Point): # print(f'zone_FB{i}') cnt_FBi[i] += 1 if cnt_FBi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_FB = i # FB 数値表示 背景を黄色にし、文字色は紫色 dsp_FB(now_FB, LCD.YELLOW, LCD.PURPLE) edt_mode = f'FB{i}' print(f'edt_mode = {edt_mode}') for i in range(max_XOF +1): if in_zone(zone_XOFsi[i], zone_XOFei[i], X_Point, Y_Point): # print(f'zone_XOF{i}') cnt_XOFi[i] += 1 if cnt_XOFi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_XOF = i # XOF 数値表示 背景を黄色にし、文字色は紫色 dsp_XOF(now_XOF, LCD.YELLOW, LCD.PURPLE) edt_mode = f'XOF{i}' print(f'edt_mode = {edt_mode}') # mainTab のタッチで終了 if in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] == TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 if in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] == TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') # OP のタッチで終了 # 上段表示エリアか? if in_zone(zUPs, zUPe, X_Point, Y_Point): for i in range(1, 5): if in_zone(zOPs[i], zOPe[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zOP[{i}]') cnt_OP[i] += 1 if cnt_OP[i] == TOUCH_TH: OP_num = i print(f'ALG OP Select = {OP_num}') elif edt_mode == 'MUL': if in_zone(guide_MULs, guide_MULe, X_Point, Y_Point): # MUL 編集ゾーンならば # print('edt_mode MUL') if edt_Ys != Y_Point: # 操作感度を上げる場合は、/4 の数字を小さく、下げる場合は、/4 の数字を大きく # edt_def = int((Y_Point - edt_Ys) /4) edt_def = int((Y_Point - edt_Ys) /8) # 加減算の正負に注意(x軸は右方向に正、y軸は下方向に正) now_MUL += (edt_def *sign_MUL) # 範囲に収める処理 now_MUL = 0 if now_MUL < 0 else now_MUL now_MUL = max_MUL if now_MUL > max_MUL else now_MUL # 表示ポイント更新 計算方法は項目ごとに異なるので注意 # スライダーポイントの座標設定(Pixcel単位):絶対値 を更新 pos_MUL = [ 40, 445 - now_MUL *10] # MUL:0~15 # MUL の操作ポイントを、倍角 TOUCH(8x8)*2 で表示する LCD.fill_rect(pos_MUL[0] -TOUCH, pos_MUL[1] -TOUCH, TOUCH*2, TOUCH*2, LCD.PURPLE) # MUL 数値表示 文字領域を 白色にしてから表示 dspMUL(now_MUL) # edt_Ys 更新 edt_Ys = pos_MUL[1] elif edt_mode == 'DT': if in_zone(guide_DTs, guide_DTe, X_Point, Y_Point): # DT 編集ゾーンならば # print('edt_mode DT') if edt_Ys != Y_Point: # 操作感度を上げる場合は、/4 の数字を小さく、下げる場合は、/4 の数字を大きく # edt_def = int((Y_Point - edt_Ys) /4) edt_def = int((Y_Point - edt_Ys) /8) # 加減算の正負に注意(x軸は右方向に正、y軸は下方向に正) now_DT += (edt_def *sign_DT) # 範囲に収める処理 now_DT = 0 if now_DT < 0 else now_DT now_DT = max_DT if now_DT > max_DT else now_DT # 表示ポイント更新 計算方法は項目ごとに異なるので注意 # スライダーポイントの座標設定(Pixcel単位):絶対値 pos_DT = [120, 445 - now_DT *10] # DT:0~7 # DT の操作ポイントを、倍角 TOUCH(8x8)*2 で表示する LCD.fill_rect(pos_DT[0] -TOUCH, pos_DT[1] -TOUCH, TOUCH*2, TOUCH*2, LCD.PURPLE) # DT 数値表示 文字領域を 白色にしてから表示 dspDT(now_DT) # edt_Ys 更新 edt_Ys = pos_DT[1] else: # get == None edt_mode = '' # カウンタのクリア cnt_MUL = 0 cnt_DT = 0 # FB カウンタのクリア for i in range(max_FB +1): cnt_FBi[i] = 0 # XOF カウンタのクリア for i in range(max_XOF +1): cnt_XOFi[i] = 0 # cnt_tabM cnt_tabS cntOP のクリア for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 LCD.show() return(tabM_num, tabS_num, OP_num, now_MUL, now_DT, now_FB, now_XOF) # DAM EAM DVB EVB の編集 def edit_dam(tabM_num, tabS_num, OP_num, now_DAM, now_EAM, now_DVB, now_EVB): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # ALG op1 ~ op4 の座標リストを取得 zOPs = TAB.get_zOPs() zOPe = TAB.get_zOPe() # 上段表示エリアの開始座標と終末座標を取得 zUPs = TAB.get_zUPs() zUPe = TAB.get_zUPe() # 下段表示エリアの開始座標と終末座標を取得 zLWs = TAB.get_zLWs() zLWe = TAB.get_zLWe() # DAM タッチゾーンの設定 # DAM タッチ開始座標は、冒頭で設定したものを利用する zone_DAMsi = [None, None] *(max_DAM +1) zone_DAMei = [None, None] *(max_DAM +1) for i in range(max_DAM +1): zone_DAMsi[i] = [DAMxs[i], DAMys[i]] zone_DAMei[i] = [DAMxs[i]+16*6, DAMys[i]+20] # DAM カウンタの設定 cnt_DAMi = [None] *(max_DAM +1) for i in range(max_DAM +1): cnt_DAMi[i] = 0 # DVB タッチゾーンの設定 # DVB タッチ開始座標は、main で設定したものを利用する zone_DVBsi = [None, None] *(max_DVB +1) zone_DVBei = [None, None] *(max_DVB +1) for i in range(max_DVB +1): zone_DVBsi[i] = [DVBxs[i], DVBys[i]] zone_DVBei[i] = [DVBxs[i]+16*6, DVBys[i]+20] # DVB カウンタの設定 cnt_DVBi = [None] *(max_DVB +1) for i in range(max_DVB +1): cnt_DVBi[i] = 0 # EAM タッチゾーンの設定 # EAM タッチ開始座標は、main で設定したものを利用する zone_EAMsi = [None, None] *(max_EAM +1) zone_EAMei = [None, None] *(max_EAM +1) for i in range(max_EAM +1): zone_EAMsi[i] = [EAMxs[i], EAMys[i]] zone_EAMei[i] = [EAMxs[i]+16*6, EAMys[i]+20] # EAM カウンタの設定 cnt_EAMi = [None] *(max_EAM +1) for i in range(max_EAM +1): cnt_EAMi[i] = 0 # EVB タッチゾーンの設定 # EVB タッチ開始座標は、冒頭で設定したものを利用する zone_EVBsi = [None, None] *(max_EVB +1) zone_EVBei = [None, None] *(max_EVB +1) for i in range(max_EVB +1): zone_EVBsi[i] = [EVBxs[i], EVBys[i]] zone_EVBei[i] = [EVBxs[i]+16*6, EVBys[i]+20] # EVB カウンタの設定 cnt_EVBi = [None] *(max_EVB +1) for i in range(max_EVB +1): cnt_EVBi[i] = 0 # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 cnt_OP = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num OP_num_old = OP_num while tabM_num_old == tabM_num and tabS_num_old == tabS_num and OP_num_old == OP_num: # 設定内容を表示する dspFillLower(LCD.WHITE) # EAM の表示 LCD.text_scaled(f'EAM', 32+8+16, 455, LCD.BLACK, 2) # EAM 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for eam in range(max_EAM +1): # EAM 設定内容の表示 dsp_EAM(eam, LCD.GREEN, LCD.GRAY) # EAM 設定値の表示 dsp_EAM(now_EAM, LCD.YELLOW, LCD.PURPLE) # DAM の表示 LCD.text_scaled(f'DAM', 32+8+16, 375, LCD.BLACK, 2) # DAM 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for dam in range(max_DAM +1): # DAM 設定内容の表示 dsp_DAM(dam, LCD.GREEN, LCD.GRAY) # DAM 設定値の表示 dsp_DAM(now_DAM, LCD.YELLOW, LCD.PURPLE) # EVB の表示 LCD.text_scaled(f'EVB', 192+8+16, 455, LCD.BLACK, 2) # EVB 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for evb in range(max_EVB +1): # EVB 設定内容の表示 dsp_EVB(evb, LCD.GREEN, LCD.GRAY) # EVB 設定値の表示 dsp_EVB(now_EVB, LCD.YELLOW, LCD.PURPLE) # DVB の表示 LCD.text_scaled(f'DVB',192+8+16, 375, LCD.BLACK, 2) # DVB 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for dvb in range(max_DVB +1): # DVB 設定内容の表示 dsp_DVB(dvb, LCD.GREEN, LCD.GRAY) # DVB 設定値の表示 dsp_DVB(now_DVB, LCD.YELLOW, LCD.PURPLE) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(max_DAM +1): if in_zone(zone_DAMsi[i], zone_DAMei[i], X_Point, Y_Point): # print(f'zone_DAM{i}') cnt_DAMi[i] += 1 if cnt_DAMi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_DAM = i # DAM 数値表示 背景を黄色にし、文字色は紫色 dsp_DAM(now_DAM, LCD.YELLOW, LCD.PURPLE) edt_mode = f'DAM{i}' print(f'select_DAM{i}') for i in range(max_DVB +1): if in_zone(zone_DVBsi[i], zone_DVBei[i], X_Point, Y_Point): # print(f'zone_DVB{i}') cnt_DVBi[i] += 1 if cnt_DVBi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_DVB = i # DVB 数値表示 背景を黄色にし、文字色は紫色 dsp_DVB(now_DVB, LCD.YELLOW, LCD.PURPLE) edt_mode = f'DVB{i}' print(f'select_DVB{i}') for i in range(max_EAM +1): if in_zone(zone_EAMsi[i], zone_EAMei[i], X_Point, Y_Point): # print(f'zone_EAM{i}') cnt_EAMi[i] += 1 if cnt_EAMi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_EAM = i # EAM 数値表示 背景を黄色にし、文字色は紫色 dsp_EAM(now_EAM, LCD.YELLOW, LCD.PURPLE) edt_mode = f'EAM{i}' print(f'select_EAM{i}') for i in range(max_EVB +1): if in_zone(zone_EVBsi[i], zone_EVBei[i], X_Point, Y_Point): # print(f'zone_EVB{i}') cnt_EVBi[i] += 1 if cnt_EVBi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_EVB = i # EVB 数値表示 背景を黄色にし、文字色は紫色 dsp_EVB(now_EVB, LCD.YELLOW, LCD.PURPLE) edt_mode = f'EVB{i}' print(f'select_EVB{i}') # mainTab のタッチで終了 if in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] == TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 if in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] == TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') # OP のタッチで終了 # 上段表示エリアか? if in_zone(zUPs, zUPe, X_Point, Y_Point): for i in range(1, 5): if in_zone(zOPs[i], zOPe[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zOP[{i}]') cnt_OP[i] += 1 if cnt_OP[i] == TOUCH_TH: OP_num = i print(f'ALG OP Select = {OP_num}') else: # get == None # カウンタクリア for i in range(max_DAM +1): cnt_DAMi[i] = 0 for i in range(max_DVB +1): cnt_DVBi[i] = 0 for i in range(max_EAM +1): cnt_EAMi[i] = 0 for i in range(max_EVB +1): cnt_EVBi[i] = 0 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 LCD.show() return(tabM_num, tabS_num, OP_num, now_DAM, now_EAM, now_DVB, now_EVB) # BO LFO の編集 def edit_bo(tabM_num, tabS_num, OP_num, now_BO, now_LFO, tone_num, tone_name): # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # ALG op1 ~ op4 の座標リストを取得 zOPs = TAB.get_zOPs() zOPe = TAB.get_zOPe() # 上段表示エリアの開始座標と終末座標を取得 zUPs = TAB.get_zUPs() zUPe = TAB.get_zUPe() # 下段表示エリアの開始座標と終末座標を取得 zLWs = TAB.get_zLWs() zLWe = TAB.get_zLWe() # BO タッチゾーンの設定 # BO タッチ開始座標は、冒頭で設定したものを利用する zone_BOsi = [None, None] *(max_BO +1) zone_BOei = [None, None] *(max_BO +1) for i in range(max_BO +1): zone_BOsi[i] = [BOxs[i], BOys[i]] zone_BOei[i] = [BOxs[i]+16*5, BOys[i]+20] # BO カウンタの設定 cnt_BOi = [None] *(max_BO +1) for i in range(max_BO +1): cnt_BOi[i] = 0 # LFO タッチゾーンの設定 # LFO タッチ開始座標は、main で設定したものを利用する zone_LFOsi = [None, None] *(max_LFO +1) zone_LFOei = [None, None] *(max_LFO +1) for i in range(max_LFO +1): zone_LFOsi[i] = [LFOxs[i], LFOys[i]] zone_LFOei[i] = [LFOxs[i]+16*5, LFOys[i]+20] # カウンタの設定 cnt_LFOi = [None] *(max_LFO +1) for i in range(max_LFO +1): cnt_LFOi[i] = 0 # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 cnt_OP = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 cnt_OP[i] = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num OP_num_old = OP_num while tabM_num_old == tabM_num and tabS_num_old == tabS_num and OP_num_old == OP_num: get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(max_BO +1): if in_zone(zone_BOsi[i], zone_BOei[i], X_Point, Y_Point): print(f'zone_BO{i}') cnt_BOi[i] += 1 if cnt_BOi[i] >= TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_BO = i # BO 数値表示 背景を黄色にし、文字色は紫色 dsp_BO(now_BO, LCD.YELLOW, LCD.PURPLE) edt_mode = f'BO{i}' cnt_BOi[i] = 0 for i in range(max_LFO +1): if in_zone(zone_LFOsi[i], zone_LFOei[i], X_Point, Y_Point): print(f'zone_LFO{i}') cnt_LFOi[i] += 1 if cnt_LFOi[i] >= TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_LFO = i # LFO 数値表示 背景を黄色にし、文字色は紫色 dsp_LFO(now_LFO, LCD.YELLOW, LCD.PURPLE) edt_mode = f'LFO{i}' cnt_LFOi[i] = 0 # mainTab のタッチで終了 if in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] >= TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 if in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] >= TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') # OP のタッチで終了 # 上段表示エリアか? if in_zone(zUPs, zUPe, X_Point, Y_Point): for i in range(1, 5): if in_zone(zOPs[i], zOPe[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zOP[{i}]') cnt_OP[i] += 1 if cnt_OP[i] >= TOUCH_TH: OP_num = i print(f'ALG OP Select = {OP_num}') else: # get == None # タッチされていないなら、設定内容を表示する dspFillUpper(LCD.WHITE) dspFillLower(LCD.WHITE) # ToneNumber ToneNmae を上段の末尾に表示する text = f'{tone_num:2}:{tone_name}' chr_num = len(text) zs = [10, 220] # dsp_text_bar(text, zs, chr_num, color_back, color_text) dsp_text_bar(text, zs, chr_num, LCD.WHITE, LCD.RED) # BO の表示 # LCD.text_scaled(f'BO', 32+8+16, 215, LCD.BLACK, 2) LCD.text_scaled(f'BO', 32+8+16, 240+215, LCD.BLACK, 2) # BO 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for bo in range(max_BO +1): # BO 設定内容の表示 dsp_BO(bo, LCD.GREEN, LCD.GRAY) # BO 設定値の表示 dsp_BO(now_BO, LCD.YELLOW, LCD.PURPLE) # LFO の表示 # LCD.text_scaled(f'LFO',192+8+16, 215, LCD.BLACK, 2) LCD.text_scaled(f'LFO',192+8+16, 240+215, LCD.BLACK, 2) # LFO 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for lfo in range(max_LFO +1): # LFO 設定内容の表示 dsp_LFO(lfo, LCD.GREEN, LCD.GRAY) # LFO 設定値の表示 dsp_LFO(now_LFO, LCD.YELLOW, LCD.PURPLE) LCD.show() return(tabM_num, tabS_num, OP_num, now_BO, now_LFO) # Tone Number の選択 # 20251018 def edit_ToneNumber(guide_msg, now_TN): を改名 # def select_ToneNumber(guide_msg, now_TN): def select_ToneNumber(tabM_num, tabS_num, guide_msg1, guide_msg2, now_TN, toneNameL): # 上段に ガイダンスを表示 dspFillUpper(LCD.WHITE) # WindowFrame 表示 zs = [0, 50] width = 320 height = 160 # = 末尾のzs(160) - zs(50) +10(1行目余白) +30(末尾の枠+余白) color_line = LCD.RED color_back = LCD.YELLOW dsp_WindowFrame(zs, width, height, color_line, color_back) zs = [20, 70] text = guide_msg1 color_text = LCD.RED LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 100] # text = 'Select Tone Number' text = guide_msg2 color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 120] text = 'and Exec or Cancel' color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) # Cancel ボタンの開始座標と終末座標 text = 'Cancel' chr_num = len(text) zCANs = [30, 170] zCANe = [zCANs[0] + chr_num *chr_w, zCANs[1] + txt_h] # TAB.save_BtnCancel(zCANs, zCANe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # Execute ボタンの開始座標と終末座標 text = 'Execute' chr_num = len(text) zEXEs = [170, 170] zEXEe = [zEXEs[0] + chr_num *chr_w, zEXEs[1] + txt_h] # TAB.save_BtnExec(zEXEs, zEXEe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) # LCD.show() # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # TN タッチゾーンの設定 # TN タッチ開始座標は、このプログラムの冒頭で設定したものを利用する zone_TNsi = [None, None] *16 zone_TNei = [None, None] *16 for i in range(max_TN +1): zone_TNsi[i] = [TNxs[i], TNys[i]] zone_TNei[i] = [TNxs[i]+16*3, TNys[i]+30] # カウンタの設定 cnt_TNi = [None] *(max_TN +1) for i in range(max_TN +1): cnt_TNi[i] = 0 cnt_Exe = 0 cnt_Can = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num btn = '' # Cancel または Execute ボタンが押されたら終了 # while not(btn == 'Cancel' or btn == 'Execute'): while tabM_num_old == tabM_num and tabS_num_old == tabS_num \ and not(btn == 'Cancel' or btn == 'Execute'): dspFillLower(LCD.WHITE) zs = [20, 270] # text = 'Select Tone Number' text = guide_msg1 color_text = LCD.BLACK LCD.text_scaled(text, zs[0], zs[1], color_text, 2) # TN 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for tn in range(max_TN +1): # TN 設定内容の表示 dsp_TN(tn, LCD.GREEN, LCD.GRAY) # TN 設定値のハイライト表示 dsp_TN(now_TN, LCD.YELLOW, LCD.PURPLE) # Tone Name を表示する text = toneNameL[now_TN] chr_num = 16 zs = [60, 440] dsp_text_bar(text, zs, chr_num, LCD.WHITE, LCD.RED) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(max_TN +1): if in_zone(zone_TNsi[i], zone_TNei[i], X_Point, Y_Point): # print(f'zone_TN{i}') cnt_TNi[i] += 1 if cnt_TNi[i] == TOUCH_TH: print(f'select_TN{i}') # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_TN = i # TN 数値表示 背景を黄色にし、文字色は紫色 dsp_TN(now_TN, LCD.YELLOW, LCD.PURPLE) # Execute ボタンが押されたら終了 if in_zone(zEXEs, zEXEe, X_Point, Y_Point): # print(f'Execute Button') cnt_Exe += 1 if cnt_Exe == TOUCH_TH: print(f'Execute Button') btn = 'Execute' # 選択されたボタンの色を変える text = 'Execute' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) # LCD.show() # Cancel ボタンが押されたら終了 elif in_zone(zCANs, zCANe, X_Point, Y_Point): # print('Cancel Button') cnt_Can += 1 if cnt_Can == TOUCH_TH: print('Cancel Button') btn = 'Cancel' # 選択されたボタンの色を変える text = 'Cancel' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # LCD.show() # mainTab のタッチで終了 elif in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] == TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 elif in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] == TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') else: # get == None # カウンタをクリア for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 for i in range(max_TN +1): cnt_TNi[i] = 0 cnt_Exe = 0 cnt_Can = 0 LCD.show() return (tabM_num, tabS_num, btn, now_TN) # Swapping Channel の選択 def select_SwapCh(tabM_num, tabS_num, guide_msg1, guide_msg2, ch): # 上段に ガイダンスを表示 dspFillUpper(LCD.WHITE) # WindowFrame 表示 zs = [0, 50] width = 320 height = 160 # = 末尾のzs(160) - zs(50) +10(1行目余白) +30(末尾の枠+余白) color_line = LCD.RED color_back = LCD.YELLOW dsp_WindowFrame(zs, width, height, color_line, color_back) zs = [20, 70] text = guide_msg1 color_text = LCD.RED LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 100] # text = 'Select Tone Number' text = guide_msg2 color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 120] text = 'and Exec or Cancel' color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) # Cancel ボタンの開始座標と終末座標 text = 'Cancel' chr_num = len(text) zCANs = [30, 170] zCANe = [zCANs[0] + chr_num *chr_w, zCANs[1] + txt_h] # TAB.save_BtnCancel(zCANs, zCANe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # Execute ボタンの開始座標と終末座標 text = 'Execute' chr_num = len(text) zEXEs = [170, 170] zEXEe = [zEXEs[0] + chr_num *chr_w, zEXEs[1] + txt_h] # TAB.save_BtnExec(zEXEs, zEXEe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # TN タッチゾーンの設定 # TN タッチ開始座標は、このプログラムの冒頭で設定したものを利用する zone_TNsi = [None, None] *16 zone_TNei = [None, None] *16 for i in range(max_TN +1): zone_TNsi[i] = [TNxs[i], TNys[i]] zone_TNei[i] = [TNxs[i]+16*3, TNys[i]+30] # カウンタの設定 cnt_TNi = [None] *(max_TN +1) for i in range(max_TN +1): cnt_TNi[i] = 0 cnt_Exe = 0 cnt_Can = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num btn = '' # Cancel または Execute ボタンが押されたら終了 # while not(btn == 'Cancel' or btn == 'Execute'): while tabM_num_old == tabM_num and tabS_num_old == tabS_num \ and not(btn == 'Cancel' or btn == 'Execute'): dspFillLower(LCD.WHITE) zs = [20, 270] # text = 'Select Tone Number' text = guide_msg1 color_text = LCD.BLACK LCD.text_scaled(text, zs[0], zs[1], color_text, 2) # TN 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for tn in range(max_TN +1): # TN 設定内容の表示 dsp_TN(tn, LCD.GREEN, LCD.GRAY) # TN 設定値のハイライト表示 dsp_TN(ch, LCD.YELLOW, LCD.PURPLE) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for i in range(max_TN +1): if in_zone(zone_TNsi[i], zone_TNei[i], X_Point, Y_Point): # print(f'zone_TN{i}') cnt_TNi[i] += 1 if cnt_TNi[i] == TOUCH_TH: print(f'select_TN{i}') # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point ch = i # TN 数値表示 背景を黄色にし、文字色は紫色 dsp_TN(ch, LCD.YELLOW, LCD.PURPLE) # Execute ボタンが押されたら終了 if in_zone(zEXEs, zEXEe, X_Point, Y_Point): # print(f'Execute Button') cnt_Exe += 1 if cnt_Exe == TOUCH_TH: print(f'Execute Button') btn = 'Execute' # 選択されたボタンの色を変える text = 'Execute' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) # LCD.show() # Cancel ボタンが押されたら終了 elif in_zone(zCANs, zCANe, X_Point, Y_Point): # print('Cancel Button') cnt_Can += 1 if cnt_Can == TOUCH_TH: print('Cancel Button') btn = 'Cancel' # 選択されたボタンの色を変える text = 'Cancel' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # LCD.show() # mainTab のタッチで終了 elif in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] == TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 elif in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] == TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') else: # get == None # カウンタをクリア for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 for i in range(max_TN +1): cnt_TNi[i] = 0 cnt_Exe = 0 cnt_Can = 0 LCD.show() return (tabM_num, tabS_num, btn, ch) # title, guide1, guide2 を表示して、実行するか否かを選択する def select_CanExe(title, guide1, guide2): # 上段に ガイダンスを表示 dspFillUpper(LCD.WHITE) # WindowFrame 表示 zs = [0, 50] width = 320 height = 160 # = 末尾のzs(160) - zs(50) +10(1行目余白) +30(末尾の枠+余白) color_line = LCD.RED color_back = LCD.YELLOW dsp_WindowFrame(zs, width, height, color_line, color_back) zs = [20, 70] text = title color_text = LCD.RED LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 100] text = guide1 color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 120] text = guide2 color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) # Cancel ボタンの開始座標と終末座標 text = 'Cancel' chr_num = len(text) zCANs = [30, 170] zCANe = [zCANs[0] + chr_num *chr_w, zCANs[1] + txt_h] # TAB.save_BtnCancel(zCANs, zCANe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # Execute ボタンの開始座標と終末座標を保存 text = 'Execute' chr_num = len(text) zEXEs = [170, 170] zEXEe = [zEXEs[0] + chr_num *chr_w, zEXEs[1] + txt_h] # TAB.save_BtnExec(zEXEs, zEXEe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) LCD.show() # 終了条件の設定 btn = '' # Cancel または Execute ボタンが押されたら終了 while not(btn == 'Cancel' or btn == 'Execute'): get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] # Execute ボタンが押されたら終了 if in_zone(zEXEs, zEXEe, X_Point, Y_Point): print(f'Execute Button') cnt_Exe += 1 if cnt_Exe >= TOUCH_TH: btn = 'Execute' # 選択されたボタンの色を変える text = 'Execute' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) LCD.show() # Cancel ボタンが押されたら終了 if in_zone(zCANs, zCANe, X_Point, Y_Point): print('Cancel Button') cnt_Can += 1 if cnt_Can >= TOUCH_TH: btn = 'Cancel' # 選択されたボタンの色を変える text = 'Cancel' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) LCD.show() else: # get == None cnt_Exe = 0 cnt_Can = 0 # LCD.show() return btn # file_list から 1つの File を選択 # def select_File(file_list, guide1, guide2, list_name): def select_Item(tabM_num, tabS_num, file_list, guide1, guide2, list_name): list_size = len(file_list) page_size = 7 # LCD 表示行数 page_max, point_mod = divmod(list_size, page_size) page_now = 0 # FileName 表示とタッチ開始座標と終末座標 zNAMEs = [ 10, 290] zNAMEe = [310, 310] # FileName 複数のタッチゾーンの設定 zNAMEsi = [None, None] *page_size zNAMEei = [None, None] *page_size for i in range(page_size): zNAMEsi[i] = [zNAMEs[0], zNAMEs[1] +txt_h *i] zNAMEei[i] = [zNAMEe[0], zNAMEe[1] +txt_h *i] # 上段に ガイダンスを表示 dspFillUpper(LCD.WHITE) # WindowFrame 表示 zs = [0, 50] width = 320 height = 160 # = 末尾のzs(160) - zs(50) +10(1行目余白) +30(末尾の枠+余白) color_line = LCD.RED color_back = LCD.YELLOW dsp_WindowFrame(zs, width, height, color_line, color_back) zs = [20, 70] # text = 'Get Tone Data' # color_text = LCD.RED LCD.text_scaled(guide1, zs[0], zs[1], LCD.RED, 2) zs = [20, 100] # text = 'Select File Name' # color_text = LCD.BLACK LCD.text_scaled(guide2, zs[0], zs[1], LCD.BLACK, 2) zs = [20, 120] text = 'and OK or Cancel' color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) # Cancel ボタンの表示とタッチゾーンの設定 text = 'Cancel' chr_num = len(text) zCANs = [30, 170] zCANe = [zCANs[0] + chr_num *chr_w, zCANs[1] + txt_h] # TAB.save_BtnCancel(zCANs, zCANe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # Execute ボタンの開始座標と終末座標を保存 text = ' OK ' chr_num = len(text) zEXEs = [170, 170] zEXEe = [zEXEs[0] + chr_num *chr_w, zEXEs[1] + txt_h] # TAB.save_BtnExec(zEXEs, zEXEe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zEXEs, chr_num, color_line, color_back, color_text) # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # カウンタの設定 cnt_NAMEi = [None] *(page_size) for i in range(page_size): cnt_NAMEi[i] = 0 cnt_Exe = 0 cnt_Can = 0 cnt_PgUp = 0 cnt_PgDw = 0 # 終了条件の設定 file_name = '' file_select = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num btn = '' # Cancel または Execute(表示は [OK] ボタンが押されたら終了 # while not(btn == 'Cancel' or btn == 'Execute'): while tabM_num_old == tabM_num and tabS_num_old == tabS_num \ and not(btn == 'Cancel' or btn == 'Execute'): # 下段に ガイダンスを表示 dspFillLower(LCD.WHITE) zs = [10,270] # text = 'File Name' # dsp_text_bar(text, zs, chr_num, color_back, color_text) dsp_text_bar(list_name, zs, 18, LCD.YELLOW, LCD.BLUE) # 0 =< page_now <= page_max に制限する page_now = page_now if page_now <= page_max else page_max page_now = 0 if page_now < 0 else page_now # file_list へのアクセスポイントと表示 point_now = page_now *page_size # 0, 7, 14, 21, 28, 35, 42 # 0-6 ずつ表示する最後の行 = point_end 差分値 if page_now < page_max: point_end = page_size else: point_end = point_mod # file name 表示 for i in range(point_end): # dsp_text_bar(text, zs, chr_num, color_back, color_text) dsp_text_bar(file_list[point_now +i], zNAMEsi[i], 18, LCD.GREEN, LCD.BLACK) # file_select あれば if file_select == 1 and select_page == page_now: file_name = file_list[point_now +file_point] # dsp_text_bar(text, zs, chr_num, color_back, color_text) dsp_text_bar(file_name, zNAMEsi[file_point], 18, LCD.YELLOW, LCD.RED) # 現在ページと終末ページ text = f'{page_now +1: 2}/{page_max +1: 2}' # [ 9/99] chr_num = 5 zs = [24, 445] # dsp_text_frame(text, zs, chr_num, color_line, color_back, color_text) dsp_text_frame(text, zs, chr_num, LCD.BLACK, LCD.WHITE, LCD.BLACK) # Page Up ボタンの表示とゾーン設定 text = 'PgUp' chr_num = len(text) zUPs = [136, 445] zUPe = [zUPs[0] + chr_num *chr_w, zUPs[1] + txt_h] # dsp_text_frame(text, zs, chr_num, color_line, color_back, color_text) dsp_text_frame(text, zUPs, chr_num, LCD.BLACK, LCD.BLUE, LCD.YELLOW) # Page Down ボタンの表示とゾーン設定 text = 'PgDw' chr_num = len(text) zDWs = [232, 445] zDWe = [zDWs[0] + chr_num *chr_w, zDWs[1] + txt_h] # dsp_text_frame(text, zs, chr_num, color_line, color_back, color_text) dsp_text_frame(text, zDWs, chr_num, LCD.BLACK, LCD.BLUE, LCD.YELLOW) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] zNAMEsi for i in range(point_end): if in_zone(zNAMEsi[i], zNAMEei[i], X_Point, Y_Point): # print(f'zNAME = {file_list[i]}') cnt_NAMEi[i] += 1 if cnt_NAMEi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point file_select = 1 select_page = page_now file_point = i file_name = file_list[point_now +file_point] print(f'Select File Name = {file_name}') # NAME 表示 背景を黄色にし、文字色は紫色 dsp_text_bar(file_name, zNAMEsi[i], 18, LCD.YELLOW, LCD.PURPLE) # PageUP ボタンが押されたら if in_zone(zUPs, zUPe, X_Point, Y_Point): cnt_PgUp += 1 if cnt_PgUp >= TOUCH_TH: # 1回だけカウントする if cnt_PgUp == TOUCH_TH: print(f'PageUP Button') page_now -= 1 # 選択されたボタンの色を変える text = 'PgUp' chr_num = len(text) dsp_text_frame(text, zUPs, chr_num, LCD.BLACK, LCD.YELLOW, LCD.PURPLE) # PageDown ボタンが押されたら elif in_zone(zDWs, zDWe, X_Point, Y_Point): cnt_PgDw += 1 if cnt_PgDw >= TOUCH_TH: # 1回だけカウントする if cnt_PgDw == TOUCH_TH: print(f'PageDown Button') page_now += 1 # 選択されたボタンの色を変える text = 'PgDw' chr_num = len(text) dsp_text_frame(text, zDWs, chr_num, LCD.BLACK, LCD.YELLOW, LCD.PURPLE) # Execute ボタンが押されたら終了 elif in_zone(zEXEs, zEXEe, X_Point, Y_Point): cnt_Exe += 1 if cnt_Exe == TOUCH_TH: print(f'Execute Button') btn = 'Execute' # 選択されたボタンの色を変える # text = 'Execute' text = ' OK ' chr_num = len(text) dsp_text_frame(text, zEXEs, chr_num, LCD.BLACK, LCD.GREEN, LCD.RED) # 表示して while の外へ # Cancel ボタンが押されたら終了 elif in_zone(zCANs, zCANe, X_Point, Y_Point): cnt_Can += 1 if cnt_Can == TOUCH_TH: print('Cancel Button') btn = 'Cancel' # 選択されたボタンの色を変える text = 'Cancel' chr_num = len(text) dsp_text_frame(text, zCANs, chr_num, LCD.BLACK, LCD.GREEN, LCD.RED) # 表示して while の外へ # mainTab のタッチで終了 elif in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] >= TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 elif in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] >= TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') else: # get == None # カウンタのクリア # cnt_tabM cnt_tabS cntOP の初期化 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # cnt_NAMEi = [None] *(page_size) for i in range(page_size): cnt_NAMEi[i] = 0 cnt_Exe = 0 cnt_Can = 0 cnt_PgUp = 0 cnt_PgDw = 0 LCD.show() # return btn, file_name return (tabM_num, tabS_num, btn, file_name) # Full Key による Text の編集 # Text の開始座標(余白=背景を含む)から、chr_num で指定された桁数の編集を行う def edit_text(text, chr_num, zs, color_back, color_text): blink = 0 # 編集行の表示 dsp_text_cursor(text, zs, chr_num, color_back, color_text, blink) # Full Key タッチゾーンは、このプログラムの冒頭部分で設定済み 32Pixel × 32Pixel # zone_FKs # zone_FKe # Full Key カウンタの設定 cnt_FKxy = [None, None] *key_c for i in range(key_c): cnt_FKxy[i] = [None] *key_r for x in range(key_c): for y in range(key_r): cnt_FKxy[x][y] = 0 cnt_BS = 0 cnt_Enter = 0 cnt_Shift = 0 cnt_Space = 0 mode_Shift = 0 # 0:Lower 1:Upper # 終了条件の設定 btn = '' while btn != 'Enter': get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] for x in range(key_c): for y in range(key_r): if in_zone(zone_FKs[x][y], zone_FKe[x][y], X_Point, Y_Point): if x==9 and y==0: # BS print(f'zone_BS key') cnt_BS += 1 if cnt_BS >=3: btn = 'BS' print(f'key_btn = {btn}') len_text = len(text) if len_text > 0: text = text[:len_text -1] # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) # 編集行の表示 dsp_text_cursor(text, zs, chr_num, color_back, color_text) cnt_BS = 0 elif (x==9 and y==3) or (x==9 and y==4): # Enter print(f'zone_Enter key') cnt_Enter += 1 if cnt_Enter >=3: btn = 'Enter' print(f'key_btn = {btn}') # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) elif (x==0 and y==5) or (x==1 and y==5): # Shift print(f'zone_Shift key') cnt_Shift += 1 if cnt_Shift >=3: btn = 'Shift' print(f'key_btn = {btn}') # mode_Shift の切り替え(反転) mode_Shift = 1 if mode_Shift == 0 else 0 # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) cnt_Shift = 0 elif (x==2 and y==5) or (x==3 and y==5): # Space print(f'zone_Space key') cnt_Space += 1 if cnt_Space >=3: btn = 'Space' # Space print(f'key_btn = {btn}') text = text + ' ' # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) # 編集行の表示 dsp_text_cursor(text, zs, chr_num, color_back, color_text) cnt_Space = 0 else: print(f'zone_FK{x}{y}') cnt_FKxy[x][y] += 1 if cnt_FKxy[x][y] >= TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point # Full Key Btn btn = FKv0[y][x] if mode_Shift == 0 else FKv1[y][x] print(f'key_btn = {btn}') text = text + btn # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) # 編集行の表示 dsp_text_cursor(text, zs, chr_num, color_back, color_text) cnt_FKxy[x][y] = 0 else: # get == None blink = 1 if blink == 0 else 0 # 編集行の表示 dsp_text_cursor(text, zs, chr_num, color_back, color_text, blink) # dspFillLower(LCD.WHITE) # Full Keyboard Button の表示 dsp_FullKeyboard(mode_Shift, LCD.GREEN, LCD.BLACK) # Full Key カウンタのクリア for x in range(key_c): for y in range(key_r): cnt_FKxy[x][y] = 0 cnt_BS = 0 cnt_Enter = 0 cnt_Shift = 0 cnt_Space = 0 LCD.show() return (btn, text) # Full Key による Tone Name の編集 digit_max = 最大桁数 # exeBtnName [Execute] [ OK ] などのボタン名 # Text の開始座標(余白=背景を含む)から、chr_num で指定された桁数の編集を行う # def edit_ToneName(tone_name, digit_max, exeName): def edit_ToneName(tabM_num, tabS_num, tone_name, digit_max, exeName): blink = 0 # 上段に ガイダンスを表示 dspFillUpper(LCD.WHITE) # WindowFrame 表示 zs = [0, 50] width = 320 height = 160 # = 末尾のzs(160) - zs(50) +10(1行目余白) +30(末尾の枠+余白) color_line = LCD.RED color_back = LCD.YELLOW dsp_WindowFrame(zs, width, height, color_line, color_back) zs = [20, 70] text = 'Put Tone SD card' color_text = LCD.RED LCD.text_scaled(text,zs[0], zs[1], color_text, 2) zs = [20, 100] text = 'Edit File Name' color_text = LCD.BLACK LCD.text_scaled(text,zs[0], zs[1], color_text, 2) # Cancel ボタンの開始座標と終末座標 text = 'Cancel' chr_num = len(text) zCANs = [30, 170] zCANe = [zCANs[0] + chr_num *chr_w, zCANs[1] + txt_h] # TAB.save_BtnCancel(zCANs, zCANe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # OK ボタンの開始座標と終末座標を保存 text = exeName exe_num = len(text) zEXEs = [170, 170] zEXEe = [zEXEs[0] + exe_num *chr_w, zEXEs[1] + txt_h] # TAB.save_BtnExec(zEXEs, zEXEe) color_line = LCD.BLACK color_back = LCD.BLUE color_text = LCD.GRAY dsp_text_frame(text, zEXEs, exe_num, color_line, color_back, color_text) # 編集行の表示 zsTXT = [20, 120] color_back = LCD.WHITE color_text = LCD.RED dsp_text_cursor(tone_name, zsTXT, digit_max +1, color_back, color_text, blink) LCD.show() # Main Tab の座標リストを取得 zoneMtab_s = TAB.get_zoneMtab_s() zoneMtab_e = TAB.get_zoneMtab_e() # Sub Tab の座標リストを取得 zoneStab_s = TAB.get_zoneStab_s() zoneStab_e = TAB.get_zoneStab_e() # cnt_tabM cnt_tabS cntOP の初期化 cnt_tabM = [None] * 5 cnt_tabS = [None] * 5 for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # Full Key タッチゾーンは、プログラムの冒頭部分で設定済み 32Pixel × 32Pixel # zone_FKs # zone_FKe # Full Key カウンタの設定 cnt_FKxy = [None, None] *key_c for i in range(key_c): cnt_FKxy[i] = [None] *key_r for x in range(key_c): for y in range(key_r): cnt_FKxy[x][y] = 0 cnt_BS = 0 cnt_Enter = 0 cnt_Shift = 0 cnt_Space = 0 mode_Shift = 0 # 0:Lower 1:Upper cnt_Exe = 0 cnt_Can = 0 # 終了条件の設定 tabM_num_old = tabM_num tabS_num_old = tabS_num btn = '' # (btn == 'Enter' or btn == 'Cancel' or btn == exeName) ならば終了 # while not(btn == 'Enter' or btn == 'Cancel' or btn == exeName): while tabM_num_old == tabM_num and tabS_num_old == tabS_num \ and not(btn == 'Enter' or btn == 'Cancel' or btn == exeName): # カーソルの点滅 blink = 1 if blink == 0 else 0 # 編集行の表示 dsp_text_cursor(tone_name, zsTXT, digit_max, color_back, color_text, blink) # Full Keyboard Button の表示 dsp_FullKeyboard(mode_Shift, LCD.GREEN, LCD.BLACK) get = LCD.touch_get() if get != None: # タッチされているなら X_Point = get[0] Y_Point = get[1] # Execute ボタンが押されたら終了 if in_zone(zEXEs, zEXEe, X_Point, Y_Point): # print(f'{exeName} Button') cnt_Exe += 1 if cnt_Exe == TOUCH_TH: btn = exeName print(f'btn = {btn}') # 選択されたボタンの色を変える dsp_text_frame(exeName, zEXEs, exe_num, LCD.BLACK, LCD.GREEN, LCD.RED) # Cancel ボタンが押されたら終了 elif in_zone(zCANs, zCANe, X_Point, Y_Point): print('Cancel Button') cnt_Can += 1 if cnt_Can == TOUCH_TH: btn = 'Cancel' # 選択されたボタンの色を変える text = 'Cancel' chr_num = len(text) color_line = LCD.BLACK color_back = LCD.GREEN color_text = LCD.RED dsp_text_frame(text, zCANs, chr_num, color_line, color_back, color_text) # mainTab のタッチで終了 elif in_zone(zoneMtab_s[1], zoneMtab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneMtab_s[i], zoneMtab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneMtab[{i}]') cnt_tabM[i] += 1 if cnt_tabM[i] == TOUCH_TH: tabM_num = i print(f'main-menu Select = {tabM_num}') # subTab のタッチで終了 elif in_zone(zoneStab_s[1], zoneStab_e[4], X_Point, Y_Point): for i in range(1, 5): if in_zone(zoneStab_s[i], zoneStab_e[i], X_Point, Y_Point): # zoneMtab[i] の周辺ならば # print(f'select zoneStab[{i}]') cnt_tabS[i] += 1 if cnt_tabS[i] == TOUCH_TH: tabS_num = i print(f'sub-menu Select = {tabS_num}') for x in range(key_c): for y in range(key_r): if in_zone(zone_FKs[x][y], zone_FKe[x][y], X_Point, Y_Point): if x==9 and y==0: # BS # print(f'zone_BS key') cnt_BS += 1 if cnt_BS ==3: btn = 'BS' print(f'key_btn = {btn}') len_text = len(tone_name) if len_text > 0: tone_name = tone_name[:len_text -1] # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) # 編集行の表示 dsp_text_cursor(tone_name, zsTXT, digit_max, color_back, color_text, blink) cnt_BS = 0 elif (x==9 and y==3) or (x==9 and y==4): # Enter print(f'zone_Enter key') cnt_Enter += 1 if cnt_Enter ==3: btn = 'Enter' print(f'key_btn = {btn}') # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) elif (x==0 and y==5) or (x==1 and y==5): # Shift # print(f'zone_Shift key') cnt_Shift += 1 if cnt_Shift ==3: btn = 'Shift' print(f'key_btn = {btn}') # mode_Shift の切り替え(反転) mode_Shift = 1 if mode_Shift == 0 else 0 # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) cnt_Shift = 0 elif (x==2 and y==5) or (x==3 and y==5): # Space # print(f'zone_Space key') cnt_Space += 1 if cnt_Space ==3: btn = 'Space' # Space print(f'key_btn = {btn}') # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) if len(tone_name) < digit_max: # digit_max 未満ならば tone_name = tone_name + ' ' # 編集行の表示 dsp_text_cursor(tone_name, zsTXT, digit_max, color_back, color_text) cnt_Space = 0 else: # print(f'zone_FK{x}{y}') cnt_FKxy[x][y] += 1 if cnt_FKxy[x][y] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point # Full Key Btn btn = FKv0[y][x] if mode_Shift == 0 else FKv1[y][x] print(f'key_btn = {btn}') # Keyboard 上の btn を 表示。背景を黄色、文字色は紫色 dsp_btn(mode_Shift, btn, x, y, LCD.YELLOW, LCD.PURPLE) if len(tone_name) < digit_max: # digit_max 未満ならば tone_name = tone_name + btn # 編集行の表示 dsp_text_cursor(tone_name, zsTXT, digit_max, color_back, color_text) cnt_FKxy[x][y] = 0 else: # get == None # cnt_tabM cnt_tabS cntOP の タッチカウントのクリア for i in range(5): cnt_tabM[i] = 0 cnt_tabS[i] = 0 # Full Key タッチカウントのクリア for x in range(key_c): for y in range(key_r): cnt_FKxy[x][y] = 0 cnt_BS = 0 cnt_Enter = 0 cnt_Shift = 0 cnt_Space = 0 cnt_Exe = 0 cnt_Can = 0 LCD.show() return (tabM_num, tabS_num, btn, tone_name) ``` ### touch_lcd.py ```MicroPython:touch_lcd.py ######################################################################## # WAVE SHARE Pico-ResTouch-LCD-3.5 で用意された main_3inch5.py をテスト・改良 # # 2025/08/28 : touch_lcd_No3_WS\ALG-033.py からライブラリとして独立させた # touch_lcd-yyyymmdd-hhmm.py # # タッチパネルの調整用のプログラムは残した状態 # ######################################################################## from machine import Pin,SPI,PWM from micropython import const import math import framebuf import time import os import gc # メモリ利用状況表示用 ############################################################################## # for DEBUG # PRINT_TOUCH_POS = True # タッチ座標を表示する時 # TOUCH_ADJ = True # タッチ座標を取得する時。ROTATE = const(180) にすること # 2025/09/26 PRINT_TOUCH_POS = False # タッチ座標を表示しない TOUCH_ADJ = False # タッチ座標を取得しない ############################################################################## LCD_DC = const(8) LCD_CS = const(9) LCD_SCK = const(10) LCD_MOSI = const(11) LCD_MISO = const(12) LCD_BL = const(13) LCD_RST = const(15) TP_CS = const(16) TP_IRQ = const(17) ############################################################## # LCDの向きに合わせて設定する # Set the rotation Angle to 0°, 90°, 180° or 270° # 0:USBが左辺上 90:USBが下辺左 180:USBが右辺下 270:USBが上辺右 # タッチ座標を取得して調整するときは。ROTATE = const(180) にすること ############################################################## ROTATE = const(180) # この Pixel 分を上下左右に拡大したエリアをタッチ有効とする # 一部、この倍の領域にしている TOUCH = const(8) class LCD_3inch5(framebuf.FrameBuffer): def __init__(self): self.RED = 0x07E0 self.GREEN = 0x001f self.BLUE = 0xf800 self.WHITE = 0xffff self.BLACK = 0x0000 # Return color565 from RGB color value. # Red Green Blue self.YELLOW = self.rgb2color565(0xFF, 0xFF, 0x00) self.PURPLE = self.rgb2color565(0xFF, 0x00, 0xFF) self.BLUEGREEN = self.rgb2color565(0x00, 0xFF, 0xFF) self.GRAY = self.rgb2color565(0x50, 0x28, 0x15) self.rotate = ROTATE # 2025/07/15 ここの設定の修正が必要だった if self.rotate == 0 or self.rotate == 180: self.width = 320 # 2025/07/15 self.height = 240 self.height = 480 else: self.width = 480 # 2025/07/15 self.height = 160 self.height = 320 # 制御信号端子の設定 self.cs = Pin(LCD_CS,Pin.OUT) self.rst = Pin(LCD_RST,Pin.OUT) self.dc = Pin(LCD_DC,Pin.OUT) self.tp_cs =Pin(TP_CS,Pin.OUT) self.irq = Pin(TP_IRQ,Pin.IN) # 制御信号端子の初期状態設定 self.cs(1) self.dc(1) self.rst(1) self.tp_cs(1) # Before LCD(ILI9488) 40MHz # self.spi_lcd = SPI(1,baudrate=40_000_000,sck=Pin(LCD_SCK),\ # mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO)) # # 2025/09/05 After LCD(ILI9488) 20MHz self.spi_lcd = SPI(1,baudrate=20_000_000,sck=Pin(LCD_SCK),\ mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO)) print(self.spi_lcd) #################### このあたりが難解 ################################ # Pico2(RP2350) ならば、画面一杯をしてしてもメモリエラーにならない self.buffer = bytearray(self.height * self.width * 2) super().__init__(self.buffer, self.width, self.height, framebuf.RGB565) ######################################################################### ############################################################# print(f'touch_lcd Start ... gc.mem_alloc() = {gc.mem_alloc()}') # メモリ未使用を示されても分かりにくい、やめ。 # print('gc.mem_free() = ', gc.mem_free()) # メモリ未使用 ############################################################# self.init_display() # color565 is Blue:5bits, Red:6bits, and Green:5bits 16bits # Return color565 from RGB color value. def rgb2color565(self, r, g, b): return (r & 0xFC) << 3 | (g & 0xF8) >> 3 | (b & 0xF8) << 8 def init_display(self): self.rst(0) time.sleep_ms(17) self.rst(1) time.sleep_ms(47) # INVON = const(0x21) # Display inversion on self.write_cmd(0x21) # Power Control 3 self.write_cmd(0xC2) self.write_data(0x33) # VMCTR1 = const(0xC5) # VCOM control 1 self.write_cmd(0xC5) self.write_data(0x00) self.write_data(0x1e) self.write_data(0x80) # FRMCTR1 = const(0xB1) # Frame rate control (In normal mode/full colors) self.write_cmd(0xB1) self.write_data(0xB0) # GMCTRP1 = const(0xE0) # Positive gamma correction self.write_cmd(0xE0) self.write_data(0x00) self.write_data(0x13) self.write_data(0x18) self.write_data(0x04) self.write_data(0x0F) self.write_data(0x06) self.write_data(0x3a) self.write_data(0x56) self.write_data(0x4d) self.write_data(0x03) self.write_data(0x0a) self.write_data(0x06) self.write_data(0x30) self.write_data(0x3e) self.write_data(0x0f) # GMCTRN1 = const(0xE1) # Negative gamma correction self.write_cmd(0xE1) self.write_data(0x00) self.write_data(0x13) self.write_data(0x18) self.write_data(0x01) self.write_data(0x11) self.write_data(0x06) self.write_data(0x38) self.write_data(0x34) self.write_data(0x4d) self.write_data(0x06) self.write_data(0x0d) self.write_data(0x0b) self.write_data(0x31) self.write_data(0x37) self.write_data(0x0f) # PIXFMT = const(0x3A) # COLMOD: Pixel format set self.write_cmd(0x3A) self.write_data(0x55) # 16bits/pixel # SLPOUT = const(0x11) # Exit sleep mode self.write_cmd(0x11) time.sleep_ms(117) self.write_cmd(0x29) # DFUNCTR = const(0xB6) # Display function control self.write_cmd(0xB6) self.write_data(0x00) self.write_data(0x62) # MADCTL = const(0x36) # Memory access control self.write_cmd(0x36) # Sets the memory access mode for rotation # bit 7-6:パネル方向 bit 5=0:横長 1:縦長 # bit 3は、常に1 bit 7654 3210 if self.rotate == 0: self.write_data(0x88) # 1000 1000 elif self.rotate == 180: self.write_data(0x48) # 0100 1000 elif self.rotate == 90: self.write_data(0xe8) # 1110 1000 else: self.write_data(0x28) # 0010 1000 def write_cmd(self, cmd): self.cs(1) self.dc(0) self.cs(0) self.spi_lcd.write(bytearray([cmd])) self.cs(1) def write_data(self, buf): self.cs(1) self.dc(1) self.cs(0) #self.spi_lcd.write(bytearray([0x00])) self.spi_lcd.write(bytearray([buf])) self.cs(1) # 全エリアに描画 def show(self): if self.rotate == 0 or self.rotate == 180: # SET_COLUMN = const(0x2A) # Column address set self.write_cmd(0x2A) self.write_data(0x00) # Start Column self.write_data(0x00) # 0x0000 self.write_data(0x01) # End Column self.write_data(0x3f) # 0x013f:319 # SET_PAGE = const(0x2B) # Page address set self.write_cmd(0x2B) self.write_data(0x00) # Start Page self.write_data(0x00) # 0x0000 self.write_data(0x01) # End Page self.write_data(0xdf) # 0x01df:479 else: # self.rotate == 90 or self.rotate == 270: # SET_COLUMN = const(0x2A) # Column address set self.write_cmd(0x2A) self.write_data(0x00) # Start Column self.write_data(0x00) # 0x0000 self.write_data(0x01) # End Column self.write_data(0xdf) # 0x01df:479 # SET_PAGE = const(0x2B) # Page address set self.write_cmd(0x2B) self.write_data(0x00) # Start Page self.write_data(0x00) # 0x0000 self.write_data(0x01) # End Page self.write_data(0x3f) # 0x013f:319 # WRITE_RAM = const(0x2C) # Memory write self.write_cmd(0x2C) self.cs(1) self.dc(1) self.cs(0) self.spi_lcd.write(self.buffer) self.cs(1) # 2025/06/29 Add # 拡大表示するテキスト描画関数 # scale:拡大率(整数) def text_scaled(self, text, x, y, color, scale=1): # 一時的なフレームバッファを作成(文字描画用) temp_fb = framebuf.FrameBuffer(bytearray(8 * len(text) * 8),\ 8 * len(text), 8, framebuf.MONO_HLSB) temp_fb.fill(0) # 背景をクリア temp_fb.text(text, 0, 0, 1) # 文字を描画 # 各ピクセルを拡大して描画 for yy in range(8): for xx in range(8 * len(text)): if temp_fb.pixel(xx, yy): # 文字のピクセルがある場合 self.fill_rect(x + xx * scale, y + yy * scale,\ scale, scale, color) def bl_ctrl(self,duty): pwm = PWM(Pin(LCD_BL)) pwm.freq(1000) if(duty>=100): pwm.duty_u16(65535) else: pwm.duty_u16(655*duty) def touch_get(self): if self.irq() == 0: # spi1 Switching to Touch Panel # 2025/07/03 : 使用都度、設定し直す、この方法が良いようだ。 # Touch Panel(XPT2046) 4MHz self.spi_touch = SPI(1, baudrate=4_000_000, sck=Pin(LCD_SCK),\ mosi=Pin(LCD_MOSI), miso=Pin(LCD_MISO)) self.tp_cs(0) time.sleep_ms(1) for i in range(0,3): self.spi_touch.write(bytearray([0xD0])) Read_date = self.spi_touch.read(2) time.sleep_us(17) x_touch = ((Read_date[0] <<8) + Read_date[1]) >>3 self.spi_touch.write(bytearray([0x90])) Read_date = self.spi_touch.read(2) time.sleep_us(17) y_touch = ((Read_date[0] <<8) + Read_date[1]) >>3 time.sleep_ms(1) self.tp_cs(1) # DEBUG ADJ 用 #################################################### if PRINT_TOUCH_POS: print('x_touch = ', x_touch, ' y_touch = ', y_touch) ################################################################### # spi1 Switching to LCD # 2025/07/03 : 使用が終われば、設定を元に戻す。この方法が良いようだ。 # Before LCD(ILI9488) 40MHz # self.spi_lcd = SPI(1, baudrate=40_000_000, sck=Pin(LCD_SCK),\ # mosi=Pin(LCD_MOSI), miso=Pin(LCD_MISO)) # # 2025/09/05 After LCD(ILI9488) 20MHz self.spi_lcd = SPI(1,baudrate=20_000_000,sck=Pin(LCD_SCK),\ mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO)) ############################## # Set Here Adjuste Parameter # x_min ===> x_max # 4800 7350 # y_min ----------------- # | | # 4700 | + + | # | | # | LCD Panel | # | |_ # | | | USB connector # 7700 | + + |~ # | | # y_max ----------------- # ~~ USB connector ########################################################### # 2025/07/24 ADJ # 四隅ではなく、各40Pixcel 中央寄りの四隅の値を基準に決める方法に変更 # 2025/08/14 Adj No3 Touch LCD # 左上の XT XY の値 result40_40 = [4800,4720] # [4900,4800] # 右上の XT XY の値 result280_40 = [7400,4720] # [7450,4800] # 左下の XT XY の値 result40_440 = [4800,7700] # [4900,7800] # 右下の XT XY の値 result280_440 = [7400,7700] # [7450,7800] # 右下の XT XY の値は、利用していない x_min = int(result40_40[0] - ((result280_40[0] - result40_40[0]) *40 /(280 -40))) x_max = int(result280_40[0] + ((result280_40[0] - result40_40[0]) *40 /(280 -40))) y_min = int(result40_40[1] - ((result40_440[1] - result40_40[1]) *40 /(440 -40))) y_max = int(result40_440[1] + ((result40_440[1] - result40_40[1]) *40 /(440 -40))) ######################### x_range = x_max - x_min y_range = y_max - y_min ######################### # Result_list = [touch_,touch_Y] # 2025/07/02 : self.rotate の方向で、LCD位置に合わせた座標を返す if self.rotate == 0 or self.rotate == 180: if self.rotate == 0: # X軸Y軸の座標入替なし and X軸Y軸とも 数値変換なし X_Point = 320 - int((x_touch - x_min) *320 /x_range) Y_Point = 480 - int((y_touch - y_min) *480 /y_range) elif self.rotate == 180: # X軸Y軸の座標入替なし and Y軸は 数値大小入替 X_Point = int((x_touch - x_min) *320 /x_range) Y_Point = int((y_touch - y_min) *480 /y_range) # 範囲内に収める 2025/07/17 修正 if X_Point >= 320: X_Point = 319 elif X_Point < 0: X_Point = 0 if Y_Point >= 480: Y_Point = 479 elif Y_Point < 0: Y_Point = 0 else: # self.rotate == 90 or self.rotate == 270: if self.rotate == 90: # X軸Y軸の座標入替あり and X軸は 数値大小入替 X_Point = 480 - int((y_touch - y_min) *480 /y_range) Y_Point = int((x_touch - x_min) *320 /x_range) elif self.rotate == 270: # X軸Y軸の座標入替あり and Y軸は 数値大小入替 X_Point = int((y_touch - y_min) *480 /y_range) Y_Point = 320 - int((x_touch - x_min) *320 /x_range) # 範囲内に収める 2025/07/17 修正 if X_Point >= 480: X_Point = 479 elif X_Point < 0: X_Point = 0 if Y_Point >= 320: Y_Point = 319 elif Y_Point < 0: Y_Point = 0 if TOUCH_ADJ: # タッチポイント調整用に生のポイントデータを返す # 2025/07/23 Result_list = [X_Point, Y_Point, x_touch, y_touch] else: # LCD Pixcel に変換したデータのみを返す Result_list = [X_Point, Y_Point] if PRINT_TOUCH_POS: # タッチされた座標を表示 print(Result_list) return(Result_list) def spi_change2_lcd(): # SD-Card 処理後にSPI-1 の設定を LCD に戻す # 2025/09/05 After LCD(ILI9488) 20MHz self.spi_lcd = SPI(1,baudrate=20_000_000,sck=Pin(LCD_SCK),\ mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO)) if __name__=='__main__': LCD = LCD_3inch5() LCD.bl_ctrl(100) print('LCD.rotate = ', LCD.rotate) LCD.fill(LCD.WHITE) X_Point_Old = 0 Y_Point_Old = 0 #調整用ポイントの座標の設定 # TOUCH_ADJ = True # ROTATE = const(180) にすること if LCD.rotate == 0 or LCD.rotate == 180: # 縦長表示 の直後 # 調整用ポイントの座標の設定 pos40_40 = [ 40, 40] pos280_40 = [280, 40] pos40_440 = [ 40,440] pos280_440 = [280,440] #color BRG LCD.fill(LCD.WHITE) # 調整用ポイントの座標を 5Pixel x 5Pixel で表示する LCD.fill_rect(pos40_40[0]-2, pos40_40[1]-2, 5, 5, LCD.RED) LCD.fill_rect(pos280_40[0]-2, pos280_40[1]-2, 5, 5, LCD.RED) LCD.fill_rect(pos40_440[0]-2, pos40_440[1]-2, 5, 5, LCD.RED) LCD.fill_rect(pos280_440[0]-2, pos280_440[1]-2, 5, 5, LCD.RED) LCD.show() scope = 10 # 移動平均 Average 個数 X_listT = [None] * scope Y_listT = [None] * scope X_listL = [None] * scope Y_listL = [None] * scope cnt_scope = 0 # 各ポジションの集計結果を利用可能(10回以上計測)になればセット flag40_40 = 0 flag280_40 = 0 flag40_440 = 0 flag280_440 = 0 # 測定結果が出たらセット flag_result = 0 # Touch Point 表示 while True: get = LCD.touch_get() if get != None: # タッチされているなら if TOUCH_ADJ: # 調整モードなら、タッチ生データ get[2], get[3] を取得 X_PointL = get[0] Y_PointL = get[1] X_PointT = get[2] Y_PointT = get[3] else: # LCD 座標変換データ取得 X_PointL = get[0] Y_PointL = get[1] # 移動平均計算用にデータを記録 X_listL[cnt_scope] = X_PointL Y_listL[cnt_scope] = Y_PointL X_listT[cnt_scope] = X_PointT Y_listT[cnt_scope] = Y_PointT if flag_result == 0: cnt_scope += 1 if cnt_scope >= scope: cnt_scope = 0 if flag_result == 0: flag_result = 1 else: # 移動平均 10 計算 X_totalL = 0 Y_totalL = 0 X_totalT = 0 Y_totalT = 0 for i in range(scope): X_totalL += X_listL[i] Y_totalL += Y_listL[i] X_totalT += X_listT[i] Y_totalT += Y_listT[i] # 移動平均 10 X_aveL = int(X_totalL / scope) Y_aveL = int(Y_totalL / scope) X_aveT = int(X_totalT / scope) Y_aveT = int(Y_totalT / scope) # 領域別に表示 # 初期状態 中心と思われる 4800 4700 の +400 +400 if X_aveT < 5200 and Y_aveT < 5100: # pos40_40 の 値を収録 ave40_40 = [X_aveT, Y_aveT] flag40_40 += 1 if flag40_40 >= 10: # 文字領域を 白色にしてから表示 LCD.fill_rect(20,80,16*8,80, LCD.WHITE) LCD.text_scaled(f'XL:{X_aveL}',20, 80,LCD.BLUE, 2) LCD.text_scaled(f'XT:{X_aveT}',20,100,LCD.BLUE, 2) LCD.text_scaled(f'YL:{Y_aveL}',20,120,LCD.BLUE, 2) LCD.text_scaled(f'YT:{Y_aveT}',20,140,LCD.BLUE, 2) # 初期状態 中心と思われる 7350 4700 の -400 +400 elif X_aveT > 6950 and Y_aveT < 5100: # pos280_40 の 値を収録 ave280_40 = [X_aveT, Y_aveT] flag280_40 += 1 if flag280_40 >= 10: # 文字領域を 白色にしてから表示 LCD.fill_rect(180,80,16*8,80, LCD.WHITE) LCD.text_scaled(f'XL:{X_aveL}',180, 80,LCD.BLUE, 2) LCD.text_scaled(f'XT:{X_aveT}',180,100,LCD.BLUE, 2) LCD.text_scaled(f'YL:{Y_aveL}',180,120,LCD.BLUE, 2) LCD.text_scaled(f'YT:{Y_aveT}',180,140,LCD.BLUE, 2) # 初期状態 中心と思われる 4800 7700 の +400 -400 elif X_aveT < 5200 and Y_aveT > 7300: # pos40_440 の 値を収録 ave40_440 = [X_aveT, Y_aveT] flag40_440 += 1 if flag40_440 >= 10: # 文字領域を 白色にしてから表示 LCD.fill_rect(20,340,16*8,80, LCD.WHITE) LCD.text_scaled(f'XL:{X_aveL}',20,340,LCD.BLUE, 2) LCD.text_scaled(f'XT:{X_aveT}',20,360,LCD.BLUE, 2) LCD.text_scaled(f'YL:{Y_aveL}',20,380,LCD.BLUE, 2) LCD.text_scaled(f'YT:{Y_aveT}',20,400,LCD.BLUE, 2) # 初期状態 中心と思われる 7350 7700 の -400 -400 elif X_aveT > 6950 and Y_aveT > 7300: # pos280_440 の 値を収録 ave280_440 = [X_aveT, Y_aveT] flag280_440 += 1 if flag280_440 >= 10: # 文字領域を 白色にしてから表示 LCD.fill_rect(180,340,16*8,80, LCD.WHITE) LCD.text_scaled(f'XL:{X_aveL}',180,340,LCD.BLUE, 2) LCD.text_scaled(f'XT:{X_aveT}',180,360,LCD.BLUE, 2) LCD.text_scaled(f'YL:{Y_aveL}',180,380,LCD.BLUE, 2) LCD.text_scaled(f'YT:{Y_aveT}',180,400,LCD.BLUE, 2) # 四隅のデータが揃ったら結果を表示する if flag280_40 >= 10 and flag280_40 >= 10 and flag40_440 >= 10 and flag280_440 >= 10: LCD.fill_rect(10,200,310,120, LCD.WHITE) LCD.text_scaled(f'Set def Result Data',10,200,LCD.BLACK, 2) LCD.text_scaled(f'def touch_get(self):',10,220,LCD.BLACK, 2) LCD.text_scaled(f'rt40_40 ={ave40_40[0]},{ave40_40[1]}',10,240,LCD.BLACK, 2) LCD.text_scaled(f'rt280_40 ={ave280_40[0]},{ave280_40[1]}',10,260,LCD.BLACK, 2) LCD.text_scaled(f'rt40_440 ={ave40_440[0]},{ave40_440[1]}',10,280,LCD.BLACK, 2) LCD.text_scaled(f'rt280_440={ave280_440[0]},{ave280_440[1]}',10,300,LCD.BLACK, 2) LCD.show() else: cnt_scope = 0 flag_result = 0 time.sleep_ms(47) ``` ### tab_cdn.py ```MicroPython:tab_cdn.py ######################################################################## # main-menu と sub-menu の タブを表示させるための座標提供 # tab_cdn_yyyymmdd-hhmm.py # # エクスポート可能 # main-menu と sub-menu の タブの座標(開始座標と終末座標)を # 他の関数に提供する # ######################################################################## import time from micropython import const ################################################# # MicroPython ################################################# class TabCoordinate: def __init__(self): # 初期設定 self.Item = 5 self.Mxs = 0 self.Mys = 0 self.Sxs = 0 self.Sys = 240 self.UPys = 24 self.LWys = 264 self.UPzs = [0, self.UPys] self.LWzs = [0, self.LWys] self.chr_n = 4 # タブの文字数 self.chr_w = 16 # 文字幅 self.chr_h = 16 # 文字高さ self.xb = 4 # 縦線幅 x self.yb = 4 # 横線幅 y # タブの全体幅 80 self.w = self.chr_n *self.chr_w + self.xb *4 # タブの全体高さ 24 self.h = self.chr_h + self.yb *2 # main-tab と sub-tab の表示内容 self.tabMain_text = [' ', 'get ', 'com ', ' op ', 'put '] self.tabCOM_text = [' ', 'ALG ', ' BO ', 'LFO ', ' '] self.tabOP_text = [' ', ' WS ', 'MUL ', 'ADSR', 'DAM '] self.tabGET_text = [' ', ' MR ', ' SD ', ' ', ' '] self.tabPUT_text = [' ', 'YMF ', ' SD ', ' ', 'MODE'] # main-tab と sub-tab の開始座標 self.zoneMtab_s = [[self.Mxs +self.xb +self.w*0,self.Mys],\ [self.Mxs +self.xb +self.w*0,self.Mys],\ [self.Mxs +self.xb +self.w*1,self.Mys],\ [self.Mxs +self.xb +self.w*2,self.Mys],\ [self.Mxs +self.xb +self.w*3,self.Mys]] self.zoneStab_s = [[self.Sxs +self.xb +self.w*0,self.Sys],\ [self.Sxs +self.xb +self.w*0,self.Sys],\ [self.Sxs +self.xb +self.w*1,self.Sys],\ [self.Sxs +self.xb +self.w*2,self.Sys],\ [self.Sxs +self.xb +self.w*3,self.Sys]] # main-tab と sub-tab の終了座標 他のクラスへのエクスポート用 self.zoneMtab_e = [None] * self.Item self.zoneStab_e = [None] * self.Item # Oparation No Tab の開始座標と終末座標 self.zOPs = [None] * self.Item self.zOPe = [None] * self.Item for i in range(self.Item): self.zoneMtab_e[i] = [self.zoneMtab_s[i][0]+self.w, self.zoneMtab_s[i][1]+self.h] self.zoneStab_e[i] = [self.zoneStab_s[i][0]+self.w, self.zoneStab_s[i][1]+self.h] self.zOPs[i] = 0 self.zOPe[i] = 0 # ALG ラベルの開始座標と終末座標の準備 alg_num = 8 self.zALGs = [None] *alg_num self.zALGe = [None] *alg_num for i in range(alg_num): self.zALGs[i] = 0 self.zALGe[i] = 0 # タブの座標 リスト提供 def get_zoneMtab_s(self): return self.zoneMtab_s def get_zoneMtab_e(self): return self.zoneMtab_e def get_zoneStab_s(self): return self.zoneStab_s def get_zoneStab_e(self): return self.zoneStab_e # タブのテキストをリストで提供 def get_tabMain_text(self): return self.tabMain_text def get_tabCOM_text(self): return self.tabCOM_text def get_tabOP_text(self): return self.tabOP_text def get_tabGET_text(self): return self.tabGET_text def get_tabPUT_text(self): return self.tabPUT_text # 個別タブの開始座標と終末座標の提供 def get_zMs(self, num): return self.zoneMtab_s[num] def get_zMe(self, num): return self.zoneMtab_e[num] # メニュー・タブの開始座標と終末座標の提供 def get_zSs(self, num): return self.zoneStab_s[num] def get_zSe(self, num): return self.zoneStab_e[num] # 上段の表示エリアと下段表示エリアの情報 def get_UpperAria(self): # 開始座標 幅 高さ return (self.UPzs, 320, 240-24) def get_LowerAria(self): # 開始座標 幅 高さ return (self.LWzs, 320, 240-24) # 上段表示エリアの開始座標と終末座標の提供 def get_zUPs(self): # 開始座標 幅 高さ # return (self.UPzs, 320, 240-24) return (self.UPzs) def get_zUPe(self): # 開始座標 幅 高さ # return (self.UPzs, 320, 240-24) return (self.UPzs[0] +320, self.UPzs[1] +(240-24)) # 下段表示エリアの開始座標と終末座標の提供 def get_zLWs(self): # 開始座標 幅 高さ # return (self.LWzs, 320, 240-24) return (self.LWzs) def get_zLWe(self): # 開始座標 幅 高さ # return (self.LWzs, 320, 240-24) return (self.LWzs[0] +320, self.LWzs[1] +(240-24)) # tone_edit の関数 alg_zl_save() からセットする # 上段に表示する時の op1 ~ op4 の zl 座標 ・・・ 中心線の開始座標である # alg_patarn(alg, stage, color_line, color_back, color_text) # を利用するのに便利 def alg_zlOP_save(self, zlOP): self.zlOP = zlOP def get_zlOP(self): return self.zlOP # tone_edit の関数 alg_zs_save() からセットする op1 ~ op4 の開始座標と終末座標 # タッチセンス用の座標である def alg_zOP_save(self, zOP1s, zOP1e, zOP2s, zOP2e, zOP3s, zOP3e, zOP4s, zOP4e): # 存在しない self.zOPs[0] = [0, 0] self.zOPe[0] = [0, 0] # タッチエリアを上下に 8Pixel 拡大 self.zOPs[1] = [zOP1s[0], zOP1s[1] -8] self.zOPe[1] = [zOP1e[0], zOP1e[1] +8] self.zOPs[2] = [zOP2s[0], zOP2s[1] -8] self.zOPe[2] = [zOP2e[0], zOP2e[1] +8] self.zOPs[3] = [zOP3s[0], zOP3s[1] -8] self.zOPe[3] = [zOP3e[0], zOP3e[1] +8] self.zOPs[4] = [zOP4s[0], zOP4s[1] -8] self.zOPe[4] = [zOP4e[0], zOP4e[1] +8] # ALG op1 ~ op4 の開始座標の提供 def get_zOPs(self): return self.zOPs # ALG op1 ~ op4 の終末座標の提供 def get_zOPe(self): return self.zOPe # alg0 ~ alg7 表示ラベルの開始座標と終末座標 # tone_edit の関数 alg_zALG_save() からセットする def alg_zALG_save(self, alg_LBs, alg_LBe): self.alg_LBs = alg_LBs self.alg_LBe = alg_LBe # ALG 表示ラベルの開始座標リストで提供 def get_zALGs(self): # return self.zALGs return self.alg_LBs # ALG 表示ラベルの終末座標リストで提供 def get_zALGe(self): # return self.zALGe return self.alg_LBe # tone_edit の関数 def wave_form() の中の # TAB.zWS_save(zWSs, zWSe) からセットする WS:0 ~ WS:30 の開始座標と終末座標 def zWS_save(self, zWSs, zWSe): self.zWSs = zWSs self.zWSe = zWSe # WS:0 ~ WS:30 の開始座標をリストで提供 def get_zWSs(self): return self.zWSs # WS:0 ~ WS:30 の終末座標をリストで提供 def get_zWSe(self): return self.zWSe def save_BtnExec(self, zEXEs, zEXEe): self.zEXEs = zEXEs self.zEXEe = zEXEe def save_BtnCansel(self, zCANs, zCANe): self.zCANs = zCANs self.zCANe = zCANe def get_zEXEs(self): return self.zEXEs def get_zEXEe(self): return self.zEXEe def get_zCANs(self): return self.zCANs def get_zCANe(self): return self.zCANe ``` ### sdcard.py ```MicroPython:sdcard.py """ MicroPython driver for SD cards using SPI bus. Requires an SPI bus and a CS pin. Provides readblocks and writeblocks methods so the device can be mounted as a filesystem. Example usage on pyboard: import pyb, sdcard, os sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) pyb.mount(sd, '/sd2') os.listdir('/') Example usage on ESP8266: import machine, sdcard, os sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) os.mount(sd, '/sd') os.listdir('/') """ from micropython import const import time _CMD_TIMEOUT = const(100) _R1_IDLE_STATE = const(1 << 0) # R1_ERASE_RESET = const(1 << 1) _R1_ILLEGAL_COMMAND = const(1 << 2) # R1_COM_CRC_ERROR = const(1 << 3) # R1_ERASE_SEQUENCE_ERROR = const(1 << 4) # R1_ADDRESS_ERROR = const(1 << 5) # R1_PARAMETER_ERROR = const(1 << 6) _TOKEN_CMD25 = const(0xFC) _TOKEN_STOP_TRAN = const(0xFD) _TOKEN_DATA = const(0xFE) class SDCard: def __init__(self, spi, cs, baudrate=1320000): self.spi = spi self.cs = cs self.cmdbuf = bytearray(6) self.dummybuf = bytearray(512) self.tokenbuf = bytearray(1) for i in range(512): self.dummybuf[i] = 0xFF self.dummybuf_memoryview = memoryview(self.dummybuf) # initialise the card self.init_card(baudrate) def init_spi(self, baudrate): try: master = self.spi.MASTER except AttributeError: # on ESP8266 self.spi.init(baudrate=baudrate, phase=0, polarity=0) else: # on pyboard self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) def init_card(self, baudrate): # init CS pin self.cs.init(self.cs.OUT, value=1) # init SPI bus; use low data rate for initialisation self.init_spi(100000) # clock card at least 100 cycles with cs high for i in range(16): self.spi.write(b"\xff") # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) for _ in range(5): if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: break else: raise OSError("no SD card") # CMD8: determine card version r = self.cmd(8, 0x01AA, 0x87, 4) if r == _R1_IDLE_STATE: self.init_card_v2() elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): self.init_card_v1() else: raise OSError("couldn't determine SD card version") # get the number of sectors # CMD9: response R2 (R1 byte + 16-byte block read) if self.cmd(9, 0, 0, 0, False) != 0: raise OSError("no response from SD card") csd = bytearray(16) self.readinto(csd) if csd[0] & 0xC0 == 0x40: # CSD version 2.0 self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 read_bl_len = csd[5] & 0b1111 capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) self.sectors = capacity // 512 else: raise OSError("SD card CSD format not supported") # print('sectors', self.sectors) # CMD16: set block length to 512 bytes if self.cmd(16, 512, 0) != 0: raise OSError("can't set 512 block size") # set to high data rate now that it's initialised self.init_spi(baudrate) def init_card_v1(self): for i in range(_CMD_TIMEOUT): time.sleep_ms(50) self.cmd(55, 0, 0) if self.cmd(41, 0, 0) == 0: # SDSC card, uses byte addressing in read/write/erase commands self.cdv = 512 # print("[SDCard] v1 card") return raise OSError("timeout waiting for v1 card") def init_card_v2(self): for i in range(_CMD_TIMEOUT): time.sleep_ms(50) self.cmd(58, 0, 0, 4) self.cmd(55, 0, 0) if self.cmd(41, 0x40000000, 0) == 0: self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte ocr = self.tokenbuf[0] # get first byte of response, which is OCR if not ocr & 0x40: # SDSC card, uses byte addressing in read/write/erase commands self.cdv = 512 else: # SDHC/SDXC card, uses block addressing in read/write/erase commands self.cdv = 1 # print("[SDCard] v2 card") return raise OSError("timeout waiting for v2 card") def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): self.cs(0) # create and send the command buf = self.cmdbuf buf[0] = 0x40 | cmd buf[1] = arg >> 24 buf[2] = arg >> 16 buf[3] = arg >> 8 buf[4] = arg buf[5] = crc self.spi.write(buf) if skip1: self.spi.readinto(self.tokenbuf, 0xFF) # wait for the response (response[7] == 0) for i in range(_CMD_TIMEOUT): self.spi.readinto(self.tokenbuf, 0xFF) response = self.tokenbuf[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here # if final<0 then store the first byte to tokenbuf and discard the rest if final < 0: self.spi.readinto(self.tokenbuf, 0xFF) final = -1 - final for j in range(final): self.spi.write(b"\xff") if release: self.cs(1) self.spi.write(b"\xff") return response # timeout self.cs(1) self.spi.write(b"\xff") return -1 def readinto(self, buf): self.cs(0) # read until start byte (0xff) for i in range(_CMD_TIMEOUT): self.spi.readinto(self.tokenbuf, 0xFF) if self.tokenbuf[0] == _TOKEN_DATA: break time.sleep_ms(1) else: self.cs(1) raise OSError("timeout waiting for response") # read data mv = self.dummybuf_memoryview if len(buf) != len(mv): mv = mv[: len(buf)] self.spi.write_readinto(mv, buf) # read checksum self.spi.write(b"\xff") self.spi.write(b"\xff") self.cs(1) self.spi.write(b"\xff") def write(self, token, buf): self.cs(0) # send: start of block, data, checksum self.spi.read(1, token) self.spi.write(buf) self.spi.write(b"\xff") self.spi.write(b"\xff") # check the response if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: self.cs(1) self.spi.write(b"\xff") return # wait for write to finish while self.spi.read(1, 0xFF)[0] == 0: pass self.cs(1) self.spi.write(b"\xff") def write_token(self, token): self.cs(0) self.spi.read(1, token) self.spi.write(b"\xff") # wait for write to finish while self.spi.read(1, 0xFF)[0] == 0x00: pass self.cs(1) self.spi.write(b"\xff") def readblocks(self, block_num, buf): # workaround for shared bus, required for (at least) some Kingston # devices, ensure MOSI is high before starting transaction self.spi.write(b"\xff") nblocks = len(buf) // 512 assert nblocks and not len(buf) % 512, "Buffer length is invalid" if nblocks == 1: # CMD17: set read address for single block if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: # release the card self.cs(1) raise OSError(5) # EIO # receive the data and release card self.readinto(buf) else: # CMD18: set read address for multiple blocks if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: # release the card self.cs(1) raise OSError(5) # EIO offset = 0 mv = memoryview(buf) while nblocks: # receive the data and release card self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 if self.cmd(12, 0, 0xFF, skip1=True): raise OSError(5) # EIO def writeblocks(self, block_num, buf): # workaround for shared bus, required for (at least) some Kingston # devices, ensure MOSI is high before starting transaction self.spi.write(b"\xff") nblocks, err = divmod(len(buf), 512) assert nblocks and not err, "Buffer length is invalid" if nblocks == 1: # CMD24: set write address for single block if self.cmd(24, block_num * self.cdv, 0) != 0: raise OSError(5) # EIO # send the data self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: raise OSError(5) # EIO # send the data offset = 0 mv = memoryview(buf) while nblocks: self.write(_TOKEN_CMD25, mv[offset : offset + 512]) offset += 512 nblocks -= 1 self.write_token(_TOKEN_STOP_TRAN) def ioctl(self, op, arg): if op == 4: # get number of blocks return self.sectors if op == 5: # get block size in bytes return 512 ``` ### ymf825.py ```MicroPython:ymf825.py ############################################################################# # YMF825 synthesizer with Raspberry Pi PICO W. # # Hardware Information: # YMF825 bottom view # 1 2 3 4 5 6 7 8 9 # -+-+-+-+-+-+-+-+-+- # | S M M C G V R | # | S O I L N C S | # | S S K D C T | # | I O | # | Audio Jack # ---------------+--- # | # ---Amp # # PICO GPIO(pin) YMF825 name(pin) LED(n/a) # 5V (40) VCC (6) # GND (38) GND (5) # SPI1 MOSI 19(25) SPI MOSI (2) # SPI1 MISO 16(21) SPI MISO (3) # SPI1 CLK 18( 24) SPI CLK (4) # SPI1 CS 17(22) SS (1) # RESET 22(29) RESET (7) #n/a LED 28(34) Anode---1K--->|---Cathode---GND # # Copyright (c) by Shunsuke Ohira # 00.100 2023/08/05: Play Do-Re-Mi # # 20240326 Change Voice_Op_Orig & VoiceZ_Op_Edit # # 20241014 Note On Velocity 対応 ・・・ 固定値(0x54)から指定値(vol)対応へ # ############################################################################# from machine import SPI, UART, Pin import time import utime import uos from micropython import const import mojipy as moji ############################################################################### # 上記インポートファイルは、予め、Picoに書き込んでおくこと # Thonnyで 当該ファイルを開いて、Picoに書き込む。 # 直下に # mojipy.py : 文字処理用 ############################################################################### # YMF825 FM_OP_NUM = const(4) # number of FM operators OP_PARAM_NUM = const(10) # number of operater parameters TONE_NUM = const(16) # number of tones TONE_OP_NUM = const(4) # number of TONE operators TONE_PARAM_NUM = const(17) # number of tone parameters TONE_HEADER = const(16) # ToneID(1) + ToneName(15) ToneName = [None] * (TONE_NUM +1) ToneName[0] = 'GRAND_PIANO' ToneName[1] = 'E_PIANO' ToneName[2] = 'TENOR_SAX' ToneName[3] = 'PICK_BASS' ToneName[4] = 'TNKL_BELL' ToneName[5] = 'NEW_AGE_PD' ToneName[6] = 'BRIGHT_PIANO' ToneName[7] = 'VIBES' ToneName[8] = 'CHURCH_ORGAN' ToneName[9] = 'FLUTE' ToneName[10] = 'ROCK_ORGAN' ToneName[11] = 'NYLON_GUITER' ToneName[12] = 'SQUARE_LEAD' ToneName[13] = 'SAW_LEAD' ToneName[14] = 'HARPSICHORD' ToneName[15] = 'HARMONICA' ToneName[16] = 'No Tone' TONE_MENU_COL_NUM = const(2) # number of tones menu TONE_MENU_ROW_NUM = const(17) # number of tones menu # ToneMenuTable の生成 ToneMenuTable = [None] * TONE_MENU_ROW_NUM # 17 for i in range(TONE_MENU_ROW_NUM): ToneMenuTable[i] = [None] * TONE_MENU_COL_NUM # 2 ToneMenuTable[0][1] = ' Select Tone' for i in range(1, TONE_MENU_ROW_NUM): ToneMenuTable[i][0] = i -1 ToneMenuTable[i][1] = ToneName[i -1] TONE_TABLE_COL_NUM = const(2) # number of tones menu TONE_TABLE_ROW_NUM = const(17) # number of tones menu # ToneTavle の生成 ToneTable = [None] * TONE_TABLE_ROW_NUM # 17 for i in range(TONE_TABLE_ROW_NUM): ToneTable[i] = [None] * TONE_TABLE_COL_NUM # 2 ToneTable[0][1] = ' Select Tone' for i in range(1, TONE_TABLE_ROW_NUM): ToneTable[i][0] = i -1 # ToneTable[i][1] = 16 # 16:No Tone ToneTable[i][1] = 0 # 0:GRAND PIANO # Original Tone Data by YAMAHA # | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | Tone_Com_Orig = [0x0b,0x0d,0x0d,0x0b,0x0d,0x0d,0x0b,0x0d, # | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 0x0f,0x0d,0x17,0x15,0x15,0x15,0x0e,0x14] Tone_Op_Orig = [ # 00:GrandPiano [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x01,0x0f,0x07,0x00,0x06,0x0f,0x27,0x00,0x01,0x08], # op2 [0x07,0x0e,0x03,0x02,0x03,0x02,0x28,0x00,0x05,0x00], # op3 [0x00,0x0d,0x01,0x01,0x04,0x03,0x22,0x01,0x01,0x00], # op4 [0x06,0x0d,0x02,0x02,0x06,0x04,0x00,0x01,0x01,0x00] ], # 01:E.Piano [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x54,0x0f,0x04,0x05,0x0c,0x0b,0x23,0x44,0x07,0x12], # op2 [0x02,0x0f,0x02,0x01,0x08,0x0f,0x04,0x45,0x01,0x00], # op3 [0x25,0x0f,0x00,0x01,0x0b,0x01,0x12,0x44,0x01,0x00], # op4 [0x04,0x0f,0x02,0x01,0x07,0x0f,0x04,0x41,0x01,0x00] ], # 02:TenorSax [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x36,0x07,0x03,0x00,0x00,0x00,0x05,0x44,0x01,0x01], # op2 [0x00,0x07,0x02,0x00,0x09,0x00,0x0f,0x43,0x01,0x08], # op3 [0x36,0x07,0x03,0x00,0x00,0x00,0x08,0x44,0x01,0x09], # op4 [0x02,0x07,0x02,0x00,0x09,0x00,0x0d,0x43,0x01,0x00] ], # 03:PickBass [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x56,0x0f,0x07,0x02,0x03,0x01,0x13,0x44,0x01,0x00], # op2 [0x04,0x0c,0x0b,0x04,0x06,0x07,0x15,0x44,0x07,0x00], # op3 [0x06,0x0f,0x09,0x02,0x06,0x02,0x17,0x44,0x02,0x00], # op4 [0x04,0x0b,0x02,0x06,0x08,0x06,0x00,0x44,0x01,0x00] ], # 04:TnklBell [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x31,0x0f,0x06,0x03,0x04,0x05,0x10,0x44,0x0e,0x00], # op2 [0x02,0x0c,0x06,0x07,0x06,0x0e,0x0b,0x44,0x02,0x00], # op3 [0x00,0x0c,0x06,0x02,0x02,0x05,0x1e,0x44,0x77,0x01], # op4 [0x00,0x0f,0x05,0x04,0x05,0x0d,0x01,0x54,0x06,0x00] ], # 05:NewAgePd [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x54,0x0f,0x0f,0x03,0x03,0x00,0x26,0x44,0x07,0x01], # op2 [0x02,0x0f,0x07,0x04,0x04,0x00,0x0b,0x44,0x05,0x00], # op3 [0x62,0x06,0x01,0x00,0x01,0x00,0x18,0x03,0x71,0x01], # op4 [0x02,0x08,0x01,0x00,0x05,0x01,0x00,0x03,0x01,0x00] ], # 06:BrightPiano [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x06,0x0f,0x02,0x02,0x02,0x05,0x27,0x00,0x01,0x00], # op2 [0x02,0x0f,0x02,0x02,0x03,0x0f,0x1c,0x00,0x05,0x00], # op3 [0x06,0x0f,0x02,0x02,0x02,0x0d,0x19,0x01,0x01,0x00], # op4 [0x04,0x0f,0x02,0x01,0x05,0x04,0x0a,0x01,0x01,0x00] ], # 07:Vibes [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x00,0x0c,0x04,0x02,0x04,0x02,0x17,0x41,0x07,0x00], # op2 [0x06,0x0d,0x09,0x02,0x05,0x06,0x07,0x51,0x04,0x00], # op3 [0x04,0x0c,0x04,0x02,0x03,0x02,0x1e,0x51,0x08,0x00], # op4 [0x00,0x0d,0x02,0x03,0x04,0x0f,0x07,0x31,0x01,0x00] ], # 08:ChurchOrgan [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x02,0x09,0x0f,0x00,0x05,0x00,0x13,0x00,0x03,0x00], # op2 [0x00,0x0b,0x07,0x00,0x02,0x02,0x1d,0x00,0x07,0x00], # op3 [0x02,0x08,0x0f,0x00,0x05,0x00,0x04,0x00,0x01,0x00], # op4 [0x02,0x08,0x07,0x00,0x05,0x00,0x04,0x00,0x00,0x05] ], # 09:Flute [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x70,0x0d,0x0a,0x00,0x01,0x01,0x07,0x10,0x03,0x00], # op2 [0x00,0x07,0x08,0x00,0x0b,0x03,0x25,0x01,0x03,0x00], # op3 [0x70,0x0e,0x08,0x00,0x09,0x00,0x27,0x31,0x01,0x00], # op4 [0x00,0x06,0x05,0x00,0x0a,0x00,0x01,0x11,0x01,0x10] ], # 10:RockOrgan [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x41,0x0f,0x0f,0x00,0x0d,0x00,0x09,0x70,0x31,0x00], # op2 [0x01,0x0b,0x0f,0x00,0x0a,0x01,0x05,0x50,0x01,0x15], # op3 [0x00,0x0f,0x0f,0x00,0x0e,0x00,0x09,0x13,0x62,0x00], # op4 [0x00,0x0f,0x0f,0x00,0x0e,0x00,0x09,0x33,0x70,0x11] ], # 11:NylonGuiter [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x65,0x0e,0x01,0x01,0x04,0x08,0x15,0x00,0x01,0x00], # op2 [0x00,0x0f,0x03,0x03,0x07,0x0f,0x00,0x01,0x01,0x00], # op3 [0x04,0x0b,0x05,0x05,0x05,0x04,0x0e,0x00,0x03,0x00], # op4 [0x02,0x0d,0x04,0x04,0x09,0x0f,0x0d,0x03,0x01,0x00] ], # 12:SquareLead [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x03,0x0f,0x0f,0x00,0x07,0x04,0x2e,0x00,0x01,0x08], # op2 [0x02,0x0a,0x0f,0x00,0x0a,0x00,0x03,0x03,0x01,0x08], # op3 [0x13,0x0f,0x0f,0x00,0x02,0x03,0x26,0x10,0x02,0x08], # op4 [0x02,0x0a,0x0f,0x00,0x0a,0x00,0x03,0x01,0x01,0x08] ], # 13:SawLead [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x70,0x0f,0x00,0x00,0x07,0x00,0x1a,0x41,0x71,0x00], # op2 [0x00,0x0d,0x0f,0x00,0x07,0x00,0x0a,0x41,0x71,0x08], # op3 [0x71,0x0f,0x0f,0x00,0x03,0x00,0x14,0x41,0x01,0x1c], # op4 [0x00,0x0e,0x0f,0x00,0x08,0x00,0x0a,0x41,0x01,0x08] ], # 14:Harpsichord [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x45,0x0e,0x02,0x02,0x05,0x00,0x00,0x00,0x01,0x04], # op2 [0x07,0x0f,0x02,0x00,0x05,0x03,0x14,0x00,0x06,0x03], # op3 [0x06,0x0f,0x03,0x00,0x01,0x06,0x1c,0x00,0x07,0x04], # op4 [0x04,0x0e,0x02,0x02,0x07,0x0f,0x04,0x03,0x01,0x05] ], # 15:Harmonica [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x03,0x0f,0x0f,0x00,0x09,0x00,0x2c,0x07,0x0e,0x00], # op2 [0x00,0x0f,0x0f,0x00,0x08,0x00,0x29,0x11,0x0a,0x00], # op3 [0x00,0x0f,0x0f,0x00,0x08,0x00,0x24,0x03,0x01,0x00], # op4 [0x02,0x06,0x0f,0x00,0x08,0x00,0x03,0x01,0x02,0x00] ] ] # | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | Tone_Com_Edit = [0x0b,0x0d,0x0d,0x0b,0x0d,0x0d,0x0b,0x0d, # | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 0x0f,0x0d,0x17,0x15,0x15,0x15,0x0e,0x14] Tone_Op_Edit = [ # 00:GrandPiano [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x01,0x0f,0x07,0x00,0x06,0x0f,0x27,0x00,0x01,0x08], # op2 [0x07,0x0e,0x03,0x02,0x03,0x02,0x28,0x00,0x05,0x00], # op3 [0x00,0x0d,0x01,0x01,0x04,0x03,0x22,0x01,0x01,0x00], # op4 [0x06,0x0d,0x02,0x02,0x06,0x04,0x00,0x01,0x01,0x00] ], # 01:E.Piano [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x54,0x0f,0x04,0x05,0x0c,0x0b,0x23,0x44,0x07,0x12], # op2 [0x02,0x0f,0x02,0x01,0x08,0x0f,0x04,0x45,0x01,0x00], # op3 [0x25,0x0f,0x00,0x01,0x0b,0x01,0x12,0x44,0x01,0x00], # op4 [0x04,0x0f,0x02,0x01,0x07,0x0f,0x04,0x41,0x01,0x00] ], # 02:TenorSax [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x36,0x07,0x03,0x00,0x00,0x00,0x05,0x44,0x01,0x01], # op2 [0x00,0x07,0x02,0x00,0x09,0x00,0x0f,0x43,0x01,0x08], # op3 [0x36,0x07,0x03,0x00,0x00,0x00,0x08,0x44,0x01,0x09], # op4 [0x02,0x07,0x02,0x00,0x09,0x00,0x0d,0x43,0x01,0x00] ], # 03:PickBass [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x56,0x0f,0x07,0x02,0x03,0x01,0x13,0x44,0x01,0x00], # op2 [0x04,0x0c,0x0b,0x04,0x06,0x07,0x15,0x44,0x07,0x00], # op3 [0x06,0x0f,0x09,0x02,0x06,0x02,0x17,0x44,0x02,0x00], # op4 [0x04,0x0b,0x02,0x06,0x08,0x06,0x00,0x44,0x01,0x00] ], # 04:TnklBell [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x31,0x0f,0x06,0x03,0x04,0x05,0x10,0x44,0x0e,0x00], # op2 [0x02,0x0c,0x06,0x07,0x06,0x0e,0x0b,0x44,0x02,0x00], # op3 [0x00,0x0c,0x06,0x02,0x02,0x05,0x1e,0x44,0x77,0x01], # op4 [0x00,0x0f,0x05,0x04,0x05,0x0d,0x01,0x54,0x06,0x00] ], # 05:NewAgePd [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x54,0x0f,0x0f,0x03,0x03,0x00,0x26,0x44,0x07,0x01], # op2 [0x02,0x0f,0x07,0x04,0x04,0x00,0x0b,0x44,0x05,0x00], # op3 [0x62,0x06,0x01,0x00,0x01,0x00,0x18,0x03,0x71,0x01], # op4 [0x02,0x08,0x01,0x00,0x05,0x01,0x00,0x03,0x01,0x00] ], # 06:BrightPiano [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x06,0x0f,0x02,0x02,0x02,0x05,0x27,0x00,0x01,0x00], # op2 [0x02,0x0f,0x02,0x02,0x03,0x0f,0x1c,0x00,0x05,0x00], # op3 [0x06,0x0f,0x02,0x02,0x02,0x0d,0x19,0x01,0x01,0x00], # op4 [0x04,0x0f,0x02,0x01,0x05,0x04,0x0a,0x01,0x01,0x00] ], # 07:Vibes [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x00,0x0c,0x04,0x02,0x04,0x02,0x17,0x41,0x07,0x00], # op2 [0x06,0x0d,0x09,0x02,0x05,0x06,0x07,0x51,0x04,0x00], # op3 [0x04,0x0c,0x04,0x02,0x03,0x02,0x1e,0x51,0x08,0x00], # op4 [0x00,0x0d,0x02,0x03,0x04,0x0f,0x07,0x31,0x01,0x00] ], # 08:ChurchOrgan [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x02,0x09,0x0f,0x00,0x05,0x00,0x13,0x00,0x03,0x00], # op2 [0x00,0x0b,0x07,0x00,0x02,0x02,0x1d,0x00,0x07,0x00], # op3 [0x02,0x08,0x0f,0x00,0x05,0x00,0x04,0x00,0x01,0x00], # op4 [0x02,0x08,0x07,0x00,0x05,0x00,0x04,0x00,0x00,0x05] ], # 09:Flute [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x70,0x0d,0x0a,0x00,0x01,0x01,0x07,0x10,0x03,0x00], # op2 [0x00,0x07,0x08,0x00,0x0b,0x03,0x25,0x01,0x03,0x00], # op3 [0x70,0x0e,0x08,0x00,0x09,0x00,0x27,0x31,0x01,0x00], # op4 [0x00,0x06,0x05,0x00,0x0a,0x00,0x01,0x11,0x01,0x10] ], # 10:RockOrgan [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x41,0x0f,0x0f,0x00,0x0d,0x00,0x09,0x70,0x31,0x00], # op2 [0x01,0x0b,0x0f,0x00,0x0a,0x01,0x05,0x50,0x01,0x15], # op3 [0x00,0x0f,0x0f,0x00,0x0e,0x00,0x09,0x13,0x62,0x00], # op4 [0x00,0x0f,0x0f,0x00,0x0e,0x00,0x09,0x33,0x70,0x11] ], # 11:NylonGuiter [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x65,0x0e,0x01,0x01,0x04,0x08,0x15,0x00,0x01,0x00], # op2 [0x00,0x0f,0x03,0x03,0x07,0x0f,0x00,0x01,0x01,0x00], # op3 [0x04,0x0b,0x05,0x05,0x05,0x04,0x0e,0x00,0x03,0x00], # op4 [0x02,0x0d,0x04,0x04,0x09,0x0f,0x0d,0x03,0x01,0x00] ], # 12:SquareLead [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x03,0x0f,0x0f,0x00,0x07,0x04,0x2e,0x00,0x01,0x08], # op2 [0x02,0x0a,0x0f,0x00,0x0a,0x00,0x03,0x03,0x01,0x08], # op3 [0x13,0x0f,0x0f,0x00,0x02,0x03,0x26,0x10,0x02,0x08], # op4 [0x02,0x0a,0x0f,0x00,0x0a,0x00,0x03,0x01,0x01,0x08] ], # 13:SawLead [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x70,0x0f,0x00,0x00,0x07,0x00,0x1a,0x41,0x71,0x00], # op2 [0x00,0x0d,0x0f,0x00,0x07,0x00,0x0a,0x41,0x71,0x08], # op3 [0x71,0x0f,0x0f,0x00,0x03,0x00,0x14,0x41,0x01,0x1c], # op4 [0x00,0x0e,0x0f,0x00,0x08,0x00,0x0a,0x41,0x01,0x08] ], # 14:Harpsichord [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x45,0x0e,0x02,0x02,0x05,0x00,0x00,0x00,0x01,0x04], # op2 [0x07,0x0f,0x02,0x00,0x05,0x03,0x14,0x00,0x06,0x03], # op3 [0x06,0x0f,0x03,0x00,0x01,0x06,0x1c,0x00,0x07,0x04], # op4 [0x04,0x0e,0x02,0x02,0x07,0x0f,0x04,0x03,0x01,0x05] ], # 15:Harmonica [ # KC | AR | DR | SR | RR | SL | TL | VB | PT | WS # op1 [0x03,0x0f,0x0f,0x00,0x09,0x00,0x2c,0x07,0x0e,0x00], # op2 [0x00,0x0f,0x0f,0x00,0x08,0x00,0x29,0x11,0x0a,0x00], # op3 [0x00,0x0f,0x0f,0x00,0x08,0x00,0x24,0x03,0x01,0x00], # op4 [0x02,0x06,0x0f,0x00,0x08,0x00,0x03,0x01,0x02,0x00] ] ] # Tone Data 20240516 Change tone_data = bytearray(485) # 20240518 Add send_tone = [] rcv_tone = [] UART_TONE_NUM = const(42) # 整数の送信データサイズ UART_BUFF_SIZE = const(100) # UART ASCII の送信データサイズ send_buff = bytearray(UART_BUFF_SIZE) # ASCII 2文字のバッファ rcv_buff = bytearray(UART_BUFF_SIZE) # ASCII 2文字のバッファ # 20240619 Add uartT_buff = '' # uart ASCII 2文字の送信バッファ uartR_buff = '' # uart ASCII 2文字の受信バッファ # VOICE COMMON PARAMETER ROW s Number COM = const(0) BO = const(1) LFO = const(2) ALG = const(3) VOICE_COM_COL_NUM = const(4) # VOICE COMMON PARAMETER COLUMON s Number CM0 = const(0) # Oparator Name CM1 = const(1) # Edit CM2 = const(2) # Orig CM3 = const(3) # Max VOICE_COM_ROW_NUM = const(4) # 20240326 Change # VOICE OPTIONAL PARAMETER ROW s Number OPT = const(0) SR = const(1) XOF = const(2) KSR = const(3) RR = const(4) DR = const(5) AR = const(6) SL = const(7) TL = const(8) KSL = const(9) DAM = const(10) EAM = const(11) DVB = const(12) EVB = const(13) MUL = const(14) DT = const(15) WS = const(16) FB = const(17) VOICE_OP_ROW_NUM = const(18) # VOICE OPTIONAL PARAMETER COLUMN s Number OP0 = const(0) # Oparator Name OP1 = const(1) # Edit 1 OP2 = const(2) # Edit 2 OP3 = const(3) # Edit 3 OP4 = const(4) # Edit 4 OP5 = const(5) # Orig 1 OP6 = const(6) # Orig 2 OP7 = const(7) # Orig 3 OP8 = const(8) # Orig 4 OP9 = const(9) # Max VOICE_OP_COL_NUM = const(10) # 編集用テーブルの生成 # Voice_Com_Edit テーブルの生成 Voice_Com_Edit = [None] * VOICE_COM_ROW_NUM # 4 for i in range(VOICE_COM_ROW_NUM): Voice_Com_Edit[i] = [None] * VOICE_COM_COL_NUM # 4 # VOICE COMMON PARAMETER TABLE ROW s NAME # Voice_Com_Edit[COM][CM0] = 'Common' Voice_Com_Edit[COM][CM1] = 'Edt' Voice_Com_Edit[COM][CM2] = 'Org' Voice_Com_Edit[COM][CM3] = 'Max' # VOICE COMMON PARAMETER ROW s NAME VoiceComName = [None] * VOICE_COM_ROW_NUM VoiceComName[COM] = 'Common' VoiceComName[BO] = 'BO' VoiceComName[LFO] = 'LFO' VoiceComName[ALG] = 'ALG' # VOICE COMMON PARAMETER TABLE COLUMN s NAME for i in range(VOICE_COM_ROW_NUM): # i : 0 - 3 Voice_Com_Edit[i][CM0] = VoiceComName[i] # Voice_Op_Edit テーブルの生成 Voice_Op_Edit = [None] * VOICE_OP_ROW_NUM # 18 for i in range(VOICE_OP_ROW_NUM): Voice_Op_Edit[i] = [None] * VOICE_OP_COL_NUM # 10 # VOICE OPARATOR PARAMETER TABLE ROW s NAME # Voice_Op_Edit[OPT][OP0] = 'Optional' Voice_Op_Edit[OPT][OP1] = 'e1' Voice_Op_Edit[OPT][OP2] = 'e2' Voice_Op_Edit[OPT][OP3] = 'e3' Voice_Op_Edit[OPT][OP4] = 'e4' Voice_Op_Edit[OPT][OP5] = 'o1' Voice_Op_Edit[OPT][OP6] = 'o2' Voice_Op_Edit[OPT][OP7] = 'o3' Voice_Op_Edit[OPT][OP8] = 'o4' Voice_Op_Edit[OPT][OP9] = 'Mx' # VOICE OPARATOR PARAMETER COLUMN s NAME VoiceOpName = [None] * VOICE_OP_ROW_NUM VoiceOpName[OPT] = 'Operator' VoiceOpName[SR] = 'SR' VoiceOpName[XOF] = 'XOF' VoiceOpName[KSR] = 'KSR' VoiceOpName[RR] = 'RR' VoiceOpName[DR] = 'DR' VoiceOpName[AR] = 'AR' VoiceOpName[SL] = 'SL' VoiceOpName[TL] = 'TL' VoiceOpName[KSL] = 'KSL' VoiceOpName[DAM] = 'DAM' VoiceOpName[EAM] = 'EAM' VoiceOpName[DVB] = 'DVB' VoiceOpName[EVB] = 'EVB' VoiceOpName[MUL] = 'MUL' VoiceOpName[DT] = 'DT' VoiceOpName[WS] = 'WS' VoiceOpName[FB] = 'FB' # VOICE OPTIONAL PARAMETER TABLE ROW s NAME for i in range(VOICE_OP_ROW_NUM): # i : 0 - 18 Voice_Op_Edit[i][OP0] = VoiceOpName[i] # Common BO, LFO, ALG の最大値 Voice_Com_Max = [3, 3, 7] # Common SR, XOF, KSR, RR, DR, AR, SL, TL, KSL, DAM, EAM, DVB, EVB, MUL, DT,WS, FB の最大値 Voice_Op_Max = [15, 1, 1, 15, 15, 15, 15, 63, 3, 3, 1, 3, 1, 15, 7, 31, 7] # Voice_Com_Edit TABLE s Max # VOICE COMMON PARAMETER TABLE s Max for i in range(1, VOICE_COM_ROW_NUM): # i : 1 - 3 Voice_Com_Edit[i][CM3] = Voice_Com_Max[i -1] # Voice_Op_Edit TABLE s Max # VOICE OPTIONAL PARAMETER TABLE s Max for i in range(1, VOICE_OP_ROW_NUM): # i : 1 - 17 Voice_Op_Edit[i][OP9] = Voice_Op_Max[i -1] # MIDI GM to YMF825 Tone Change # テーブル(辞書) # 2025/10/01 SyntaxError 発生 # 01:06, # 02:Bright Acostic Piano:06:Bright Piano では # Traceback (most recent call last): # File "<stdin>", line 670 # SyntaxError: invalid syntax for integer with base 0 # 余分な 0 があるとダメになったようだ。 # exGmYmf825 = {0:0, # ピアノ系 1:6, # 02:Bright Acostic Piano:06:Bright Piano 2:1, # 03:Electric Grand Piano:01:E.Piano 3:1, # 04:Honky-Tonk Piano:01:E.Piano 4:1, # 05:Electric Piano 1:01:E.Piano 5:1, # 06:Electric Piano 2:01:E.Piano 6:0, 7:0, # クロマチック・パーカッション系:04:TiklBell 8:4, 9:4, 10:4, 11:7, # 12:Vibraphone:ヴィヴラフォン:大型鉄琴:07:Vibes 12:4, 13:4, 14:4, 15:4, 16:4, 17:4, # オルガン系 18:10, 19:8, # 20:Church Organ:パイプ・オルガン:08:Church Organ 20:10, 21:15, # 22:Accordion:アコーディオン:15:Harmonica 22:10, 23:10, # ギター系 24:11, # 25:Acostic Guitar (nylon):11:NulonGuiter 25:11, 26:11, 27:11, 28:11, 29:11, 30:11, 31:11,\ # ベース系 32:3, # 33:Acosic Bass 通常のアコースティック:03:PickBass 33:3, # 34:Electric Bass (finger):03:PickBass 34:3, # 35:Electric Bass (pick):03:PickBass 35:3, 36:3, 37:3, 38:3, 39:3, # ストリングス系 40:12, # 41:Violin ヴァイオリン:12:SpuareLead 41:14, 42:14, 43:14, 44:14, 45:14, 46:14, # 47:Orchestral Harp:ハープ:14:Harrpsichord 47:14, # アンサンブル系 48:10, # 49:String Ensamble-1:ストリングス・アンサンブル:10:RockOrgan 49:10, # 50:String Ensamble 2:ストリンクス・アンサンブル:10:RockOrgan 50:5, # 51:Synth Strings 1:05:NewAgePd 51:5, # 52:Synth Strings 2:05:NewAgePd 52:5, 53:5, 54:5, 55:5, # ブラス系 56:0, 57:0, 58:0, 59:0, 60:0, 61:0, 62:0, 63:0, # リード系 64:2, 65:2, 66:2, 67:2, 68:2, 69:2, 70:2, 71:2, # 72:Clarinet:クラリネット:02:TenorSax # パイプ系 72:9, 73:9, # 74:Flute:フルート:09:Flute 74:13, # 75:Recorder:リコーダー:13:SawLead 75:13, 76:13, 77:13, 78:13, 79:13, # シンセ・リード系 80:0, 81:0, 82:0, 83:0, 84:0, 85:0, 86:0, 87:0, # シンセ・パッド系 88:0, 89:0, 90:0, 91:0, 92:0, 93:0, 94:0, 95:0, 96:0, # シンセ・エフェクト系 97:0, 98:0, 99:0,100:0,101:0,102:0,103:0, # エスニック系 104:0,105:0,106:0,107:0,108:0,109:0,110:0,111:0, # パーカッシヴ系 112:0,113:0,114:0,115:0,116:0,117:0,118:0,119:0, # 効果音 120:0,121:0,122:0,123:0,124:0,125:0,126:0,127:0} GmName = [None] * (128 +1) GmName[0] = 'MIDI GM Tone Name' # ピアノ系 GmName[1] = 'Acostic Grand Piano' GmName[2] = 'Bright Acostic Piano' GmName[3] = 'Electric Grand Piano' GmName[4] = 'Honky-Tonk Piano' GmName[5] = 'Electric Piano 1' GmName[6] = 'Electric Piano 2' GmName[7] = 'Harpsicord' GmName[8] = 'Clavi' # クロマチック・パーカッション系 GmName[9] = 'Celesta' GmName[10] = 'Glockenspiel' GmName[11] = 'Music Box' GmName[12] = 'Vibraphone' GmName[13] = 'Marimba' GmName[14] = 'Xylophone' GmName[15] = 'Tubular Bells' GmName[16] = 'Dulcimer' # オルガン系 GmName[17] = 'Drawber Organ' GmName[18] = 'Percussive Organ' GmName[19] = 'Rock Organ' GmName[20] = 'Church Organ' GmName[21] = 'Reed Organ' GmName[22] = 'Accordion' GmName[23] = 'Harmonica' GmName[24] = 'Tango Accordion' # ギター系 GmName[25] = 'Acostic Guitar (nylon)' GmName[26] = 'Acostic Guitar (steel)' GmName[27] = 'Electric Guitar (jazz)' GmName[28] = 'Electric Guitar (clean)' GmName[29] = 'Electric Guitar (muted)' GmName[30] = 'Overdriven Guitar' GmName[31] = 'Distortion Guitar' GmName[32] = 'Guitar Harmonics' # ベース系 GmName[33] = 'Acosic Bass' GmName[34] = 'Electric Bass (finger)' GmName[35] = 'Electric Bass (pick)' GmName[36] = 'Fretless Bass' GmName[37] = 'Slap Bass 1' GmName[38] = 'Slap Bass 2' GmName[39] = 'Synth Bass 1' GmName[40] = 'Synth Bass 2' # ストリングス系 GmName[41] = 'Violin' GmName[42] = 'Viola' GmName[43] = 'Cello' GmName[44] = 'Contrabass' GmName[45] = 'Tremoro Strings' GmName[46] = 'Pizzicato Strings' GmName[47] = 'Orchestral Harp' GmName[48] = 'Timpani' # アンサンブル系 GmName[49] = 'String Ensamble 1' GmName[50] = 'String Ensamble 2' GmName[51] = 'Synth Strings 1' GmName[52] = 'Synth Strings 2' GmName[53] = 'Choir Aahs' GmName[54] = 'Voice Oohs' GmName[55] = 'Synth Voice' GmName[56] = 'Orchestra Hit' # ブラス系 GmName[57] = 'Trumpet' GmName[58] = 'Trombone' GmName[59] = 'Tuba' GmName[60] = 'Muted Trumpet' GmName[61] = 'French Horn' GmName[62] = 'Brass Section' GmName[63] = 'Synth Brass 1' GmName[64] = 'Synth Brass 2' # リード系 GmName[65] = 'Soprano Sax' GmName[66] = 'Alto Sax' GmName[67] = 'Tenor Sax' GmName[68] = 'Baritone Sax' GmName[69] = 'Oboe' GmName[70] = 'English Horn' GmName[71] = 'Bassoon' GmName[72] = 'Clarinet' # パイプ系 GmName[73] = 'Piccolo' GmName[74] = 'Flute' GmName[75] = 'Recorder' GmName[76] = 'Pan Flute' GmName[77] = 'Bottle Blow' GmName[78] = 'Shakuhachi' GmName[79] = 'Whistle' GmName[80] = 'Ocarina' # シンセ・リード系 GmName[81] = 'Lead 1 (square)' GmName[82] = 'Lead 2 (sawtooth)' GmName[83] = 'Lead 3 (caliope)' GmName[84] = 'Lead 4 (chiff)' GmName[85] = 'Lead 5 (charang)' GmName[86] = 'Lead 6 (voice)' GmName[87] = 'Lead 7 (fifth)' GmName[88] = 'Lead 8 (bass+lead)' # シンセ・パッド系 GmName[89] = 'Pad 1 (new age)' GmName[90] = 'Pad 2 (warm)' GmName[91] = 'Pad 3 (polysynth)' GmName[92] = 'Pad 4 (choir)' GmName[93] = 'Pad 5 (bowed)' GmName[94] = 'Pad 6 (metalic)' GmName[95] = 'Pad 7 (halo)' GmName[96] = 'Pad 8 (sweep)' # シンセ・エフェクト系 GmName[97] = 'FX (rain)' GmName[98] = 'FX (soundtrack)' GmName[99] = 'FX (crystal)' GmName[100] = 'FX (atmosphere)' GmName[101] = 'FX (brightness)' GmName[102] = 'FX (goblins)' GmName[103] = 'FX (echoes)' GmName[104] = 'FX (sci-fi)' # エスニック系 GmName[105] = 'Sitar' GmName[106] = 'Banjo' GmName[107] = 'Shamisen' GmName[108] = 'Koto' GmName[109] = 'Kalimba' GmName[110] = 'Bagpipe' GmName[111] = 'Fiddle' GmName[112] = 'Shanai' # パーカッシヴ系 GmName[113] = 'Tinkle Bell' GmName[114] = 'Agogo' GmName[115] = 'Steel Drums' GmName[116] = 'Woodblock' GmName[117] = 'Taiko Drum' GmName[118] = 'Melodic Tom' GmName[119] = 'Synth Drum' GmName[120] = 'Reverse Cymbal' # 効果音 GmName[121] = 'Guitar Fret Noise' GmName[122] = 'Breath Noise' GmName[123] = 'Seashore' GmName[124] = 'Bird Tweet' GmName[125] = 'Telephone Ring' GmName[126] = 'Helicopter' GmName[127] = 'Applause' GmName[128] = 'Gun Shot' # YMF825 # key name KEY_C = const(0) KEY_C_SHARP = const(1) KEY_D = const(2) KEY_D_SHARP = const(3) KEY_E = const(4) KEY_F = const(5) KEY_F_SHARP = const(6) KEY_G = const(7) KEY_G_SHARP = const(8) KEY_A = const(9) KEY_A_SHARP = const(10) KEY_B = const(11) # I/O voltage IOVDD_5V = const(0) IOVDD_3V3 = const(1) # number of channels CH_MAX = const(16) # FNUM table # C C# D D# E F F# G G# A A# B FNUM = [357, 378, 401, 425, 450, 477, 505, 535, 567, 601, 637, 674] FNUM_MAX = 12 # FNUM table (high byte) calcurated in SimpleYMF825::begin() uint8_t FNUMH[12]; FNUMH = [None] * FNUM_MAX # FNUM table (low byte) calcurated in SimpleYMF825::begin() uint8_t FNUML[12]; # uint8_t FNUML[12]; FNUML = [None] * FNUM_MAX # init_fnum() で FNUMH FNUML を定義する for i in range(FNUM_MAX): FNUMH[i] = (FNUM[i] & 0x0380) >> 4 FNUML[i] = (FNUM[i] & 0x007F) # PicoMain では、使用しない ・・・ ここから # SPI SPI_CH = const(0) SPI_MAX_SPEED_HZ = const(1000000) #GPIO assignment # Pin No. SPIPORT_MOSI = const(19) # pin25 SPIPORT_MISO = const(16) # pin21 SPIPORT_CLK = const(18) # pin24 SPIPORT_CE = const(17) # pin22 YMF825_RESET = const(22) # pin29 GPIO_LED = const(28) # pin34 # N/A # SPI0 YMF825 spi_cs = Pin(SPIPORT_CE, Pin.OUT) spi0 = SPI(SPI_CH, sck=Pin(SPIPORT_CLK), mosi=Pin(SPIPORT_MOSI), miso=Pin(SPIPORT_MISO), baudrate=SPI_MAX_SPEED_HZ, firstbit=SPI.MSB, polarity=0, phase=0) print('spi0 YMF825 in YMF825py = ', spi0) print() # YMF825 RESET pin YMF825_reset = Pin(YMF825_RESET, Pin.OUT) # LED (CURRENTLY NOT AVAILABLE) led_indicator = Pin(GPIO_LED, Pin.OUT) # PicoMain では、使用しない ・・・ ここまで # 20240501 Add # UASRT 設定 UART_BAUD = 115200 # 20240517 Change # uart = UART(1, UART_BAUD, bits=8, parity=None, stop=1, tx=Pin(4), rx=Pin(5)) # # uart = UART(1, UART_BAUD, bits=8, parity=None, stop=1, tx=Pin(4), rx=Pin(5), \ # timeout=500, timeout_char=500) # # 20240810 Change uart = UART(1, UART_BAUD, bits=8, parity=None, stop=1, tx=Pin(4), rx=Pin(5), \ timeout=50, timeout_char=50) #LED indicator # onoff:: True:turn on, False: turn off def led_turn(onoff): led_indicator.value(1 if onoff else 0) #Wait timer # msec:: Waite time in milli-seconds def delay(msec): time.sleep(msec/1000) #Set SPI Slave Select Pin (CE0) # PicoMain では、使用しない。 # pinv:: GPIO.HIGH: not-select, GPIO.LOW: select def chip_select(sel): spi_cs.value(0 if sel else 1) ################################################################# # 20240316 Add & Change in use # PicoMain では、使用しない。 # SPI write (multi bytes) def spi_write_multi(addr, multi_data): data_array = bytearray([addr]) data_array += multi_data chip_select(True) spi0.write(data_array) chip_select(False) # 20240316 Add in use # PicoMain では、使用しない。 # SPI write (single byte) def spi_write_single(addr, single_data): data_array = bytearray([addr, single_data]) chip_select(True) spi0.write(data_array) chip_select(False) ################################################################# #Set Chanel # PicoMain では、使用しない。 def set_chanel(): spi_write_single(0x0F,0x30) spi_write_single(0x10,0x71) spi_write_single(0x11,0x00) spi_write_single(0x12,0x08) spi_write_single(0x13,0x00) # 20240314 ADD in use # Set Mater Volume # vol: volume (0...63) # 1...63; -50dB... +12dB def set_MasterVolume(vol): spi_write_single(25,vol << 2) # 20240315 Add in use # PicoMain では、使用しない。 # ch:0-15 octave: vol: def keyon4(ch, octave, key, vol): global FNUMH global FNUML # global sund_param spi_write_single(11,ch & 0x0F) spi_write_single(12,vol & 0x7F) spi_write_single(13,FNUMH[key] | (octave - 1)) spi_write_single(14,FNUML[key]) spi_write_single(15,0x40 | 0) # Last 0:tone led_turn(True) # 20240315 Add in use # PicoMain では、使用しない。 # ch:0-15 octave: vol: def keyon5(ch, octave, key, vol, tone): global FNUMH global FNUML # global sund_param spi_write_single(11,ch & 0x0F) spi_write_single(12,vol & 0x7F) spi_write_single(13,FNUMH[key] | (octave - 1)) spi_write_single(14,FNUML[key]) spi_write_single(15,0x40 | tone & 0x0F) led_turn(True) # 20240315 Add in use # PicoMain では、使用しない。 def keyoff(ch): spi_write_single(11, ch & 0x0F) spi_write_single(0x0F, 0) led_turn(False) # 20240622 Add in use # PicoMain では、使用しない。 # tone は、ToneTableを参照し、16以上ならば何もしない def note_on(ch, octave, key, vol): global FNUMH global FNUML global Tonetable # ToneTable の値が 16未満なら if ToneTable[(ch & 0x0F) +1][1] <16: spi_write_single(11,ch & 0x0F) spi_write_single(12,vol & 0x7F) spi_write_single(13,FNUMH[key] | (octave - 1)) spi_write_single(14,FNUML[key]) spi_write_single(15,0x40 | ToneTable[(ch & 0x0F) +1][1]) led_turn(True) # 20240705 Add in use # PicoMain では、使用しない。 # tone は、1つを指定する。 def note_onMonoTone(ch, octave, key, vol, tone): global FNUMH global FNUML global Tonetable # ToneTable の値が 16未満なら if ToneTable[(ch & 0x0F) +1][1] <16: spi_write_single(11,ch & 0x0F) spi_write_single(12,vol & 0x7F) spi_write_single(13,FNUMH[key] | (octave - 1)) spi_write_single(14,FNUML[key]) spi_write_single(15,0x40 | tone & 0x0F) led_turn(True) # 20240622 Add in use # PicoMain では、使用しない。 def note_off(ch): spi_write_single(11, ch & 0x0F) spi_write_single(0x0F, 0) led_turn(False) ################################################################# # 20240501 Add def uart_write_multi(multi_data): uart.write(multi_data) # 20240618 Add def uart_read_multi(): global rcv_buff rcv_size = uart.readinto(rcv_buff) return rcv_size # 20240701 Add def uart_blank_read(): while uart.any() > 0: try: data_rx = uart.read(1) except UnicodeError: print('uart_blank_read() UnicodeError') except: print('uart_blank_read() Error') ################################################################# # 20240518 Add def uartOutToneData(): global send_buff print("Write tone data out to UART") uart_write_multi(send_buff) # 20240619 Add def uartOutToneTable(): global uartT_buff print("Write Tone Table out to UART") uart_write_multi(uartT_buff) # 20240518 Add # 20240619 Change ==> headerID が、0:ToneData、1:ToneTable、両方に対応 def uartInTone(): global rcv_buff # ASCII 2文字リスト global rcv_tone # 整数リスト print("Read tone data in from UART") rcv_size = uart_read_multi() if rcv_size == None: # 受信データなし print() print('rcv_size = None') # rcv_size, headerID, tone_name return None, None, None else: # 受信データあり # DEBUG print print('rcv_size = ', rcv_size) # print(rcv_buff) headerID = chr(rcv_buff[0]) if headerID == '0': tone_name = rcv_buff[1:TONE_HEADER].decode('utf-8') # tone_name print('Recive Data = ', tone_name) # 2文字の ASCIIコード(0-9 A-F)を1byteの整数に変換する。 rcv_tone = [] for i in range(UART_TONE_NUM): # 42 rcv_tone.append(moji.asc2int(chr(rcv_buff[TONE_HEADER + i *2]) \ + chr(rcv_buff[TONE_HEADER + i *2 +1]))) # DEBUG print print('rcv_tone = ', rcv_tone) return rcv_size, headerID, tone_name elif headerID == '1': tone_name = rcv_buff[1:TONE_HEADER].decode('utf-8') # 'Tone Table' print('Recive Data = ', tone_name) # 2文字の ASCIIコード(0-9 A-F)を1byteの整数に変換する。 rcv_tone = [] for i in range(TONE_TABLE_ROW_NUM -1): # 0-15 : 16 rcv_tone.append(moji.asc2int(chr(rcv_buff[TONE_HEADER + i *2]) \ + chr(rcv_buff[TONE_HEADER + i *2 +1]))) # DEBUG print print('ToneTable = ', rcv_tone) return rcv_size, headerID, tone_name elif headerID == '%': # PrintDFP command print('rcv_buff = ', rcv_buff) PrintDFPcommand = rcv_buff[:rcv_size] # DEBUG print print('PrintDFPcommand = ', PrintDFPcommand) # return rcv_size, headerID, tone_name return rcv_size, headerID, PrintDFPcommand ################################################################# # 20240518 Add # tone_num で指定された Tone\Com_edit および Tone_Op_Edit の情報を # UART送信で使用する ASCIIコードの2文字に変換する。 def takeOutToneData(num): tone_num = num & 0x0F # 念の為 0-15 に限定 global send_tone global send_buff global Tone_Com_Edit global Tone_Op_Edit send_buff[0] = ord('0') # [0]:ZERO:ToneID # ToneName send_buff[1:TONE_HEADER] = bytes(moji.strFixL_n(ToneName[tone_num], TONE_HEADER -1), 'utf8') send_tone = [] # 整数 send_tone.append(tone_num) send_tone.append(Tone_Com_Edit[tone_num]) for i in range(FM_OP_NUM): # 4 for j in range(OP_PARAM_NUM): # 10 send_tone.append(Tone_Op_Edit[tone_num][i][j]) # DEBUG print # print('send ToneData = ', send_tone) # 1byte の整数を ASCIIコード(0-9 A-F)の2文字に変換する。 for i in range(UART_TONE_NUM): # 42 (asc_H, asc_L) = moji.int2asc2(send_tone[i]) send_buff[TONE_HEADER + i *2] = ord(asc_H) send_buff[TONE_HEADER + i *2 +1] = ord(asc_L) ################################################################# # 20251004 Add 20251014:edit_num, save_num に分ける理由は何だったか? # editTN で指定された Tone_Com_edit および Tone_Op_Edit の情報を # UART送信で使用する ASCIIコードの2文字に変換する。 # トーン番号を saveTN にする。 def takeOutToneData2(edit_num, save_num): edit_num = edit_num & 0x0F # 念の為 0-15 に限定 save_num = save_num & 0x0F global send_tone global send_buff global Tone_Com_Edit global Tone_Op_Edit send_buff[0] = ord('0') # [0]:ZERO:ToneID # ToneName send_buff[1:TONE_HEADER] = bytes(moji.strFixL_n(ToneName[edit_num], TONE_HEADER -1), 'utf8') send_tone = [] # 整数 send_tone.append(save_num) # 20251004 Change edit_num ---> save_num send_tone.append(Tone_Com_Edit[edit_num]) for i in range(FM_OP_NUM): # 4 for j in range(OP_PARAM_NUM): # 10 send_tone.append(Tone_Op_Edit[edit_num][i][j]) # DEBUG print # print('send ToneData = ', send_tone) # 1byte の整数を ASCIIコード(0-9 A-F)の2文字に変換する。 for i in range(UART_TONE_NUM): # 42 (asc_H, asc_L) = moji.int2asc2(send_tone[i]) send_buff[TONE_HEADER + i *2] = ord(asc_H) send_buff[TONE_HEADER + i *2 +1] = ord(asc_L) ################################################################# # 20240619 Add # Tone Table の情報を UART送信で使用する ASCIIコードの2文字に変換する。 def takeOutToneTable(): global ToneTable global send_tone global send_buff global uartT_buff send_buff[0] = ord('1') # [1]:ONE:Tone Table # Tone Table send_buff[1:TONE_HEADER] = bytes(moji.strFixL_n('Tone Table', TONE_HEADER -1), 'utf8') # ToneTable の中身だけ抽出 ・・・ ch 0-15 に対応する ToneNo 0-16 16:NoTone send_tone = [] # 整数リスト for i in range(1, TONE_TABLE_ROW_NUM): # 1-17 : 16 send_tone.append(ToneTable[i][1]) # DEBUG print # print('send ToneTable = ', send_tone) # 1byte の整数を ASCIIコード(0-9 A-F)の2文字に変換する。 for i in range(TONE_TABLE_ROW_NUM -1): # 0-15 : 16 (asc_H, asc_L) = moji.int2asc2(send_tone[i]) send_buff[TONE_HEADER + i *2] = ord(asc_H) send_buff[TONE_HEADER + i *2 +1] = ord(asc_L) # TONE_HEADER + (TONE_TABLE_ROW_NUM) *2) = 48 bytes uartT_buff = send_buff[:(TONE_HEADER + (TONE_TABLE_ROW_NUM -1) *2)] ################################################################# # 20240518 Add # 受信した rcv_tone のデータを tone_num で指定された番号の # Tone_Com_edit および Tone_Op_Edit に格納する。 def takeInToneData(): global rcv_tone # 整数リスト global Tone_Com_Edit global Tone_Op_Edit if len(rcv_tone) > 0: tone_num = rcv_tone[0] & 0x0F # 念の為、0-15 に限定 Tone_Com_Edit[tone_num] = rcv_tone[1] # rcv_tone は、2文字の ASCIIコード(0-9 A-F)から1byteの整数に変換したリスト # rcv_tone データを Tone_Op_Edit に格納 for i in range(FM_OP_NUM): # 4 for j in range(OP_PARAM_NUM): # 10 Tone_Op_Edit[tone_num][i][j] = rcv_tone[2 + i *OP_PARAM_NUM + j] else: tone_num = None return tone_num ################################################################# # 20240620 Add # 受信した rcv_tone のデータを ToneTable に格納する。 def takeInToneTable(): global rcv_tone # 整数リスト global ToneTable if len(rcv_tone) > 0: if len(rcv_tone) == (TONE_TABLE_ROW_NUM -1): # 16 # rcv_tone は、2文字の ASCIIコード(0-9 A-F)から1byteの整数に変換したリスト # rcv_tone データを ToneTable に格納 for i in range(1, TONE_TABLE_ROW_NUM): # 1-17 : 16 ToneTable[i][1] = rcv_tone[i -1] # rcv_tone[i] 0-16 print('ToneTable =', ToneTable) else: print('rcv_tone size is not 16') print('ToneTable size is 16') else: print('rcv_tone is None') ################################################################# # 20240318 Add in use # YMF825 に tone_dataを設定する # PicoMain では、使用しない。 def init_tone(): global tone_data global Tone_Com_Edit global Tone_Op_Edit global ToneName # tone parameter data size COMMON_PARAM_SIZE = 2 OP_PARAM_SIZE = 7 TONE_PARAM_SIZE = COMMON_PARAM_SIZE + FM_OP_NUM * OP_PARAM_SIZE; MESSAGE_SIZE = TONE_PARAM_SIZE * TONE_NUM + 1 + 4 # 485 # print() # print("YMF825 Tone Parameter Setting Data") # header tone_data[0] = 0x80 + TONE_NUM # print(f"Header = {tone_data[0]:4}") # register data for i in range(TONE_NUM): # print() # print(f'Voice Number = {i} : {ToneName[i]}') # common parameter 1 tone_data[i* TONE_PARAM_SIZE +1] = (Tone_Com_Edit[i] & 0x60) >> 5 # print(f"common parameter 1 = {tone_data[i* TONE_PARAM_SIZE +1]:4}") # common parameter 2 tone_data[i* TONE_PARAM_SIZE +2] = ((Tone_Com_Edit[i] & 0x18) << 3) | (Tone_Com_Edit[i] & 0x07) # print(f"common parameter 2 = {tone_data[i* TONE_PARAM_SIZE +2]:4}") # operator parameter 7 x 4 for j in range(FM_OP_NUM): # print(f"operator parameter [{j}] = ", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +3] = \ (Tone_Op_Edit[i][j][3] << 4) | \ (Tone_Op_Edit[i][j][0] & 0x08) | \ ((Tone_Op_Edit[i][j][0] & 0x04) >> 2) # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +3]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +4] = \ (Tone_Op_Edit[i][j][4] << 4) | Tone_Op_Edit[i][j][2] # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +4]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +5] = \ (Tone_Op_Edit[i][j][1] << 4) | Tone_Op_Edit[i][j][5] # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +5]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +6] = \ (Tone_Op_Edit[i][j][6] << 2) | (Tone_Op_Edit[i][j][0] & 0x03) # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +6]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +7] = \ Tone_Op_Edit[i][j][7] # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +7]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +8] = \ ((Tone_Op_Edit[i][j][8] & 0x0f) << 4) | \ ((Tone_Op_Edit[i][j][8] & 0xf0) >> 4) # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +8]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +9] = \ (Tone_Op_Edit[i][j][9] << 3) | \ ((Tone_Op_Edit[i][j][0] & 0x70) >> 4) # print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +9]:4}") # footer tone_data[TONE_PARAM_SIZE * TONE_NUM +0] = 0x80 # print(f"footer 1 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +0]}") tone_data[TONE_PARAM_SIZE * TONE_NUM +1] = 0x03 # print(f"footer 2 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +1]}") tone_data[TONE_PARAM_SIZE * TONE_NUM +2] = 0x81 # print(f"footer 3 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +2]}") tone_data[TONE_PARAM_SIZE * TONE_NUM +3] = 0x80 # print(f"footer 4 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +3]}") #Burst write mode # print("YMF85 Burst write mode.") spi_write_single(0x08, 0xF6) # delay(20) delay(10) # Before 1000 spi_write_single(0x08, 0x00) #Write tone data to YMF825 FIFO print("Write tone data to YMF825.") spi_write_multi(0x07, tone_data) def copyTone2_Voice(num): tone_num = num & 0x0F global Tone_Com_Orig global Tone_Op_Orig global Tone_Com_Edit global Tone_Op_Edit global Voice_Com_Edit global Voice_Op_Edit # common parameter Voice_Com_Edit[BO][CM2] = (Tone_Com_Orig[tone_num] & 0x60) >> 5 Voice_Com_Edit[LFO][CM2] = (Tone_Com_Orig[tone_num] & 0x18) >> 3 Voice_Com_Edit[ALG][CM2] = Tone_Com_Orig[tone_num] & 0x07; Voice_Com_Edit[BO][CM1] = (Tone_Com_Edit[tone_num] & 0x60) >> 5 Voice_Com_Edit[LFO][CM1] = (Tone_Com_Edit[tone_num] & 0x18) >> 3 Voice_Com_Edit[ALG][CM1] = Tone_Com_Edit[tone_num] & 0x07 # operator s parameter for j in range(FM_OP_NUM): # j : 0 - 3 Voice_Op_Edit[SR][j +5] = (Tone_Op_Orig[tone_num][j][3] & 0x0F) Voice_Op_Edit[SR][j +1] = (Tone_Op_Edit[tone_num][j][3] & 0x0F) Voice_Op_Edit[XOF][j +5] = ((Tone_Op_Orig[tone_num][j][0] & 0x08) >> 3) Voice_Op_Edit[XOF][j +1] = ((Tone_Op_Edit[tone_num][j][0] & 0x08) >> 3) Voice_Op_Edit[KSR][j +5] = ((Tone_Op_Orig[tone_num][j][0] & 0x04) >> 2) Voice_Op_Edit[KSR][j +1] = ((Tone_Op_Edit[tone_num][j][0] & 0x04) >> 2) Voice_Op_Edit[RR][j +5] = (Tone_Op_Orig[tone_num][j][4] & 0x0F) Voice_Op_Edit[RR][j +1] = (Tone_Op_Edit[tone_num][j][4] & 0x0F) Voice_Op_Edit[DR][j +5] = (Tone_Op_Orig[tone_num][j][2] & 0x0f) Voice_Op_Edit[DR][j +1] = (Tone_Op_Edit[tone_num][j][2] & 0x0f) Voice_Op_Edit[AR][j +5] = (Tone_Op_Orig[tone_num][j][1] & 0x0F) Voice_Op_Edit[AR][j +1] = (Tone_Op_Edit[tone_num][j][1] & 0x0F) Voice_Op_Edit[SL][j +5] = (Tone_Op_Orig[tone_num][j][5] & 0x0F) Voice_Op_Edit[SL][j +1] = (Tone_Op_Edit[tone_num][j][5] & 0x0F) Voice_Op_Edit[TL][j +5] = (Tone_Op_Orig[tone_num][j][6] & 0x3F) Voice_Op_Edit[TL][j +1] = (Tone_Op_Edit[tone_num][j][6] & 0x3F) Voice_Op_Edit[KSL][j +5] = (Tone_Op_Orig[tone_num][j][0] & 0x03) Voice_Op_Edit[KSL][j +1] = (Tone_Op_Edit[tone_num][j][0] & 0x03) Voice_Op_Edit[DAM][j +5] = ((Tone_Op_Orig[tone_num][j][7] & 0x60) >> 5) Voice_Op_Edit[DAM][j +1] = ((Tone_Op_Edit[tone_num][j][7] & 0x60) >> 5) Voice_Op_Edit[EAM][j +5] = ((Tone_Op_Orig[tone_num][j][7] & 0x10) >> 4) Voice_Op_Edit[EAM][j +1] = ((Tone_Op_Edit[tone_num][j][7] & 0x10) >> 4) Voice_Op_Edit[DVB][j +5] = ((Tone_Op_Orig[tone_num][j][7] & 0x06) >> 1) Voice_Op_Edit[DVB][j +1] = ((Tone_Op_Edit[tone_num][j][7] & 0x06) >> 1) Voice_Op_Edit[EVB][j +5] = (Tone_Op_Orig[tone_num][j][7] & 0x01) Voice_Op_Edit[EVB][j +1] = (Tone_Op_Edit[tone_num][j][7] & 0x01) Voice_Op_Edit[MUL][j +5] = (Tone_Op_Orig[tone_num][j][8] & 0x0f) Voice_Op_Edit[MUL][j +1] = (Tone_Op_Edit[tone_num][j][8] & 0x0f) Voice_Op_Edit[DT][j +5] = ((Tone_Op_Orig[tone_num][j][8] & 0xf0) >> 4) Voice_Op_Edit[DT][j +1] = ((Tone_Op_Edit[tone_num][j][8] & 0xf0) >> 4) Voice_Op_Edit[WS][j +5] = (Tone_Op_Orig[tone_num][j][9] & 0x1F) Voice_Op_Edit[WS][j +1] = (Tone_Op_Edit[tone_num][j][9] & 0x1F) Voice_Op_Edit[FB][j +5] = ((Tone_Op_Orig[tone_num][j][0] & 0x70) >> 4) Voice_Op_Edit[FB][j +1] = ((Tone_Op_Edit[tone_num][j][0] & 0x70) >> 4) def copyVoice2_Tone(num): tone_num = num & 0x0F global Tone_Com_Edit global Tone_Op_Edit global Voice_Com_Edit global Voice_Op_Edit Tone_Com_Edit[tone_num] = ((Voice_Com_Edit[BO][CM1] << 5) | \ (Voice_Com_Edit[LFO][CM1] << 3) | \ Voice_Com_Edit[ALG][CM1]) # operator s parameter for j in range(FM_OP_NUM): # j : 0 - 3 Tone_Op_Edit[tone_num][j][0] = ((Voice_Op_Edit[FB][j +1] << 4) | \ (Voice_Op_Edit[XOF][j +1] << 3) | \ (Voice_Op_Edit[KSR][j +1] << 2) | \ (Voice_Op_Edit[KSL][j +1])) Tone_Op_Edit[tone_num][j][1] = Voice_Op_Edit[AR][j +1] Tone_Op_Edit[tone_num][j][2] = Voice_Op_Edit[DR][j +1] Tone_Op_Edit[tone_num][j][3] = Voice_Op_Edit[SR][j +1] Tone_Op_Edit[tone_num][j][4] = Voice_Op_Edit[RR][j +1] Tone_Op_Edit[tone_num][j][5] = Voice_Op_Edit[SL][j +1] Tone_Op_Edit[tone_num][j][6] = Voice_Op_Edit[TL][j +1] Tone_Op_Edit[tone_num][j][7] = ((Voice_Op_Edit[DAM][j +1] << 5) | \ (Voice_Op_Edit[EAM][j +1] << 4) | \ (Voice_Op_Edit[DVB][j +1] << 1) | \ (Voice_Op_Edit[EVB][j +1])) Tone_Op_Edit[tone_num][j][8] = ((Voice_Op_Edit[DT][j +1] << 4) | \ (Voice_Op_Edit[MUL][j +1])) Tone_Op_Edit[tone_num][j][9] = Voice_Op_Edit[WS][j +1] def serialOutVoiceData(num): tone_num = num & 0x0F global Voice_Com_Edit global Voice_Op_Edit print() print(f'Voice Number = {tone_num} : {ToneName[tone_num]}') # Voice Edit Common Parameter print(f'{Voice_Com_Edit[COM][CM0]:10}:', end = '') # Header for j in range(1, VOICE_COM_COL_NUM): print(f'{Voice_Com_Edit[COM][j]:> 5}|', end = '') print() # Body for i in range(1, VOICE_COM_ROW_NUM): # print(f'|{moji.strFixL_n(Voice_Com_Edit[i][CM0], 5)} ', ' :', end = '') print(f'{Voice_Com_Edit[i][CM0]:10}:', end = '') print(f'{Voice_Com_Edit[i][CM1]: 5}|', end = '') print(f'{Voice_Com_Edit[i][CM2]: 5}|', end = '') print(f'{Voice_Com_Edit[i][CM3]: 5}|') print() # Vice Edit Oparetor Parameter print(f'{Voice_Op_Edit[OPT][OP0]:10}:', end = '') # Header for j in range(1, VOICE_OP_COL_NUM): print(f'{Voice_Op_Edit[OPT][j]:> 3}|', end = '') print() # Body for i in range(1, VOICE_OP_ROW_NUM): # print(f'|{moji.strFixL_n(Voice_Com_Edit[i][CM0], 5)} ', ' :', end = '') print(f'{Voice_Op_Edit[i][OP0]:10}:', end = '') print(f'{Voice_Op_Edit[i][OP1]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP2]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP3]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP4]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP5]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP6]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP7]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP8]: 3}|', end = '') print(f'{Voice_Op_Edit[i][OP9]: 3}|') print() def serialOutToneData(num): tone_num = num & 0x0F global tone_data global Tone_Com_Edit global Tone_Op_Edit global ToneName # tone parameter data size COMMON_PARAM_SIZE = 2 OP_PARAM_SIZE = 7 TONE_PARAM_SIZE = COMMON_PARAM_SIZE + FM_OP_NUM * OP_PARAM_SIZE; MESSAGE_SIZE = TONE_PARAM_SIZE * TONE_NUM + 1 + 4 # 485 print() print("YMF825 Tone Parameter Setting Data") print(f'Voice Number = {tone_num} : {ToneName[tone_num]}') tone_data[tone_num * TONE_PARAM_SIZE +1] = (Tone_Com_Edit[i] & 0x60) >> 5 print(f"common parameter 1 = {tone_data[tone_num * TONE_PARAM_SIZE +1]:4}") # common parameter 2 tone_data[tone_num * TONE_PARAM_SIZE +2] = ((Tone_Com_Edit[i] & 0x18) << 3) | (Tone_Com_Edit[i] & 0x07) print(f"common parameter 2 = {tone_data[tone_num * TONE_PARAM_SIZE +2]:4}") # operator parameter 7 x 4 for j in range(FM_OP_NUM): print(f"operator parameter [{j}] = ", end = "") tone_data[tone_num * TONE_PARAM_SIZE + j* OP_PARAM_SIZE +3] = \ (Tone_Op_Edit[i][j][3] << 4) | \ (Tone_Op_Edit[i][j][0] & 0x08) | \ ((Tone_Op_Edit[i][j][0] & 0x04) >> 2) print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +3]:4},", end = "") tone_data[tone_num * TONE_PARAM_SIZE + j* OP_PARAM_SIZE +4] = \ (Tone_Op_Edit[i][j][4] << 4) | Tone_Op_Edit[i][j][2] print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +4]:4},", end = "") tone_data[tone_num * TONE_PARAM_SIZE + j* OP_PARAM_SIZE +5] = \ (Tone_Op_Edit[i][j][1] << 4) | Tone_Op_Edit[i][j][5] print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +5]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +6] = \ (Tone_Op_Edit[i][j][6] << 2) | (Tone_Op_Edit[i][j][0] & 0x03) print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +6]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +7] = \ Tone_Op_Edit[i][j][7] print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +7]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +8] = \ ((Tone_Op_Edit[i][j][8] & 0x0f) << 4) | \ ((Tone_Op_Edit[i][j][8] & 0xf0) >> 4) print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +8]:4},", end = "") tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +9] = \ (Tone_Op_Edit[i][j][9] << 3) | \ ((Tone_Op_Edit[i][j][0] & 0x70) >> 4) print(f"{tone_data[i* TONE_PARAM_SIZE + j* OP_PARAM_SIZE +9]:4}") # footer tone_data[TONE_PARAM_SIZE * TONE_NUM +0] = 0x80 print(f"footer 1 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +0]}") tone_data[TONE_PARAM_SIZE * TONE_NUM +1] = 0x03 print(f"footer 2 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +1]}") tone_data[TONE_PARAM_SIZE * TONE_NUM +2] = 0x81 print(f"footer 3 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +2]}") tone_data[TONE_PARAM_SIZE * TONE_NUM +3] = 0x80 print(f"footer 4 = {tone_data[TONE_PARAM_SIZE * TONE_NUM +3]}") #Reset and Initialize YMF825 # PicoMain では、使用しない。 def init_YMF825(): YMF825_reset.low() # print("RESET LOW") # C-out delay(100) # Before 1000 YMF825_reset.high() delay(100) # Before 1000 # print("Reset YMF825.") # C-out spi_write_single(0x1D,0x00) spi_write_single(0x02,0x0E) delay(20) spi_write_single(0x00,0x01) spi_write_single(0x01,0x00) spi_write_single(0x1A,0xA3) delay(20) spi_write_single(0x1A,0x00) delay(40) spi_write_single(0x02,0x04) delay(20) spi_write_single(0x02,0x00) # add spi_write_single(0x19,0xFF) spi_write_single(0x1B,0x3F) spi_write_single(0x14,0x00) spi_write_single(0x03,0x01) spi_write_single(0x08,0xF6) delay(40) spi_write_single(0x08,0x00) spi_write_single(0x09,0xF8) spi_write_single(0x0A,0x00) spi_write_single(0x17,0x40) spi_write_single(0x18,0x00) print("YMF825 initialized.") # YMF825 Set up hardware # PicoMain では、使用しない。 def setup(): led_turn(True) chip_select(False) print("Set up YMF825") init_YMF825() set_chanel() print("Finished setting up.") led_turn(False) ``` ### mojipy.py ```MicroPython:mojipy.py ############################################################################# # mojipy.py # 2024/04/15:文字処理をライブラリ化:Programd by Hyodo # Thonny で Pico直下にコピーしておき # import mojipy as moji として利用する #---------------------------------------------------------------------------- # 整数を 16進数表記のASCII文字(0~9 A~F)2文字に変換する。 # 整数を 10進数表記のASCII文字に変換するには str(num) でよい。 def int2asc2(num): num_H = int(num / 16) num_L = num % 16 if num_H > 9: num_H = num_H - 9 asc_H = chr(0x40 + num_H) else: asc_H = chr(0x30 + num_H) if num_L > 9: num_L = num_L - 9 asc_L = chr(0x40 + num_L) else: asc_L = chr(0x30 + num_L) return asc_H, asc_L #---------------------------------------------------------------------------- # 2バイト以上の16進数表記のASCIIコード(0~9、A~F a~f)を整数に変換する。 # 10進数表記のASCIIコードを整数に変換するには int(s) でよい。 # int2asc2(num)関数の逆操作 def asc2int(s): l = len(s) data_int = 0 # rcv_data は、s の i 番目の要素を示す 「Python入門」p140 参照 for i, rcv_data in enumerate(s): # print("rcv_data[{}] = {} ".format(i, ord(rcv_data))) data_ascii = ord(rcv_data) # print("rcv_ascii[{}] = {} ".format(i, data_ascii), end="") if data_ascii >= 48 and data_ascii <= 57: data_int += (data_ascii - 48) * 16 ** (l - i - 1) elif data_ascii >= 65 and data_ascii <= 70: data_int += ((data_ascii - 65) + 10) * 16 ** (l - i - 1) elif data_ascii >= 97 and data_ascii <= 102: data_int += ((data_ascii - 97) + 10) * 16 ** (l - i - 1) return data_int #---------------------------------------------------------------------------- # 1バイトデータを4ビットx2に分け、0~9 A~F 2文字(2バイト)に変換する。 # chr2dec(s)関数(16進表記の文字列を 0x00 〜 0xFF の数値に変換)の逆操作 def byte2chr2(num): num_H = int(ord(num) / 16) num_L = ord(num) % 16 if num_H > 9: num_H = num_H - 9 str_H = chr(0x40 + num_H) else: str_H = chr(0x30 + num_H) if num_L > 9: num_L = num_L - 9 str_L = chr(0x40 + num_L) else: str_L = chr(0x30 + num_L) return str_H + str_L #---------------------------------------------------------------------------- # 2バイト以上のAsciiコード(0~9、A~F a~f)を数値に変換する。 # byte2chr2(num)関数(1バイトを16進表記2文字に変換)の逆操作 # 2023/11/27:この関数は、次の式と同じであるが、Value Errorを生じさせない。 # return int("0x" + s) def chr2dec(s): l = len(s) data_hex = 0 # rcv_data は、s の i 番目の要素を示す 「Python入門」p140 参照 for i, rcv_data in enumerate(s): # print("rcv_data[{}] = {} ".format(i, ord(rcv_data))) data_ascii = ord(rcv_data) # print("rcv_ascii[{}] = {} ".format(i, data_ascii), end="") if data_ascii >= 48 and data_ascii <= 57: data_hex += (data_ascii - 48) * 16 ** (l - i - 1) elif data_ascii >= 65 and data_ascii <= 70: data_hex += ((data_ascii - 65) + 10) * 16 ** (l - i - 1) elif data_ascii >= 97 and data_ascii <= 102: data_hex += ((data_ascii - 97) + 10) * 16 ** (l - i - 1) return data_hex #---------------------------------------------------------------------------- # 数値を指定桁の数字文字列に変換・・・数字を右詰め、先頭の余白は、スペース # 20240328 Name Change def int2str_n(num, n): # int num, n:桁数 sp_n = ' ' * n # 最大桁数分 スペース # sp_n = '0' * n とする方法あり str_num = sp_n + str(num) # 先頭側に スペース return str_num[-n:] # 末尾の n桁 #---------------------------------------------------------------------------- # 文字列項目を固定桁数に編集・・・文字を左詰め、末尾の余白は、スペース # 20240328 Name Change def strFixL_n(str_x, n): # n:桁数 sp_n = ' ' * n # 最大桁数分 スペース str_x += sp_n # 末尾側に スペース return str_x[:n] # 先頭の n桁 #---------------------------------------------------------------------------- # 文字列項目を固定桁数に編集・・・文字を左詰め、末尾の余白は、0 # 20240328 Name Change def strFixLZ_n(str_x, n): # n:桁数 sp_n = '0' * n # 最大桁数分 0 str_x += sp_n # 末尾側に 0 return str_num[:n] # 先頭の n桁 #---------------------------------------------------------------------------- # 文字列項目を固定桁数に編集・・・文字を右詰め、先頭の余白は、スペース # 20240328 Name Change def strFixR_n(str_x, n): # n:桁数 sp_n = ' ' * n # 最大桁数分 スペース sp_n += str_x # 先頭側に スペース return sp_n[-n:] # 末尾の n桁 #---------------------------------------------------------------------------- ``` プログラム全体の見通しを良くするため「main.py」はできるだけ小さくして、タッチパネルを利用した音源パラメータ編集プログラムは、「tone_edit.py」に関数を集めモジュール化しました。 LCD表示やタッチパネル座標取得は「touch_lcd.py」、タブ表示やタブ座標などを管理する「tab_cdn.py」、SD-Cardへの読み書きを担当する「sdcard.py」などもモジュールとして「lib」フォルダ下にします。「tone_edit.py」は200KBを超える大きさになってしまいました。 ## PicoSub側のプログラム PicoSubプログラムは、次のプログラムで構成されています。 PicoSubプログラム側の説明は本題と外れますので省きます。 一部、関係のないプログラムが入っています。 ### main.py ```MicroPython:main.py ############################################################################# # YMF825で演奏するための PicoSub側のプログラム # PicoS_YMF825Midi-061.py Programed by Hyodo # # PicoMain と PicoSub で分担して処理する。このプログラムは、PicoSub用のプログラムである。 # PicoMain と PicoSub 間は、シリアル通信で接続する。 # PicoMain で YMF825の音源パラメータ(ToneData)などを編集し、PicoSubに送信する。 # PicoSub は、MIDI信号を受信し、YMF825で音出し(演奏)するとともに、MIDI-OUTにも出力する。 # # 実現できたこと # MIDI信号を受信し、YMF825で音出し(演奏)するとともに、MIDI-OUTにも信号を出す。 # YMF825 の音源は 16しかないが、GM音源に対応できるように、ToneTableを用意して適当に割った。 # MIDI-OUT側に、ポケットミクなどの音源を接続すれば、YMF825 と並行して音出しができる。 # # MIDI Keyboard(鍵盤)の入力で、YMF825 で和音を出すため、空きチャンネルを割り振る方法を採用した。 # # # YMF825による音出しはは、Shunsuke Ohira さんのプログラムを参考にした。 # # YMF825 との接続 # PICO gpio name (pin) (pin) YMF825 # gpio-17 SPI CS (22) ----白---- (1) SS # gpio-19 SPI MOSI (25) ----青---- (2) MOSI # gpio-16 SPI MISO (21) ----緑---- (3) MISO # gpio-18 SPI CLK (24) ----黄---- (4) CLK # GND -----------白---- (5) GND # 5V -----------橙---- (6) VCC # gpio-22 RESET (29) ----紫---- (7) RST # No Connect (8) Audio Jack # # YMF825 Monitor LED-BLUE # gpio-28 (34) --- BLUE-LED Anode --->--- Cathode (GND) # # # PicoMain と PicoSub との接続 # <<< PicoMain >>> Low True <<< PicoSub >>> # gpio-2 respT (4) --紫-- --黄-- (4) respT gpio-2 # X # gpio-3 respR (5) --黄-- --紫-- (5) respR gpio-3 # # gpio-4 TX (6) --緑-- --青-- (6) TX gpio-4 # X # gpio-5 RX (7) --青-- --緑-- (7) RX gpio-5 # # # Aques Talk との接続・・・このプログラムでは未使用 # <<< PicoSub >>> <<< Aques Talk ATP3012 >>> # (Pin) (Pin:ATP3012) # gpio-12 spi1_MISO (16) --緑-- (18) MISO # gpio-13 spi1_CE (17) --黃-- (16) /SS # gpio-14 spi1_CKL (19) --紫-- (19) SCK # gpio-15 spi1_MOSI (20) --青-- (17) MOSI # +5V --赤-- VCC # GND --白-- GND # # # PicoS(YMF825)HectOne-026.py をベースに、イコライザー(フィルター)機能を追加した # ものを残している ############################################################################# from machine import Timer, SPI, UART, Pin import time import utime import uos from micropython import const # 20240919 Add import math import ymf825py as ymf825 import mojipy as moji ############################################################################# # 上記インポートファイルは、予め、Picoに書き込んでおくこと # ymf825py.py : YMF825 接続用 # mojipy.py : 文字処理用 ############################################################################# HectOneVoice = [ # 01 tenchitennno- ['akinotano,','karihonoiono,', 'tomaoarami-,', 'wagakoromodewa,', 'tuyuninuretutu-.'], # 02 jito-tennno- ['harusugite,', 'natukinikerasi,', 'sirotaeno-,', 'koromohosutyo-,', 'amanokaguyama-.'], # 03 kakinomotonmo hitomaro ['asibikino,', 'yamadorinoono,', 'sidariono-,', 'naganagasiyowo,', 'hitorikamunenn-.'], # 04 yamabeno akahito ['tagonoura,', 'utidetemireba,', 'sirotaeno-,', 'fujinotakaneni,', 'yukiwafuritutu-.'], # 05 sarumaru dayu- ['okuyamani,', 'momijikakiwake,', 'nakusikano-,', 'koekikutokizo,', 'akiwakanasiki-.'], # 06 tyuunagionn nakamoti ['kasasagino,', 'wataseruhasini,', 'okusimono-,', 'sirokiomireba,', 'yozofukenikeru-.'], # 07 ['amanohara,', 'furisakemireba,', 'kasuganaru-,', 'mikasanoyamani,', 'idesitukikamo-.'], # 08 ['toppann,', 'ippann,', 'nippann,', 'nissann,', 'hyakuninnissyu.'], # 09 ['', '', '', '', ''], # 10 ['', '', '', '', ''], # 11 ['', '', '', '', ''], # 12 ['', '', '', '', ''], # 13 ['', '', '', '', ''], # 14 ['', '', '', '', ''], # 15 ['', '', '', '', ''], ] # MIDI Keyboard 入力を ch に振り分けるためのリスト TONE_NUM = const(16) ChList = [None] *TONE_NUM # KeyOn 起動で、NoteOff までのタイマー値 note_off_timer = [-1] *TONE_NUM NOTE_OFF_TIME = 4000 # シリアル uart_midi を生成 # MIDI は、31250bpsである。 MIDI_BAUD_RATE = 31250 # uart_midi = UART(1, MIDI_BAUD_RATE,bits=8,parity=None,stop=1,tx=Pin(8),rx=Pin(9)) uart_midi = UART(0, MIDI_BAUD_RATE,bits=8,parity=None,stop=1,tx=Pin(0),rx=Pin(1)) uartRespT = Pin(2, Pin.OUT) # Low TRUE uartRespT.value(1) uartRespR = Pin(3, Pin.IN) # Low TRUE # spi1 Aques Talk MODE=3 spi1 = SPI(1, baudrate=1000000, polarity=1, phase=1, sck=Pin(14), mosi=Pin(15), miso=Pin(12)) aques_cs = Pin(13, Pin.OUT) aques_cs.value(1) # 初期状態:1 # 時分割処理のためのタイマー # global変数定義。関数で利用するグローバル変数は、関数の定義前に書くのが無難。 uart_timer = 0 # UART RTS CTS Timer uartRtsReq = 0 # UART RTS Request 1:Request uartRtsBusy = 0 # UART RTS Busy 1:Busy MONOTONE_TIME = const(8000) # MIDI受信タイマー monoTone_timer = 0 spi_timer = 0 # SPI Time # 10ms 毎に割り込みが発生する なぜか引数 (t) は必須である。 def every10ms(t): global uart_timer, uartRespR, uartRtsReq, uartRtsBusy global monoTone_timer, note_off_timer global spi_timer if uart_timer < 10: uart_timer = 0 else: uart_timer -= 10 if uartRespR.value() == 0 and uartRtsBusy == 0: # PicoMain から送信要求あり uartRtsReq = 1 if monoTone_timer < 10: monoTone_timer = 0 else: monoTone_timer -= 10 if spi_timer < 10: spi_timer = 0 else: spi_timer -= 10 # note_off_timer for ch in range(TONE_NUM): if note_off_timer[ch] < 10 and note_off_timer[ch] >= 0: ymf825.note_off(ch) # 空きチャンネルにする ChList[ch] = 0 note_off_timer[ch] = -1 elif note_off_timer[ch] >= 10: note_off_timer[ch] -= 10 else: # note_off_timer[ch] < 0 pass # 20240416 10ms # 10ms 毎に every1ms を呼び出す呪文。これ以前に callback関数を定義のこと。 # Timer(period=10, mode=Timer.PERIODIC, callback=every1ms) # mode=Timer.PERIODIC は、指定しなくても大丈夫のようだ。 ############################################################################## # Main 直前で起動するするのが無難か # Timer(period=10, callback=every10ms) ############################################################################## # MicroPython説明サイトでは、タイマーの初期化を行っているが、なくても動作する。 # tim = Timer(period=1, mode=Timer.PERIODIC, callback=every1ms) # tim.init(period=1, callback=every1ms) ####################################################################### # HandShake Send RTS & Recive CTS Cross Connection # PicoMain と PicoSub との接続 # <<< PicoMain >>> Low True <<< PicoSub >>> # gpio-2 respT (4) --紫-- --黄-- (4) respT gpio-2 # X # gpio-3 respR (5) --黄-- --紫-- (5) respR gpio-3 # def waitCTS(rts, time, msg, cnt): global uart_timer if rts == 0: # Send RTS On uartRespT.value(0) uart_timer = time # Wait CTS On while uartRespR.value() == 1: # On == Low になるのを待つ if uart_timer == 0: print(msg) uart_timer = time if cnt > 0: cnt -= 1 else: break # Pico Sub と UART 通信できない utime.sleep_ms(10) elif rts == 1: # Send RTS Off uartRespT.value(1) uart_timer = time # Wait CTS Off while uartRespR.value() == 0: # Off == High になるのを待つ if uart_timer == 0: print(msg) uart_timer = time if cnt > 0: cnt -= 1 else: break # Pico Sub と UART 通信できない utime.sleep_ms(10) elif rts == 2: # Sub-Pico で利用 # Send RTS On uartRespT.value(0) uart_timer = time # Wait CTS Off while uartRespR.value() == 0: # Off == High になるのを待つ if uart_timer == 0: print(msg) uart_timer = time if cnt > 0: cnt -= 1 else: break # Pico Sub と UART 通信できない utime.sleep_ms(10) return cnt ####################################################################### # PicoMain からの受信処理 def uartComRcv(): global uartRespR, uartRespT, uartRtsReq, uartRtsBusy, tone_num, play_mode # 念のために確認 if uartRespR.value() == 0: # 念のためにから読みする ymf825.uart_blank_read() print('RTS arrived from Main-Pico') # Main Pico へ送信可を送出して、送信完了を待つ print('RTS On(0) to Main_Pico') cnt = 3 # RTS On(0) Wait CTS Off(1) = 送信完了 cnt = waitCTS(2, 1000, 'Wait UART data ...', cnt) # uartRespR.value() == 1 を待って if cnt > 0: uartRespT.value(1) # Toneリストを UART から読み込む # utime.sleep_ms(10) try: (rcv_size, headerID, tone_name) = ymf825.uartInTone() except: print('Error : on (rcv_size, headerID, tone_name) = ymf825.uartInTone() : NoneType?') rcv_size = 0 try: if rcv_size > 0: print() print(f'rcv_size={rcv_size} headerID={headerID} tone_name={tone_name}') # headerID == '0' : ToneData ならば if headerID == '0': # 読み込んだ Toneリストを、Tone_Com_Edit と Tone_Op_Edit に格納する # UART から受け取った Toneリストの tone_num を取得 tone_num = ymf825.takeInToneData() # ToneName 更新 ymf825.ToneName[tone_num] = tone_name # ToneMenuTable 更新 ・・・ PicoSubでは利用しないが ymf825.ToneMenuTable[tone_num +1][1] = tone_name # 内容をシリアル出力する # ymf825.serialOutToneData(tone_num) ymf825.copyTone2_Voice(tone_num) ymf825.serialOutVoiceData(tone_num) ymf825.init_tone() print('受信した音源で発音テスト(ToneTable の登録に従って音出し)') print('DoMiSo', tone_num, ymf825.ToneName[tone_num], 'Octave:4') ymf825.keyon5(0, 4, ymf825.KEY_C, 40, tone_num) utime.sleep_ms(1000) ymf825.keyon5(1, 4, ymf825.KEY_E, 40, tone_num) utime.sleep_ms(1000) ymf825.keyon5(2, 4, ymf825.KEY_G, 40, tone_num) utime.sleep_ms(1000) ymf825.keyoff(0) ymf825.keyoff(1) ymf825.keyoff(2) # headerID == '1' : ToneTable ならば elif headerID == '1': # ToneTable に格納 print('ymf825.takeInToneTable()') ymf825.takeInToneTable() # headerID == '%' : PrintDFP Command ならば elif headerID == '%': # PrintDFP Command を uart に送信 print('ymf825.uart_write_multi(PrintDFP Command)') ymf825.uart_write_multi(tone_name) # headerID == '2' : YMF825 Play Mode ならば elif headerID == '2': # play_mode Command を 受信 print('Recived play_mode Command') play_mode = tone_name.strip() # 文字列にする play_mode = play_mode.decode('utf-8') print(f'play_mode = {play_mode}') except TypeError: print('uartComRcv(): rcv_size > 0:') else: print() print('CTS Off(1) signal not comming from Main-Pico') print('ymf825.uartInTone() was not performed !!!') print('Check the connection with Main-Pico') print() # Send RTS Off uartRespT.value(1) utime.sleep_ms(1000) else: # print('RTS is not arrived') uartRespT.value(1) utime.sleep_ms(10) ####################################################################### # note_off_timer[0-15] を -1:TimeOver にする def init_note_off_timer(): global note_off_timer for ch in range(TONE_NUM): # ch 0-15 note_off_timer[ch] = -1 # -1:TimeOver ####################################################################### def check_and_set_ChList(kk): global ChList try: # すでに利用中の kk であるか? ch = ChList.index(kk) # エラーでなければ(見つかったなら)、その ch をそのまま利用する。 ############################# # 一旦、ノートオフにする print(f' note off ch = {ch}') ymf825.note_off(ch) utime.sleep_ms(50) ############################# return ch except ValueError: # エラーならば(利用中ではないなら)、空き ch を探す。 try: ch = ChList.index(0) # チャンネルを kk で使用中にする ChList[ch] = kk return ch except ValueError: return 16 ####################################################################### # ChList は整数リストとする # ChList(整数リスト)を 0クリアする def initChList(): global ChList # 0:空きチャンネル for ch in range(TONE_NUM): # ch 0-15 ChList[ch] = 0 ####################################################################### # ChList は整数リストとする # ChList(整数リスト)から、最初に見つかった 0 の位置(空きインデックス)を返す # 見つからなければ 16を返す def setChList(kk): global ChList try: ch = ChList.index(0) # チャンネルを kk で使用中にする ChList[ch] = kk return ch except ValueError: return 16 ####################################################################### # ChList は整数リストとする # ChList(整数リスト)から、最初に見つかった kk の位置(インデックス)を返す # 見つからなければ 16を返す def resetChList(kk): global ChList try: ch = ChList.index(kk) # 空きチャンネルに戻す ChList[ch] = 0 return ch except ValueError: return 16 ####################################################################### def allNoteOff(): for ch in range(16): # ch 0-15 ymf825.note_off(ch) utime.sleep_ms(10) ####################################################################### def sendAllNoteOffMidi(): midi_msg = bytearray(3) # オール・サウンド・オフ for ch in range(16): # ch 0-15 midi_msg[0] = 0xB0 + ch midi_msg[1] = 0x78 midi_msg[2] = 0x00 uart_midi.write(midi_msg) utime.sleep_ms(10) # オール・ノート・オフ for ch in range(16): # ch 0-15 midi_msg[0] = 0xB0 + ch midi_msg[1] = 0x7B midi_msg[2] = 0x00 uart_midi.write(midi_msg) utime.sleep_ms(10) ####################################################################### # note off = 8n kk vv or 9n kk 00 # note on = 9n kk vv # midi_rcvbuff から note on, note off 情報を抽出して ymf825に送る。 def noteYmf825(midi_rcvbuff): print('noteYmf825', end='') ch = moji.asc2int(midi_rcvbuff[0:2]) % 16 kk = moji.asc2int(midi_rcvbuff[2:4]) & 0x7F vv = moji.asc2int(midi_rcvbuff[4:6]) & 0x7F # note off if midi_rcvbuff[0] == '8' or (midi_rcvbuff[0] == '9' and vv == 0): print(' note off', ch) ymf825.note_off(ch) # note on # 20240928 Edit elif midi_rcvbuff[0] == '9' and vv != 0: octave = int(kk / 12) -1 key = kk % 12 print(' note on', ch, octave, key, vv) ymf825.note_on(ch, octave, key, vv) ####################################################################### # note on = 9n kk vv のみに対応し、 # note off = 8n kk vv or 9n kk 00 には直接反応せず、一定時間後に対応するモード。 # midi_rcvbuff から note on, note off 情報を抽出して ymf825に送る。 # midi Keyboard 入力で和音を出すために MONO TONE でチャンネルを振り分ける # 20240927 def noteMonoToneYmf825(midi_rcvbuff): を改造した。 def noteChaimeModeYmf825(midi_rcvbuff): # PicoMain から受信した tone_num で演奏する global tone_num print('noteKeyboardYmf825', end='') # ch = moji.asc2int(midi_rcvbuff[0:2]) % 16 kk = moji.asc2int(midi_rcvbuff[2:4]) & 0x7F vv = moji.asc2int(midi_rcvbuff[4:6]) & 0x7F if midi_rcvbuff[0] == '8' or (midi_rcvbuff[0] == '9' and vv == 0): # note off # なにもしない pass elif midi_rcvbuff[0] == '9' and vv != 00: # note on # 同一 kk で利用チャンネルを探す、なければ、空きチャンネルを探す ch = check_and_set_ChList(kk) print(f' {ch} = check_and_set_ChList({kk})', end = '') if ch >= 0 and ch < TONE_NUM: # ch 0-15 octave = int(kk / 12) -1 key = kk % 12 print(f' note on ch={ch} octave={octave} key={key} velocity={vv} tone={tone_num}') ymf825.note_onMonoTone(ch, octave, key, vv, tone_num) # タイマーをセット note_off_timer[ch] = NOTE_OFF_TIME else: # ch 0-15 以外なら # 何もしない pass ####################################################################### # MIDIの Program Change情報に基づき、ToneTable を編集する。 # MIDI受信したGM音源(1-128)を ymf825 の音色に変換して、ToneTableに記録する。 def changeToneTable(midi_rcvbuff): print('PROGRAM CHANGE ', end='') ch = moji.asc2int(midi_rcvbuff[0:2]) % 16 gm = moji.asc2int(midi_rcvbuff[2:4]) & 0x7F ymf = ymf825.exGmYmf825.get(gm) # ToneTable の更新 ymf825.ToneTable[ch +1][1] = ymf # ドラム(9)は、無音にする ymf825.ToneTable[9 +1][1] = 16 print('ch = ', ch, 'GM = ', gm, 'YMF825 = ', ymf) ####################################################################### # MIDI 入力を演奏する # Keyboardからの MIDIは、ch=0 だけなので、 MONO TONE にして和音対応する。 # Chaime Mode = Key On で発音し、 Key off 後も一定時間(4秒)持続する。 # 20240717:def noteMonoToneYmf825(midi_rcvbuff): 関数を内蔵して自動切り替えする。 # PicoMain からの送信要求(uartRtsReq)があれば、中断する。 # 20240927:def midiPlayYmf825(): を改造して作成。 def midiPlayChaimeModeYmf825(): global uartRespR, uartRtsReq, uartRtsBusy global monoTone_timer midi_rcvbuff = "" note_Flag = 0 note_Byte = 0 prg_Flag = 0 prg_Byte = 0 status_Flag = 0 # 0:mono_toneでない通常のmidi:MIDI受信した Program Change(音色変更)を利用する # 1:Keyboard:ch分割で和音対応:PicoMainから受信したToneDataを利用する # MIDI信号があれば、1 から 0 に切り替える。 mono_tone = 1 # チャンネルリストを 0 クリア initChList() # ノートオフタイマーを初期設定 init_note_off_timer() # PicoMain から送信要求があれば中断する while uartRtsReq == 0: # MIDI 受信ありなら if uart_midi.any() > 0: try: # uart_midi から、1データ読み込む(decodeなし=bytesデータのまま) midi_data_rx = uart_midi.read(1) except UnicodeError: # 読み込みエラーになるの?なら print("uart_midi.read(1) Error!!") midi_data_rx = "" # 受信した1バイトを2バイトの文字に変換して、シリアル出力する # print(moji.byte2chr2(midi_data_rx), end="") # 受信データを2バイトの文字データにして追加保存する midi_rcvbuff += moji.byte2chr2(midi_data_rx) # MIDI受信が8秒以上なければ、mono_tone = 1 にする ############################################## monoTone_timer = MONOTONE_TIME ############################################## ######################################################################### # note on または note off ならば if ord(midi_data_rx) >= 0x80 and ord(midi_data_rx) <= 0x9F: note_Flag = 1 note_Byte = 1 prg_Flag = 0 status_Flag = 0 # note on または note off のデータならば elif ord(midi_data_rx) < 0x80 and note_Flag == 1: note_Byte += 1 if note_Byte == 3: # データをシリアル出力する print(" >>> midi_rcvbuff = ", midi_rcvbuff) ##################################################### if mono_tone == 1: # mono_tone ###################################### # noteMonoToneYmf825(midi_rcvbuff) noteChaimeModeYmf825(midi_rcvbuff) ###################################### else: # MIDI受信した Program Change(音色変更)を利用した演奏 noteYmf825(midi_rcvbuff) ##################################################### note_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # Program Change(音色変更)ならば elif ord(midi_data_rx) >= 0xC0 and ord(midi_data_rx) <= 0xCF: mono_tone = 0 prg_Flag = 1 prg_Byte = 1 note_Flag = 0 status_Flag = 0 # Program Change(音色変更)のデータならば elif ord(midi_data_rx) < 0x80 and prg_Flag == 1: prg_Byte += 1 if prg_Byte == 2: # ToneTable を更新する print(" >>> midi_rcvbuff = ", midi_rcvbuff) # ############################## changeToneTable(midi_rcvbuff) ############################## prg_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # その他の情報ならば、何もしない else: #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### elif monoTone_timer == 0: # MIDI受信が8秒以上なければ、mono_tone = 1 にする ############################################## mono_tone = 1 ############################################## # while uartRtsReq != 0 PicoMain から送信要求があれば中断する else: print('Recived uartRtsReq !') # YMF825 allNoteOff() # MIDI sendAllNoteOffMidi() uartRtsBusy = 1 return ####################################################################### # MIDI 入力を YMF825で演奏する # 20251117:Ch0 以外なら MIDI 出力する機能を追加・・・ポケットミクをつなげる。 # 20251118:sw_ch (Swap Channel)が、0 以外なら、Ch0 をその sw_ch に出力する。 # Keyboardからの MIDIは、ch=0 だけなので、 MONO TONE にして和音対応する。 # 20240717:def noteMonoToneYmf825(midi_rcvbuff): 関数を内蔵して自動切り替えする。 # PicoMain からの送信要求(uartRtsReq)があれば、中断する。 def midiPlayYmf825(): global uartRespR, uartRtsReq, uartRtsBusy global monoTone_timer global sw_ch midi_rcvbuff = "" note_Flag = 0 note_Byte = 0 prg_Flag = 0 prg_Byte = 0 status_Flag = 0 # 0:mono_toneでない通常のmidi:MIDI受信した Program Change(音色変更)を利用する # 1:Keyboard:ch分割で和音対応:PicoMainから受信したToneDataを利用する # MIDI信号があれば、1 から 0 に切り替える。 mono_tone = 1 # チャンネルリストを 0 クリア initChList() # midiモニターバッファ midiMB = '' # PicoMain から送信要求があれば中断する while uartRtsReq == 0: # MIDI 受信ありなら if uart_midi.any() > 0: try: # uart_midi から、1データ読み込む(decodeなし=bytesデータのまま) midi_data_rx = uart_midi.read(1) except UnicodeError: # 読み込みエラーになるの?なら print("uart_midi.read(1) Error!!") midi_data_rx = "" # 受信データを2バイトの文字データにして追加保存する midi_rcvbuff += moji.byte2chr2(midi_data_rx) # MIDI受信が8秒以上なければ、mono_tone = 1 にする ############################################## monoTone_timer = MONOTONE_TIME ############################################## ######################################################################### # note on または note off のコマンドならば if ord(midi_data_rx) >= 0x80 and ord(midi_data_rx) <= 0x9F: note_Flag = 1 note_Byte = 1 prg_Flag = 0 status_Flag = 0 ch = ord(midi_data_rx) & 0x0F print(f'midi---> {midiMB}') midiMB = '' # midiモニターバッファ if sw_ch == 0: if ch == 0: pass else: uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # スワッピングが設定されていてコマンドなら sw_ch に変換して出力 else: if ch == 0: # ch == 0 なら sw_ch に変換して MIDI 出力 midi_data_tx = ord(midi_data_rx) & 0xF0 | sw_ch midi_data_tx = midi_data_tx.to_bytes(1, "big") uart_midi.write(midi_data_tx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_tx) elif ch == sw_ch: # ch == sw_ch なら MIDI 出力しない pass else: # それ以外なら そのまま MIDI 出力 uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # note on または note off のデータならば、データは2バイト elif ord(midi_data_rx) < 0x80 and note_Flag == 1: note_Byte += 1 if sw_ch == 0: if ch == 0: pass else: uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # スワッピングが設定されていてデータなら そのまま出力 else: if ch == sw_ch: # ch == sw_ch なら MIDI 出力しない pass else: # それ以外なら そのまま MIDI 出力 uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) if note_Byte == 3: # データが3バイト目ならば、YMF825に出力する print(" >>> midi_rcvbuff = ", midi_rcvbuff) ##################################################### if mono_tone == 1: # mono_tone noteMonoToneYmf825(midi_rcvbuff) else: # MIDI受信した Program Change(音色変更)を利用する noteYmf825(midi_rcvbuff) ##################################################### # 次の受信の準備 note_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # Program Change(音色変更)のコマンドならば elif ord(midi_data_rx) >= 0xC0 and ord(midi_data_rx) <= 0xCF: mono_tone = 0 prg_Flag = 1 prg_Byte = 1 note_Flag = 0 status_Flag = 0 ch = ord(midi_data_rx) & 0x0F print(f'midi---> {midiMB}') midiMB = '' # midiモニターバッファ if sw_ch == 0: if ch == 0: pass else: uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # スワッピングが設定されていてコマンドなら sw_ch に変換して出力 else: if ch == 0: # ch == 0 なら sw_ch に変換して MIDI 出力 midi_data_tx = ord(midi_data_rx) & 0xF0 | sw_ch midi_data_tx = midi_data_tx.to_bytes(1, "big") uart_midi.write(midi_data_tx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_tx) elif ch == sw_ch: # ch == sw_ch なら MIDI 出力しない pass else: # それ以外なら そのまま MIDI 出力 uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # Program Change(音色変更)のデータならば elif ord(midi_data_rx) < 0x80 and prg_Flag == 1: prg_Byte += 1 if sw_ch == 0: if ch == 0: pass else: uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # スワッピングが設定されていてデータなら そのまま出力 else: if ch == sw_ch: # ch == sw_ch なら MIDI 出力しない pass else: # それ以外なら そのまま MIDI 出力 uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) if prg_Byte == 2: print(" >>> midi_rcvbuff = ", midi_rcvbuff) ################################## # YMF825 用の ToneTable を更新する changeToneTable(midi_rcvbuff) ################################## # 次の受信の準備 prg_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # 0xBn 0xEn のコマンドならば、YMF825 に対しては何もせず。MIDI出力はする。 elif (ord(midi_data_rx) & 0xF0) == 0xB0 or (ord(midi_data_rx) & 0xF0) == 0xE0: status_Flag = 1 status_Byte = 1 note_Flag = 0 prg_Flag = 0 ch = ord(midi_data_rx) & 0x0F # print(f'ch = {ch} sw_ch = {sw_ch}') print(f'midi---> {midiMB}') midiMB = '' # midiモニターバッファ if sw_ch == 0: if ch == 0: pass else: uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # スワッピングが設定されていてコマンドなら sw_ch に変換して出力 else: if ch == 0: # ch == 0 なら sw_ch に変換して MIDI 出力 midi_data_tx = ord(midi_data_rx) & 0xF0 | sw_ch midi_data_tx = midi_data_tx.to_bytes(1, "big") uart_midi.write(midi_data_tx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_tx) elif ch == sw_ch: # ch == sw_ch なら MIDI 出力しない pass else: # それ以外なら そのまま MIDI 出力 uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # 0xBn 0xEn コマンドのデータならば、データは2バイト、全体で3バイト。 elif ord(midi_data_rx) < 0x80 and status_Flag == 1: status_Byte += 1 if sw_ch == 0: if ch == 0: pass else: uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # スワッピングが設定されていてデータなら そのまま出力 else: if ch == sw_ch: # ch == sw_ch なら MIDI 出力しない pass else: # それ以外なら そのまま MIDI 出力 uart_midi.write(midi_data_rx) # 1バイトを2桁の文字に変換してmidiモニターバッファに追加する midiMB += moji.byte2chr2(midi_data_rx) # 0xBn 0xEn コマンドならば、3バイトである if status_Byte == 3: # データが3バイト目ならば、YMF825には出力せず # 次の受信の準備 status_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # その他の情報ならば、YMF825 に対しては何もせず。MIDI出力はする。 else: # MIDI 出力する uart_midi.write(midi_data_rx) # YMF825 に対しては何もしない #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### elif monoTone_timer == 0: # MIDI受信が8秒以上なければ、mono_tone = 1 にする ############################################## mono_tone = 1 ############################################## # while uartRtsReq != 0 PicoMain から送信要求があれば中断する else: print('Recived uartRtsReq !') allNoteOff() uartRtsBusy = 1 return ####################################################################### # note off = 8n kk vv or 9n kk 00 note on = 9n kk vv # global tone_num で指定されているトーン番号=PicoMainからのToneData # midi_rcvbuff から note on, note off 情報を抽出して ymf825に送る。 # midi Keyboard 入力で和音を出すために MONO TONE でチャンネルを振り分ける def noteMonoToneYmf825(midi_rcvbuff): # PicoMain から受信した tone_num で演奏する global tone_num print('noteKeyboardYmf825', end='') # ch = moji.asc2int(midi_rcvbuff[0:2]) % 16 kk = moji.asc2int(midi_rcvbuff[2:4]) & 0x7F vv = moji.asc2int(midi_rcvbuff[4:6]) & 0x7F # note off if midi_rcvbuff[0] == '8' or (midi_rcvbuff[0] == '9' and vv == 0): # ノート オン したチャンネルを探す ch = resetChList(kk) print(f' {ch} = index_ChList({kk})', end = '') if ch >= 0 and ch <= 16: print(f' note off ch = {ch}') ymf825.note_off(ch) else: pass # note on # 20240928 Edit elif midi_rcvbuff[0] == '9' and vv != 0: # 空きチャンネルを探す ch = setChList(kk) print(f' {ch} = index_ChList(0)', end = '') if ch >= 0 and ch <= 16: octave = int(kk / 12) -1 key = kk % 12 print(f' note on ch={ch} octave={octave} key={key} velocity={vv} tone={tone_num}') ymf825.note_onMonoTone(ch, octave, key, vv, tone_num) else: pass ####################################################################### # MIDI Keyboard からの入力を演奏する # Keyboardは、ch=0 だけなので、 MONO TONE にして和音対応する # PicoMain からの送信要求(uartRtsReq)があれば、中断する。 # 20240928 利用されていない def midiKeyboardPlayYmf825(): global uartRespR, uartRtsReq, uartRtsBusy midi_rcvbuff = "" note_Flag = 0 note_Byte = 0 prg_Flag = 0 prg_Byte = 0 status_Flag = 0 # チャンネルリストを 0 クリア initChList() # PicoMain から送信要求があれば中断する while uartRtsReq == 0: # MIDI 受信ありなら if uart_midi.any() > 0: try: # uart_midi から、1データ読み込む(decodeなし=bytesデータのまま) midi_data_rx = uart_midi.read(1) except UnicodeError: # 読み込みエラーになるの?なら print("uart_midi.read(1) Error!!") midi_data_rx = "" # 受信した1バイトを2バイトの文字に変換して、シリアル出力する # print(moji.byte2chr2(midi_data_rx), end="") # 受信データを2バイトの文字データにして追加保存する midi_rcvbuff += moji.byte2chr2(midi_data_rx) ######################################################################### # note on または note off ならば if ord(midi_data_rx) >= 0x80 and ord(midi_data_rx) <= 0x9F: note_Flag = 1 note_Byte = 1 prg_Flag = 0 status_Flag = 0 # note on または note off 情報情報ならば elif ord(midi_data_rx) < 0x80 and note_Flag == 1: note_Byte += 1 if note_Byte == 3: # データをシリアル出力する print(" >>> midi_rcvbuff = ", midi_rcvbuff) # ################################### # 20240705 Change # noteYmf825(midi_rcvbuff) noteMonoToneYmf825(midi_rcvbuff) ################################### note_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # Program Change(音色変更)ならば elif ord(midi_data_rx) >= 0xC0 and ord(midi_data_rx) <= 0xCF: prg_Flag = 1 prg_Byte = 1 note_Flag = 0 status_Flag = 0 # Program Change(音色変更)のデータならば elif ord(midi_data_rx) < 0x80 and prg_Flag == 1: prg_Byte += 1 if prg_Byte == 2: # ToneTable を更新する print(" >>> midi_rcvbuff = ", midi_rcvbuff) # ############################## # 20240705 Change # changeToneTable(midi_rcvbuff) ############################## prg_Byte = 0 #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # その他の情報ならば、何もしない else: #################### midi_rcvbuff = "" note_Flag = 0 prg_Flag = 0 status_Flag = 0 #################### # while uartRtsReq != 0 PicoMain から送信要求があれば中断する else: print('Recived uartRtsReq !') allNoteOff() uartRtsBusy = 1 return ######################################################################## # Aques Talk Ready Chexk def aquesReady(time, msg): global spi_timer spi_timer = time buff = bytearray(1) aques_cs.value(0) utime.sleep_us(100) spi1.readinto(buff, 0xFF) # 0xFF 送出して1byte 読み込む utime.sleep_us(100) aques_cs.value(1) while buff != '>': # > = Ready になるのを待つ if spi_timer == 0: print('Time Over spi_timer') return spi_timer else: # DEBUG print # print(msg, ' ', end='') # print(f'spi1.read(1) = {buff}') utime.sleep_ms(20) aques_cs.value(0) utime.sleep_us(100) spi1.readinto(buff, 0xFF) # 0xFF 送出して1byte 読み込む utime.sleep_us(100) aques_cs.value(1) return spi_timer ######################################################################## # Aques Talk 発声 # 末尾に改行('\r')を送るので、talk_buffは本文のローマ字だけで良い。 def aquesTalk(talk_buff): if len(talk_buff) > 0: print(talk_buff) # Aques Talk Ready Check cnt = aquesReady(2000, 'Wait Aques Talk Ready') if cnt > 0: aques_cs.value(0) utime.sleep_us(100) for i in range(len(talk_buff)): spi1.write(talk_buff[i]) utime.sleep_us(30) # byte間 20us以上 spi1.write(b'\r') utime.sleep_us(100) aques_cs.value(1) else: print('Error Aques Talk is not Ready in def aquesTalk(talk_buff):') ######################################################################## # Calculate the biquad filter parameters def on_calc_biquad_filter(flt_type, fc_num, qv_num): # Cut off frequency and Q value (fc Hz, YMF825 sampling frequency is always 48000 Hz) fc = float(fc_num) qv = float(qv_num) print(f'fc = {fc}, qx = {qv}') # Zero clear the Fc and Qv if fc < 0.0 or qv < 0.0: print('if fc < 0.0 or qv < 0.0: in def on_calc_biquad_filter(fc_num, qv_num)') return # Calculate the filter parameters if qv < 0.01: qv = 0.01 # print("BIQUAD FILTER:{}, Fc={}, Q={}".format(flt_type, fc, qv)) # 20240919 Change w0 = math.pi * 2 * fc / 48000 alpha = math.sin(w0) / (qv + qv) cosw0 = math.cos(w0) print(f'w0 = {w0}, alpha = {alpha}, cosw0 = {cosw0}') a0 = 1.0 + alpha a1 = cosw0 * 2 / a0 a2 = (alpha - 1.0) / a0 if flt_type == "LPF:FcQ": b0 = (1.0 - cosw0) / (a0 + a0) b1 = (1.0 - cosw0) / a0 b2 = b0 elif flt_type == "HPF:FcQ": b0 = (1.0 + cosw0) / (a0 + a0) b1 = -(1.0 + cosw0) / a0 b2 = b0 elif flt_type == "BPFskt:FcQ": b0 = qv * alpha / a0 b1 = 0 b2 = -b0 elif flt_type == "BPF0db:FcQ": b0 = alpha / a0 b1 = 0 b2 = -b0 elif flt_type == "NOTCH:FcQ": b0 = 1 / a0 b1 = -2 * cosw0 / a0 b2 = b0 elif flt_type == "APF:FcQ": b0 = (1 - alpha) / a0 b1 = -2 * cosw0 / a0 b2 = (1 + alpha) / a0 else: print("UNKNOWN FILTER TYPE.") return # Set parameters print(f'PARMS b0 = {b0}, b1 = {b1} , b2 = {b2}, a0 = {a0}, a1 = {a1}, a2 = {a2}') # return b0, b1, b2, a1, a2 ######################################################################## # FROM ymf825pico.py 757 line~ # Set equalizer # eql:: Equalizer number (0, 1, 2) # ceq#:: ceq-eql-# # def set_equalizer( self, eql, ceq0 = 1.0, ceq1 = 0.0, ceq2 = 0.0, ceq3 = 0.0, ceq4 = 0.0 ): def set_equalizer( eql, ceq0 = 1.0, ceq1 = 0.0, ceq2 = 0.0, ceq3 = 0.0, ceq4 = 0.0 ): # 20240920 Add global equalizer_ceq def decimal_to_binary(n: float, int_digits: int = 3, frac_digits: int = 20): """Convert a decimal number to its binary representation""" # Check if number is negative negative = n < 0 n = abs(n) # Separate the integer part and fractional part int_part = int(n) # 整数部 frac_part = n - int_part # 小数部 # Convert integer part to binary int_binary = bin(int_part).replace("0b", "") while len(int_binary) < int_digits: int_binary = "0" + int_binary # Convert fractional part to binary frac_binary = "" while frac_part > 0 and len(frac_binary) < frac_digits: frac_part *= 2 bit = int(frac_part) if bit == 1: frac_part -= bit frac_binary += "1" else: frac_binary += "0" # If the number is negative, perform two's complement if negative: binary = list(int_binary + frac_binary) for i, bit in enumerate(binary): binary[i] = '0' if bit == '1' else '1' # 1's complement for i in range(len(binary) - 1, -1, -1): # 2's complement if binary[i] == '1': binary[i] = '0' else: binary[i] = '1' break int_binary = "".join(binary[:int_digits]) frac_binary = "".join(binary[int_digits:]) # return f"{'1' if negative else '0'}{int_binary}{frac_binary}" return f"{'0b1' if negative else '0b0'}{int_binary}{frac_binary}" # Make CEQ# bytes data def make_ceq_bytes( ceq_num, ceq ): print(f'ceq_num = {ceq_num}') print(f'ceq = {ceq}') ######################################## ceqB = int(decimal_to_binary(ceq), 2) ######################################## print(f'{ceqB} = int(decimal_to_binary(ceq), 2)') print(f'{ceqB:b} = int(decimal_to_binary({ceq}))') print(f'type(ceqB) = {type(ceqB)}') equalizer_ceq[ceq_num *3 +0] = (ceqB & 0xFF0000) >> 16 # 上位8bit equalizer_ceq[ceq_num *3 +1] = (ceqB & 0x00FF00) >> 8 # 中位8bit equalizer_ceq[ceq_num *3 +2] = ceqB & 0x0000FF # 下位8bit print(f'equalizer_ceq = {equalizer_ceq}') print(f'len(equalizer_ceq) = {len(equalizer_ceq)}') print() # この関数の実行開始位置 # Clear CEQ bytes data for b in range(15): # # 20240920 Change # self.equalizer_ceq[b] = 0 equalizer_ceq[b] = 0 # Make CEQ0 bytes data make_ceq_bytes( 0, ceq0 ) make_ceq_bytes( 1, ceq1 ) make_ceq_bytes( 2, ceq2 ) make_ceq_bytes( 3, ceq3 ) make_ceq_bytes( 4, ceq4 ) # Burst write mode and all key notes off # print("EDITOR: YMF825 Burst write mode.") # # 20240920 Change # self.spi_write_byte( 0x08, 0xF6 ) # self.delay(20) # self.spi_write_byte( 0x08, 0x00 ) # ymf825.spi_write_single( 0x08, 0xF6 ) utime.sleep_ms(20) ymf825.spi_write_single( 0x08, 0x00 ) # # Write tone data to YMF825 FIFO. # print("EDITOR: Write sound data to YMF825.") # print("EQUALIZER", eql, ":", list(self.equalizer_ceq)) # # 20240920 Change # self.spi_write( 32 + eql, bytearray(list(self.equalizer_ceq)) ) # # ymf825.spi_write_multi( 32 + eql, bytearray(list(equalizer_ceq)) ) # ymf825.spi_write_multi( 32 + eql, equalizer_ceq ) ######################################################################## def domisoTest(): print('DoMiSo', 'Octave:4') ymf825.note_on(0, 4, ymf825.KEY_C, 40) utime.sleep_ms(1000) ymf825.note_on(1, 4, ymf825.KEY_E, 40) utime.sleep_ms(1000) ymf825.note_on(2, 4, ymf825.KEY_G, 40) utime.sleep_ms(1000) ymf825.note_off(0) ymf825.note_off(1) ymf825.note_off(2) ######################################################################## # ------------------------------------------------------------------------- # Python Main Program # ------------------------------------------------------------------------- # YMF825 Setting ymf825.setup() # Max = 63 # 指定しなければ Max = 63 のままのようだ。 # ymf825.set_MasterVolume(24) ymf825.set_MasterVolume(32) # ymf825.set_MasterVolume(40) # ymf825.set_MasterVolume(48) ymf825.init_tone() time.sleep(1) print('初期設定の音源で発音テスト(= ToneTable の登録に従って音出し)') domisoTest() # Ch0 スワッピング先の Ch 番号 # ポケット・ミクの音源を利用する場合、ミクの音声は出さない、または、GM音源としたい場合がある。 # ポケット・ミクの Ch0 の音声は、プログラム・チェンジ(楽器変更)に関係なく、ミクの音声になるので # これを回避するため、MIDI入力から Ch0 を sw_ch に変更して出力する。 # 0 なら 出力先なし = Play Mode With Out Ch0 と同じ・・・ミクの音声は出さない # 10(内部コード:9)はドラムなので sw_ch には指定しないのが無難。 sw_ch = 0 tone_num = 0 uartRtsReq = 0 # PicoMain からの送信要求 uartRtsBusy = 0 # UART COM RECIVE 実行中 # 'Ch0_Waon_Normal':Ch0 は和音モードで動作するが、プログラムチェンジを受信するとMIDIのまま発音 play_mode = 'Ch0_Waon_Normal' play_mode_old = play_mode ############################################################################## # Main 直前で起動する Timer(period=10, callback=every10ms) ############################################################################## #---------------------------------------------------------------------------- # MicroPython Main Loop while True: # PicoMain からの受信があれば if uartRtsReq == 1 and uartRtsBusy == 1: play_mode_old = play_mode uartComRcv() # PicoMain からの受信処理 uartRtsBusy = 0 # UART COM RECIVE 実行終了 uartRtsReq = 0 # PicoMain からの送信要求 クリア # if play_mode.lower() == 'Init YMF825'.lower(): if 'Init'.lower() in play_mode.lower() and 'YMF'.lower() in play_mode.lower(): print('Init YMF825') ymf825.setup() # 指定しなければ Max = 63 のままのようだ。 ymf825.set_MasterVolume(32) ymf825.init_tone() time.sleep(1) print('初期設定の音源で発音テスト(= ToneTable の登録に従って音出し)') domisoTest() time.sleep(4) # 元の play_mode に戻す play_mode = play_mode_old # if play_mode.lower == 'All_Note_Off'.lower(): elif 'Note'.lower() in play_mode.lower() and 'Off'.lower() in play_mode.lower(): print('All Note Off') allNoteOff() sendAllNoteOffMidi() time.sleep(2) # 元の play_mode に戻す play_mode = play_mode_old # if play_mode.lower() == 'With Out Ch0'.lower(): elif 'With'.lower() in play_mode.lower() and 'Out'.lower() in play_mode.lower() \ and 'Ch0'.lower() in play_mode.lower(): print('With Out Ch0') sw_ch = 0 # 元の play_mode に戻す play_mode = play_mode_old # if play_mode.lower() == 'Swapping_Ch0_to >'.lower(): elif 'Swapping'.lower() in play_mode.lower() and 'Ch0'.lower() in play_mode.lower(): print('Swapping Ch0 to >') begin = 99 try: begin = play_mode.index('>') except ValueError: pass if begin < 14: sw_ch_old = sw_ch # > と space を取り除き、整数にする sw_ch = int(play_mode[begin:].strip('> ')) print(f'sw_ch = {sw_ch}') if sw_ch >= 0 and sw_ch <= 15: print(f'Swapping Ch0 to > {sw_ch}') else: sw_ch = sw_ch_old else: print('Irregular Swap Commands Ch ???') # 元の play_mode に戻す play_mode = play_mode_old # if play_mode.lower() == 'Ch0_Waon+4sec'.lower(): elif 'Waon'.lower() in play_mode.lower() and 'sec'.lower() in play_mode.lower(): print('play_mode = Ch0 Waon+4sec') # 元の play_mode に戻さない # if play_mode.lower() == 'Ch0_Waon+Normal'.lower(): elif 'Waon'.lower() in play_mode.lower() and 'Normal'.lower() in play_mode.lower(): print('play_mode = Ch0 Waon+Normal') # 元の play_mode に戻さない else: print('??? Unknown Commands') # 元の play_mode に戻す play_mode = play_mode_old # PicoMain からの受信がなければ else: ################################################################# # MIDI 受信・演奏をここに ・・・ midiPlayYmf825() # uartRtsReq == 1: PicoMain からの送信要求 あれば、処理を中断し、 # uartRtsBusy = 1: UART COM RECIVE 実行開始 をセットして戻る。 # 中断がない限り戻ってこない。 # Ch0 は、和音対応するが、MIDI信号にプログラムチェンジがあれば以降は # 和音対応せず、MIDI情報にしたがって発声する。 ################################################################# # if play_mode.lower() == 'Ch0_Waon+4sec'.lower(): if 'Waon'.lower() in play_mode.lower() and 'sec'.lower() in play_mode.lower(): print(f'play_mode = {play_mode}') print('midiPlayChaimeModeYmf825()') midiPlayChaimeModeYmf825() # play_mode_old = play_mode else: play_mode = 'Ch0 Waon Normal' print(f'play_mode = {play_mode}') print('midiPlayYmf825()') midiPlayYmf825() # play_mode_old = play_mode ''' aquesTalk("akuesu,to-ku,kido-simasita.") # 百人一首読み上げテスト aquesTalk("amanohara-,") aquesTalk("furisakemireba-,kasuganaru-,") aquesTalk("mikasanoyamani-,idesitukikamo-.") aquesTalk("a") aquesTalk("ma") aquesTalk("no") aquesTalk("ha") aquesTalk("ra,") aquesTalk("fu") aquesTalk("ri") aquesTalk("sa") aquesTalk("ke") aquesTalk("mi") aquesTalk("re") aquesTalk("ba,") aquesTalk("ka") aquesTalk("su") aquesTalk("ga") aquesTalk("na") aquesTalk("ru,") aquesTalk("mi") aquesTalk("ka") aquesTalk("sa") aquesTalk("no") aquesTalk("ya") aquesTalk("ma") aquesTalk("ni,") aquesTalk("i") aquesTalk("de") aquesTalk("si") aquesTalk("tu") aquesTalk("ki") aquesTalk("ka") aquesTalk("mo.") # Copy HectOnVoice to HectOne # Test 7 syu for i in range(8): # ローマ字 31文字文を連結する voiceRm = HectOneVoice[i][0] + \ HectOneVoice[i][1] + \ HectOneVoice[i][2] + \ HectOneVoice[i][3] + \ HectOneVoice[i][4] # 百人一首読み上げテスト aquesTalk(voiceRm) utime.sleep_ms(3000) equalizer_ceq = bytearray(15) ################################# # 以下は EQ(フィルター)テスト ################################# flt_type = 'LPF:FcQ' flt_fc = 1760 flt_qv = 0.7 # Calculate the biquad filter parameters (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer set_equalizer( 0, b0, b1, b2, a1, a2) utime.sleep_ms(1000) domisoTest() flt_type = 'HPF:FcQ' flt_fc = 440 flt_qv = 0.7 # Calculate the biquad filter parameters (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer set_equalizer( 1, b0, b1, b2, a1, a2) utime.sleep_ms(1000) domisoTest() flt_type = 'BPFskt:FcQ' flt_fc = 880 flt_qv = 0.7 # Calculate the biquad filter parameters (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer set_equalizer( 2, b0, b1, b2, a1, a2) utime.sleep_ms(1000) domisoTest() flt_type = 'LPF:FcQ' flt_fc = 1760 flt_qv = 0.7 # Calculate the biquad filter parameters (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer set_equalizer( 2, b0, b1, b2, a1, a2) utime.sleep_ms(1000) domisoTest() # Test Calculate the biquad filter parameters # on_calc_biquad_filter(flt_type, fc_num, qv_num) # (b0, b1, b2, a1, a2) = on_calc_biquad_filter("LPF:FcQ", 880, 4) flt_fc = 500.0 flt_qv = 0.7 for i in range(6): if i == 0: flt_type = 'LPF:FcQ' (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer Test set_equalizer( 0, b0, b1, b2, a1, a2) elif i == 1: flt_type = 'HPF:FcQ' (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer Test set_equalizer( 0, b0, b1, b2, a1, a2) elif i == 2: flt_type = 'BPFskt:FcQ' (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer Test set_equalizer( 0, b0, b1, b2, a1, a2) elif i == 3: flt_type = 'BPF0db:FcQ' (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer Test set_equalizer( 0, b0, b1, b2, a1, a2) elif i == 4: flt_type = 'NOTCH:FcQ' (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer Test set_equalizer( 0, b0, b1, b2, a1, a2) elif i == 5: # 【注意】強烈な音になる flt_type = 'APF:FcQ' (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer Test set_equalizer( 0, b0, b1, b2, a1, a2) utime.sleep_ms(1000) domisoTest() flt_type = 'LPF:FcQ' flt_fc = 5000.0 flt_qv = 0.7 # Calculate the biquad filter parameters (b0, b1, b2, a1, a2) = on_calc_biquad_filter(flt_type, flt_fc, flt_qv) # Set equalizer set_equalizer( 0, b0, b1, b2, a1, a2) utime.sleep_ms(1000) domisoTest() ''' ``` ### ymf825.py - 既出です・・・PicoMain側の ymf825.py と同じです。 ### mojipy.py - 既出です・・・PicoMain側の mojipy.py と同じです。 ## モジュールの紹介 ### 「touch_lcd.py」の改良について 「touch_lcd.py」は、LCD表示やタッチパネルからの入力を行うプログラムで、Waveshare社のサイトで提供されているサンプルプログラムmain_3inch5.pyを改変して「touch_lcd.py」としました。主に、「tone_edit.py」が利用します。 LCDの表示は4方向に指定できますが、表示を回転した時にも、表示座標(X軸・Y軸)とタッチ座標(X軸・Y軸)の方向が合致するように変更しました。表示位置のPixelと同様に扱えるようにしました。 タッチパネルのタッチ位置を表示位置に合わせて調整できるよう用のプログラムを内蔵・・・4隅にポイントを表示したところをタッチして、表示した結果でプログラムの定数を変更します。変更は自動ではなく、Thonyyでプログラムを書き換えが必要です。

-

### ymf825.pyについて

+

### ymf825.py について

「ymf825.py」は、FM音源IC YMF825を制御するための音源パラメータや制御コマンドを収納したモジュールです。 このモジュールは、Shunsuke Ohira様が作成されたプログラムやYAMAHAのC言語ライブラリなどを参考に作成しました。

-

### moji.pyについて

+

### moji.py について

「moji.py」は、①1バイトの整数を2バイトのASCII文字に変換 ②2バイト以上の0-9 a-f or A-F表記のASCII文字を整数に変換 するためのモジュールです。シリアル通信するときのデータのパックやアンパックに利用していますが、bytearrayの使い方がよく分かっていなかった時に作ったモジュールです。bytearrayをうまく使えば不要にできると思いますがプログラムを書き換えるのが面倒なのでそのままにしています。 # プログラムの動かし方(読み飛ばし可) PicoでMicroPythonプログラムを動かす方法は、①Thonnyで開いているプログラムを実行させる。②Picoにmain.pyの名前で書き込んで実行する。の2つの方法があります。 どちらにしてもmain.pyプログラム以外のモジュールである「touch_lcd.py」や「tone_edit.py」などは、予めPicoに書き込んでおく必要があります。 # YMF825パラメータの紹介(読み飛ばし可) - ご参考に編集対象である、YMF825のパラメータについて紹介します - YMF825では、16種類の音源を設定できます。 - 各音源の音色は、ベースの高さ(BO)、音の揺れ(LFO)、アルゴリズム(ALG)の3つに、17種類のパラメータをもつ4オペレータ(68パラメータ)を加えた全71パラメータで決定します。 - 4オペレータには、SR、XOF、KSR、RR、DR、AR、SL、TL、KSL、DAM、EAM、DVB、EVB、MUL、DT、WS、FBの17要素があります。 - 例えば、YAMAHAが用意しているTone Number 11 NylonGuiter は、次のようなパラメータになっています。 |Common Parameter|Max|Now| |:--------------:|:----:|:----:|:---:|:---:| |BO|3|0| |LFO|3|2| |ARG|7|5| |Parameter|Max|op1|op2|op3|op4| |:--------------:|:----:|:----:|:---:|:---:|:---:|:---:| |SR| 15| 1| 3| 5| 4| |XOF| 1| 0| 0| 0| 0| |KSR| 1| 1| 0| 1| 0| |RR| 15| 4| 7| 5| 9| |DR| 15| 1| 3| 5| 4| |AR| 15| 14| 15| 11| 13| |SL| 15| 8| 15| 4| 15| |TL| 63| 21| 0| 14| 13| |KSL| 3| 1| 0| 0| 2| |DAM| 3| 0| 0| 0| 0| |EAM| 1| 0| 0| 0| 0| |DVB| 3| 0| 0| 0| 1| |EVB| 1| 0| 1| 0| 1| |MUL| 15| 1| 1| 3| 1| |DT| 7| 0| 0| 0| 0| |WS| 31| 0| 0| 0| 0| |FB| 7| 6| 0| 0| 0| Maxは、YMF825が、項目別に設定できる最大値です。 # 編集画面の紹介 YMF825では、16の音源毎に共通項である3要素(BO、LFO、ALG)の編集画面と、4オペレータ17要素(SR、XOF、KSR、RR、DR、AR、SL、TL、KSL、DAM、EAM、DVB、EVB、MUL、DT、WS、FB)について編集する必要があります。 以下、編集画面を紹介します。 編集の操作状況は、Facebookに紹介動画があります。 Facebookに紹介動画があります。(Facebookへのログインが必要です) https://www.facebook.com/toshikazu.hyodo/videos/1216092900384973?idorvanity=247733226639836 ## ALG(Algorithm)選択画面 ![ALG(Algorithm)選択画面](https://camo.elchika.com/526486979179fc3d72b4be2c4e9af1b8f5832583/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f64366635326463332d386138382d343334622d623433662d396338356133353536333335/) CIMG9075.JPG - ALG(Algorithm):アルゴリズムは、4つのオペレータをどのような組み合わせるかの選択です。 - YMF825の場合、7つのアルゴリズムがありますので、組み合わせのイメージを表示して、その番号部分をタッチして選択できるようにしました。 ## BO、LFO 選択画面 ![BO、LFO 選択画面](https://camo.elchika.com/f1e523fc1af11df234dcb9aef93c80a2dfd920d6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f66346439313035662d373430342d346333382d616265652d623363353630313161323031/) CIMG9076.JPG - 音源のベースの高さ(BO)を設定します。通常は「0」ですが、低い方に1オクターブ、2オクターブ、3オクターブを選択できるようになっています。 - 音の揺れ(LFO)は、オシレータの周波数を選択できます。4つのオペレータのDAM、EAM、DVB、EVBと関係があると思います。 ## WS(Wave Shapes)選択画面 ![WS(Wave Shapes)選択画面](https://camo.elchika.com/a94f327d1b54bace72ac51a1e22c3b70e9e2c8d0/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f34653530303162622d393334322d343139372d616135342d373435373035356461656563/) CIMG9077.JPG WS(Wave Shapes):音源の波形の選択では、29の波形をイメージ表示してそれをタッチ選択するようにしました。 ## ADSR編集画面 ![ADSR編集画面](https://camo.elchika.com/7154475640558644d8917aa99a218e8577693ca6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f33323034316431392d306466322d343663382d396231642d373636393065393038653364/) CIMG9086.JPG - ADSR編集画面では、AR、DR、SR、RR、TL、SL、KSL、KSRを、1つの画面で編集しようとするものです。 - これらの要素は、4つのオペレータごとに設定する必要がありますので、画面上半分にある「OP1」~「OP4」で、どのオペレータに対する編集かを選択する必要があります。 - WSとMULは関連が深いので参考に表示しています。 - グラフの偏移点に紫色で四角のポイントが4つあります。ここにタッチペンを当てると大きなポイント表示となり、そのポイントを緑色の直線状、または、黄色の四角や緑色の四角の範囲内でスライドさせることで値を設定できます。 - ARとTL、DRとSRについては相互に関連していますので、黄色の四角と緑色の四角の範囲内で両方を同時に設定できるようにしています。 - KSL、KSRは、段階的な設定値を選ぶようになっています。設定値の場所をタッチするとその設定に切り替わり背景色と文字色が変わります。 ## MUL、DT、FB、XOF 編集画面 ![MUL、DT、FB、XOF 編集画面](https://camo.elchika.com/5091d9fb41d451e08a79ddc95639ec271bd4aeb1/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f35643161653735632d363665382d346666392d393266662d323563623830343134363732/) CIMG9081.JPG - この画面では、MUL、DT、FB、XOFを設定する画面です。 - これらの要素は、4つのオペレータごとに設定する必要がありますので、画面上半分にある「OP1」~「OP4」でオペレータを選択する必要があります。 - WSとMULは関連が深いので参考に表示しています。 - MULとDTは、緑の直線状に紫色で四角のポイントがあります。ここにタッチペンを当てると大きなポイント表示となり、そのポイントを緑色の直線状にスライドさせることで値を設定できます。 - FB、XOFは、段階的な設定値を選ぶようになっています。設定値の場所をタッチすると、その設定に切り替わり背景色と文字色が変わります。 ## DAM、EAM、DVB、EVB、編集画面 ![DAM、EAM、DVB、EVB、編集画面](https://camo.elchika.com/dc152470dd8579538fe8cd85aeed72751142a1f3/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f62383862633132652d643638622d346432342d386466362d643333323565336134373161/) CIMG9089.JPG DAM、EAM、DVB、EVBの選択画面です。 LFOの設定と関係があるようです。 # おまけ - 他人が作ったプログラムを見る(読む)には大変です。特に素人の私が作った長く絡まりまくったスパゲッティのようなプログラムを見るのは苦行だと思います。 - そこで最後までご覧いた方に、おまけを用意しました。 - このプログラムの実行には touch_lcd.py が必要です。touch_lcd.pyは既出です。 - Pico-ResTouch-LCD-3.5の背面にある40PinのPico用のソケットにPimoroni Pico Plus2 または Raspberry Pi Pico2を装着するだけで、PicoSubとの接続は無しで編集画面だけの確認ができます。 ![簡単、お試し回路(Raspberry Pi Pico2の場合)](https://camo.elchika.com/2ec523c0636d29f72afb729ba76916d0829ccbcc/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62663065396663652d373837332d343266652d623963322d3363666339616236313062612f32396138333134362d343738612d343666352d616462632d653730323337343036393661/) CIMG9113_4-3コメント.jpg ## TestEditMul_main.py 上記回路で確認できる MUL、DT、FB、XOFの設定部分だけをコンパクトにまとめたプログラムです。 ```MicroPython:TestEditMul_main.py ######################################################################## # 2025/11/30 Programed by Hyodot # TestEditMUL.py # このプログラムを Pico に保存して起動するときはファイル名を main.py にしてください。 # このプログラムはLCDタッチパネル Waveshare社製 Pico-ResTouch-LCD-3.5 を利用して # MUL DT FB XOF というパラメータ編集だけに限定した、体験用プログラムです。 ######################################################################## # # このプログラムでは、Pico-ResTouch-LCD-3.5 を利用するために # touch_lcd.py # を必要とします。 # touch_lcd.py は、Waveshare社が用意しているサンプルプログラム # main_3inch5.py をベースにライブラリとして利用できるように改変したものです。 # touch_lcd.py は Micropython の FrameBufferを利用します。 # 1画面分では、320 ☓ 480 Pixel ☓ 2 Bytes = 307200 Bytes のメモリを必要です。 # Pimoroni Pico Plus2 のメモリは、PSRAM 8MB ・・・ 動作します # Raspberry Pi Pico2 のメモリは、SRAM 520KB ・・・ 動作します # Raspberry Pi Pico のメモリは、SRAM 264KB ・・・ 動作しません # このプログラムは Pimoroni Pico Plus2 および Raspberry Pi Pico2 で動作しますが # メモリの少ない Raspberry Pi Pico では動作しません。 # # Pico-ResTouch-LCD-3.5 の背面にある Pico取り付け用のソケットに # Pimoroni Pico Plus2 または Raspberry Pi Pico2 を装着するだけで動作します。 # # Raspberry Pi Pico2 では、SPIの周波数が 40MHz で動作しますが、 # Pimoroni Pico Plus2 は、40MHz で動作させると嵌まり込む症状が出ます。 # PSRAM の特性で速度の問題があるのかもしれません。20MHzなら動作します。 # 理由はわかりませんが、SPI の実行速度は、設定した周波数の6割で動作しています。 # ######################################################################## from machine import Pin, SPI, PWM from micropython import const import os import gc # メモリ利用状況表示用 from touch_lcd import LCD_3inch5 ######################################################################## print(f'main MicroPython Start ... gc.mem_alloc() = {gc.mem_alloc()}') ######################################################################## ################################################## # import した ライブラリ class の短縮名 LCD = LCD_3inch5() LCD.bl_ctrl(100) # LCD輝度 100% 変更可能です print(f'LCD.rotate = {LCD.rotate}') ################################################## # タッチの誤動作を防止するためゾーンを複数回タッチした時に反応するようにしました。 # ここで設定した回数を連続して検知した時に受け付ける。3回にしました。 TOUCH_TH = const(3) # この Pixel 分を上下左右に拡大したエリアをタッチ有効とする。 # パネルの周辺部分では誤差が多いので、一部はこの倍の領域にしています。 TOUCH = const(8) # 表示座標 UPys = const(24) LWys = const(264) UPzs = [0, UPys] LWzs = [0, LWys] # 開始座標 幅 高さ UpperAria = (UPzs, 320, 240-24) LowerAria = (LWzs, 320, 240-24) # 編集テスト用パラメータ・データ # このプログラムでは、一部のパラメータの編集のみですが、すべてのパラメータを掲載します。 # 音源番号(ToneNo)は、0~15 ありますが、0:Grand Pianoのパラメータです。 # YMF825 Grand Piano Tone Data Set # ToneNo 0-15 TN = 0 max_TN = const(15) # Common BO = 0 LFO = 1 ALG = 3 max_BO = const(3) max_LFO = const(3) max_ALG = const(7) # Operator # 以下は、オペレーション・パラメータで、それぞれ4つのオペレータがある。 # 0:Max,op1,op2,op3,op4 を OP_numで指定する。 # 0:Max 1 2 3 4 WS = [31, 8, 0, 0, 0] MUL = [15, 1, 5, 1, 1] DT = [ 7, 0, 0, 0, 0] FB = [ 7, 0, 0, 0, 0] XOF = [ 1, 0, 0, 0, 0] TL = [63,39,40,34, 0] # YMF825 は 63 だが 実用的に 48 とする SL = [15,15, 2, 3, 4] AR = [15,15,14,13,13] DR = [15, 7, 3, 1, 2] SR = [15, 0, 2, 1, 2] RR = [15, 6, 3, 4, 6] KSL = [ 3, 1, 3, 0, 2] KSR = [ 1, 0, 1, 0, 1] DAM = [ 3, 0, 0, 0, 0] EAM = [ 1, 0, 0, 0, 0] DVB = [ 3, 0, 0, 0, 0] EVB = [ 1, 0, 0, 1, 1] # Operator は4つありますが、ここでは1番目のパラメータのみを編集対象にします。 OP_num = 1 now_WS = WS[OP_num] now_MUL = MUL[OP_num] now_DT = DT[OP_num] now_FB = FB[OP_num] now_XOF = XOF[OP_num] now_TL = TL[OP_num] now_SL = SL[OP_num] now_AR = AR[OP_num] now_DR = DR[OP_num] now_SR = SR[OP_num] now_RR = RR[OP_num] now_KSL = KSL[OP_num] now_KSR = KSR[OP_num] now_DAM = DAM[OP_num] now_EAM = EAM[OP_num] now_DVB = DVB[OP_num] now_EVB = EVB[OP_num] OP_max = const(0) max_WS = WS[OP_max] max_MUL = MUL[OP_max] max_DT = DT[OP_max] max_FB = FB[OP_max] max_XOF = XOF[OP_max] max_TL = TL[OP_max] -15 # 48 に抑制 max_SL = SL[OP_max] max_AR = AR[OP_max] max_DR = DR[OP_max] max_SR = SR[OP_max] max_RR = RR[OP_max] max_KSL = KSL[OP_max] max_KSR = KSR[OP_max] max_DAM = DAM[OP_max] max_EAM = EAM[OP_max] max_DVB = DVB[OP_max] max_EVB = EVB[OP_max] # X_Poin と Y_Point が 共に zoneS ~ zoneE の範囲内にあるか否か def in_zone(zoneS, zoneE, X_Point, Y_Point): # X_Poin と Y_Point が 共に zoneS ~ zoneE の範囲内ならば True if zoneS[0] <= X_Point and X_Point <= zoneE[0] \ and zoneS[1] <= Y_Point and Y_Point <= zoneE[1]: return True else: return False def dspFillUpper(color_back): (zs, w, h) = UpperAria LCD.fill_rect(zs[0], zs[1], w, h, color_back) def dspFillLower(color_back): (zs, w, h) = LowerAria LCD.fill_rect(zs[0], zs[1], w, h, color_back) def dspMUL(now_MUL): # MUL 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(8, 270, 16*4, 20, LCD.WHITE) LCD.text_scaled(f'{now_MUL:>2}', 24, 270 +2, LCD.BLACK, 2) # 右寄せ表示 def dspDT(now_DT): # DT 数値表示 文字領域を 白色にしてから表示 LCD.fill_rect(80+16, 340, 16*3, 20, LCD.WHITE) LCD.text_scaled(f'{now_DT}', 80+32, 340+2, LCD.BLACK, 2) def dsp_FB(now_FB, color_back, color_text): # FB 数値表示 背景を黄色にし、文字色は紫色 # 0 1 2 3 4 5 6 7 text_FB = [' 0 ', 'pi/16', 'pi/ 8', 'pi/ 4', 'pi/ 2', 'pi ', 'pi *2', 'pi *4'] if now_FB >= 0 and now_FB <= 7: LCD.fill_rect(FBxs[now_FB]-2, FBys[now_FB], 16*FBcn +4, 20, color_back) LCD.text_scaled(text_FB[now_FB], FBxs[now_FB], FBys[now_FB]+2, color_text, 2) def dsp_XOF(now_XOF, color_back, color_text): # XOF 数値表示 背景を黄色にし、文字色は紫色 # 0 1 text_XOF = ['off', 'on '] if now_XOF >= 0 and now_XOF <= 1: LCD.fill_rect(XOFxs[now_XOF]-2, XOFys[now_XOF], 16*XOFcn +4, 20, color_back) LCD.text_scaled(text_XOF[now_XOF], XOFxs[now_XOF], XOFys[now_XOF]+2, color_text, 2) ######################################################################## # MicroPython Start ######################################################################## # sign_XX は、スライダーの正負(X軸、Y軸の移動に対して取得数値が増大か?縮小か?) # MUL DT ともに上が大、下が小なので、-1 sign_MUL = -1 sign_DT = -1 # FB タッチ開始座標の設定 # 0 1 2 3 4 5 6 7 FBxs = [160,160,160,160,160,160,160,160] FBys = [430,410,390,370,350,330,310,290] FBcn = 5 # XOF タッチ開始座標の設定 # 0 1 XOFxs = [250,250] XOFys = [430,410] XOFcn = 3 # 編集メモ tone_edit.py の関数 # def edit_mul(tabM_num, tabS_num, OP_num, now_MUL, now_DT, now_FB, now_XOF): # から主要部分を移植した。 # FB タッチゾーンの設定 # FB タッチ開始座標は、main で設定したものを利用する zone_FBsi = [None, None] *(max_FB +1) zone_FBei = [None, None] *(max_FB +1) for i in range(max_FB +1): zone_FBsi[i] = [FBxs[i], FBys[i]] zone_FBei[i] = [FBxs[i]+16*6, FBys[i]+20] # FB カウンタの設定 cnt_FBi = [None] *(max_FB +1) for i in range(max_FB +1): cnt_FBi[i] = 0 # XOF タッチゾーンの設定 # XOF タッチ開始座標は、冒頭で設定したものを利用する zone_XOFsi = [None, None] *(max_XOF +1) zone_XOFei = [None, None] *(max_XOF +1) for i in range(max_XOF +1): zone_XOFsi[i] = [XOFxs[i], XOFys[i]] zone_XOFei[i] = [XOFxs[i]+16*6, XOFys[i]+20] # XOF カウンタの設定 cnt_XOFi = [None] *(max_XOF +1) for i in range(max_XOF +1): cnt_XOFi[i] = 0 # MUL DT スライダーポイントの座標設定(Pixcel単位):絶対値 pos_MUL = [ 40, 445 - now_MUL *10] # MUL:0~15 pos_DT = [120, 445 - now_DT *10] # DT:0~7 # MUL DT カウンタの設定 cnt_MUL = 0 cnt_DT = 0 # MUL DT タッチゾーン設定 16 Pixcel四方 ---> 24 Pixcel四方 zone_MULs = [None] *2 zone_MULs[0] = 0 if pos_MUL[0] < TOUCH *2 else pos_MUL[0] - TOUCH *2 zone_MULs[1] = 0 if pos_MUL[1] < TOUCH *2 else pos_MUL[1] - TOUCH *2 zone_MULe = [None] *2 zone_MULe[0] = 319 if (pos_MUL[0] + TOUCH) >= 320 else pos_MUL[0] + TOUCH zone_MULe[1] = 479 if (pos_MUL[1] + TOUCH) >= 480 else pos_MUL[1] + TOUCH zone_DTs = [None] *2 zone_DTs[0] = 0 if pos_DT[0] < TOUCH *2 else pos_DT[0] - TOUCH *2 zone_DTs[1] = 0 if pos_DT[1] < TOUCH *2 else pos_DT[1] - TOUCH *2 zone_DTe = [None] *2 zone_DTe[0] = 319 if (pos_DT[0] + TOUCH) >= 320 else pos_DT[0] + TOUCH zone_DTe[1] = 479 if (pos_DT[1] + TOUCH) >= 480 else pos_DT[1] + TOUCH ######################################################################## # MUL 直線上の設定範囲(Pixcel単位):絶対値 slide_MULs = [ 40, 445 - max_MUL *10] slide_MULe = [ 40, 445] # DT 直線上の設定範囲(Pixcel単位):絶対値 slide_DTs = [120, 445 - max_DT *10] slide_DTe = [120, 445] # 長方形の操作可能範囲 16 Pixcel guide_MULs = [None] *2 guide_MULs[0] = 0 if slide_MULs[0] < TOUCH *2 else slide_MULs[0] - TOUCH *2 guide_MULs[1] = 0 if slide_MULs[1] < TOUCH else slide_MULs[1] - TOUCH guide_MULe = [None] *2 guide_MULe[0] = 319 if (slide_MULe[0] + TOUCH) >= 320 else slide_MULe[0] + TOUCH guide_MULe[1] = 479 if (slide_MULe[1] + TOUCH) >= 480 else slide_MULe[1] + TOUCH guide_DTs = [None] *2 guide_DTs[0] = 0 if slide_DTs[0] < TOUCH *2 else slide_DTs[0] - TOUCH *2 guide_DTs[1] = 0 if slide_DTs[1] < TOUCH else slide_DTs[1] - TOUCH guide_DTe = [None] *2 guide_DTe[0] = 319 if (slide_DTe[0] + TOUCH) >= 320 else slide_DTe[0] + TOUCH guide_DTe[1] = 479 if (slide_DTe[1] + TOUCH) >= 480 else slide_DTe[1] + TOUCH edt_mode = '' while True: # MUL DT 座標更新 # MUL DT スライダーポイントの座標設定(Pixcel単位):絶対値 pos_MUL = [ 40, 445 - now_MUL *10] # MUL:0~15 pos_DT = [120, 445 - now_DT *10] # DT:0~7 # MUL DT タッチゾーン更新 16 Pixcel四方 ---> 24 Pixcel四方 # pos_MUL と pos_DT は、タッチで更新される zone_MULs[0] = 0 if pos_MUL[0] < TOUCH *2 else pos_MUL[0] - TOUCH *2 zone_MULs[1] = 0 if pos_MUL[1] < TOUCH *2 else pos_MUL[1] - TOUCH *2 zone_MULe[0] = 319 if (pos_MUL[0] + TOUCH) >= 320 else pos_MUL[0] + TOUCH zone_MULe[1] = 479 if (pos_MUL[1] + TOUCH) >= 480 else pos_MUL[1] + TOUCH zone_DTs[0] = 0 if pos_DT[0] < TOUCH *2 else pos_DT[0] - TOUCH *2 zone_DTs[1] = 0 if pos_DT[1] < TOUCH *2 else pos_DT[1] - TOUCH *2 zone_DTe[0] = 319 if (pos_DT[0] + TOUCH) >= 320 else pos_DT[0] + TOUCH zone_DTe[1] = 479 if (pos_DT[1] + TOUCH) >= 480 else pos_DT[1] + TOUCH dspFillUpper(LCD.WHITE) dspFillLower(LCD.WHITE) # 画面全体を白色にしたい場合 # LCD.fill(LCD.WHITE) # slide Line 垂直方向のガイド(垂直方向に5回線を引く) # MUL DT for x in range(-2, 3): # -2, -1, 0, 1, 2 : 38, 39, 40, 41, 42 : 118, 119, 120, 121, 122 LCD.line(slide_MULs[0]+x, slide_MULs[1], slide_MULe[0]+x, slide_MULe[1]+4, LCD.GREEN) LCD.line(slide_DTs[0]+x, slide_DTs[1], slide_DTe[0]+x, slide_DTe[1]+4, LCD.GREEN) # MUL DT の操作ポイントを、サイズ TOUCH(8x8)で再表示する LCD.fill_rect(pos_MUL[0] -4, pos_MUL[1] -4, TOUCH, TOUCH, LCD.RED) LCD.fill_rect(pos_DT[0] -4, pos_DT[1] -4, TOUCH, TOUCH, LCD.RED) # MUL のタイトル表示 LCD.text_scaled(f'MUL', 0 +16, 455, LCD.BLACK, 2) # DT のタイトル表示 LCD.text_scaled(f'DT', 80 +24, 455, LCD.BLACK, 2) # MUL DT の数値を表示する(編集中にも表示することに留意) dspMUL(now_MUL) dspDT(now_DT) # FB のタイトル表示 LCD.text_scaled(f'FB', 160+24, 455, LCD.BLACK, 2) # FB 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for fb in range(max_FB +1): # FB 設定内容の表示 dsp_FB(fb, LCD.GREEN, LCD.GRAY) # FB 設定値の表示 dsp_FB(now_FB, LCD.YELLOW, LCD.PURPLE) # XOF のタイトル表示 LCD.text_scaled(f'XOF',250, 455, LCD.BLACK, 2) # XOF 数値表示 文字領域を 緑色にしてから表示、文字色は一旦灰色 for xof in range(max_XOF +1): # XOF 設定内容の表示 dsp_XOF(xof, LCD.GREEN, LCD.GRAY) # XOF 設定値の表示 dsp_XOF(now_XOF, LCD.YELLOW, LCD.PURPLE) get = LCD.touch_get() if get != None: # タッチされているなら、X座標、Y座標を取得します X_Point = get[0] Y_Point = get[1] if edt_mode == '': if in_zone(zone_MULs, zone_MULe, X_Point, Y_Point): # MUL ポイント周辺ならば # print('zone_MUL') cnt_MUL += 1 if cnt_MUL == TOUCH_TH: print('select_MUL') # 差分検出用に現在値を記録(Pixcel値) edt_Ys = Y_Point edt_mode = 'MUL' elif in_zone(zone_DTs, zone_DTe, X_Point, Y_Point): # DT ポイント周辺ならば # print('zone_DT') cnt_DT += 1 if cnt_DT == TOUCH_TH: print('select_DT') # 差分検出用に現在値を記録(Pixcel値) edt_Ys = Y_Point edt_mode = 'DT' for i in range(max_FB +1): if in_zone(zone_FBsi[i], zone_FBei[i], X_Point, Y_Point): # print(f'zone_FB{i}') cnt_FBi[i] += 1 if cnt_FBi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_FB = i # FB 数値表示 背景を黄色にし、文字色は紫色 dsp_FB(now_FB, LCD.YELLOW, LCD.PURPLE) edt_mode = f'FB{i}' print(f'edt_mode = {edt_mode}') for i in range(max_XOF +1): if in_zone(zone_XOFsi[i], zone_XOFei[i], X_Point, Y_Point): # print(f'zone_XOF{i}') cnt_XOFi[i] += 1 if cnt_XOFi[i] == TOUCH_TH: # 差分検出用に現在値を記録(Pixcel値) edt_Xs = X_Point edt_Ys = Y_Point now_XOF = i # XOF 数値表示 背景を黄色にし、文字色は紫色 dsp_XOF(now_XOF, LCD.YELLOW, LCD.PURPLE) edt_mode = f'XOF{i}' print(f'edt_mode = {edt_mode}') elif edt_mode == 'MUL': if in_zone(guide_MULs, guide_MULe, X_Point, Y_Point): # MUL 編集ゾーンならば # print('edt_mode MUL') if edt_Ys != Y_Point: # 操作感度を上げる場合は、/4 の数字を小さく、下げる場合は、/4 の数字を大きく # edt_def = int((Y_Point - edt_Ys) /4) edt_def = int((Y_Point - edt_Ys) /8) # 加減算の正負に注意(x軸は右方向に正、y軸は下方向に正) now_MUL += (edt_def *sign_MUL) # 範囲に収める処理 now_MUL = 0 if now_MUL < 0 else now_MUL now_MUL = max_MUL if now_MUL > max_MUL else now_MUL # 表示ポイント更新 計算方法は項目ごとに異なるので注意 # スライダーポイントの座標設定(Pixcel単位):絶対値 を更新 pos_MUL = [ 40, 445 - now_MUL *10] # MUL:0~15 # MUL の操作ポイントを、倍角 TOUCH(8x8)*2 で表示する LCD.fill_rect(pos_MUL[0] -TOUCH, pos_MUL[1] -TOUCH, TOUCH*2, TOUCH*2, LCD.PURPLE) # MUL 数値表示 文字領域を 白色にしてから表示 dspMUL(now_MUL) # edt_Ys 更新 edt_Ys = pos_MUL[1] elif edt_mode == 'DT': if in_zone(guide_DTs, guide_DTe, X_Point, Y_Point): # DT 編集ゾーンならば # print('edt_mode DT') if edt_Ys != Y_Point: # 操作感度を上げる場合は、/4 の数字を小さく、下げる場合は、/4 の数字を大きく # edt_def = int((Y_Point - edt_Ys) /4) edt_def = int((Y_Point - edt_Ys) /8) # 加減算の正負に注意(x軸は右方向に正、y軸は下方向に正) now_DT += (edt_def *sign_DT) # 範囲に収める処理 now_DT = 0 if now_DT < 0 else now_DT now_DT = max_DT if now_DT > max_DT else now_DT # 表示ポイント更新 計算方法は項目ごとに異なるので注意 # スライダーポイントの座標設定(Pixcel単位):絶対値 pos_DT = [120, 445 - now_DT *10] # DT:0~7 # DT の操作ポイントを、倍角 TOUCH(8x8)*2 で表示する LCD.fill_rect(pos_DT[0] -TOUCH, pos_DT[1] -TOUCH, TOUCH*2, TOUCH*2, LCD.PURPLE) # DT 数値表示 文字領域を 白色にしてから表示 dspDT(now_DT) # edt_Ys 更新 edt_Ys = pos_DT[1] else: # get == None edt_mode = '' # MUL DT カウンタのクリア cnt_MUL = 0 cnt_DT = 0 # FB カウンタのクリア for i in range(max_FB +1): cnt_FBi[i] = 0 # XOF カウンタのクリア for i in range(max_XOF +1): cnt_XOFi[i] = 0 LCD.show() ``` **最後までご覧いただきありがとうございます。何かの参考になれば幸いです。**