Hyodotのアイコン画像
Hyodot 2024年10月27日作成
製作品 製作品 閲覧数 149
Hyodot 2024年10月27日作成 製作品 製作品 閲覧数 149

ワイングラスの音色を楽器にしてMIDI演奏する

外観

全体の構成

動画

編集画面やMIDI演奏の動画です。
Facebookに紹介動画

用途(目的)

  • 音楽の楽しみ方は色々あると思いますが、この作品は、楽器の音色を自分好みに編集して演奏を楽しむためのものです。
  • 楽器が弾ける人なら、編集した楽器で演奏できますが、私は楽器を演奏できないので、インターネットからパソコンにMIDIファイルをダウンロードして、無料ソフト「Domino」で演奏させています。

概要(作品全体の説明)

  • FM音源IC(YMF825)を利用して、手持ちのワイングラスの音色を真似た楽器作り。
  • ワイングラスは1つあればOK。音色の特徴を設定すれば、音階はYMF825にお任せ。
  • 2つのPicoをシリアル通信で連携させ、1つをPicoMainとし音源編集用、もう1つをPicoSubとしYMF825を使ったMIDI再生(発音)用にしました。
  • パラメータを設定しやすいように編集用のPicoMainにはPS/2マウスとPS/2キーボードを繋げ、TFT-LCDを接続しました。
  • パソコンからのMIDI信号をUSBに出力して、PicoSub側でDIN-MIDIインターフェースで受けて、再生(発音)します。
  • Pico側でUSB-MIDI対応するのはハードルが高いので、DIN-MIDIインターフェースで受けることにしました。
  • この関係で、パソコンのUSB端子に接続してDIN-MIDIに変換して出力できるケーブルが必要です。(Amazonで購入しました)
  • 本作品とは直接関係ありませんが、声紋のようなスペクトログラム表示しているモジュールは、液晶表示付きマイコンボードDISC-F746です。(スペクトログラム表示のアプリを入れています)
  • 音楽やシンセサイザーは ド素人ですが、音色は倍音の構成を真似るといいようです。声紋のようなスペクトログラム表示が分析ツールになります。楽器では線状に倍音の模様が現われますので、それを真似るようにYMF825の音源パラメータを調整します。
  • YMF825は、16音源16和音対応ですが、動画ではワイングラスの音ということで、1音源だけにしています。

主要部品

キャプションを入力できます

  • この作品は、PS/2キーボードに対応していますが、USBキーボードからPS/2キーボードに逆変換する 「PS/2 USB逆変換アダプタ」を使うと、USB無線のキーボードが使えます。
  • 「PS/2 USB逆変換アダプタ」は、マウスには対応していませんので、マウスを無線化することはできません。

回路図

回路全体の写真

全体ブロック図

(UARTデバイスやSPIデバイスとの接続は、個別接続図があります)
全体ブロック図

UARTデバイスやSPIデバイスの個別接続図

PicoMainとTFT-LCD ST7789との接続図

キャプションを入力できます

PicoMainとRFID RC522との接続図

キャプションを入力できます

PicoMainとPS/2キーボード、PS/2マウスとのgpio接続

PicoMainとPS/2キーボード、PS/2マウスとのgpio接続

PicoSubとYMF825とのSPI-0接続図

PicoSubとYMF825とのSPI-0接続図

PicoMainとPicoSubとのgpio接続図

PicoMainとPicoSubとのgpio接続図

MIDIインターフェースとPicoMain、PicoSubとのUART-0接続図

キャプションを入力できます

MIDIインターフェースの改良図面

MIDI入出力の精度を上げるため、MIDI入力をカレントミラー回路に、MIDI出力にバッファを入れました。赤色ボールペン手書きの部分。
MIDIインターフェースの改良図面

プログラム

プログラムは数が多くサイズも大きいので、末尾に掲載します。

ライブラリ・プログラムについて

RC522 RFID リーダー モジュールを使用するため、次のサイトのライブラリを引用しました。
https://how2electronics.com/using-rc522-rfid-reader-module-with-raspberry-pi-pico/
ST7789(TFT-LCD)用のライブラリはDFROBOTサイトのライブラリを引用しました。
https://community.dfrobot.com/makelog-311712.html
なお、このST7789ライブラリにはSPI設定に問題があります。
spi1 = machine.SPI(1, baudrate=40000000, polarity=1)
とあるところは
spi1 = machine.SPI(1, baudrate=40000000, polarity=1, phase=1)
と、phase=1の設定が追加すべきです。(表示しないLCDがあり困りました)
上記以外のライブラリは、自作です。
YMF825のライブラリは、以前には存在したYAMAHAのサイトからダウンロードしていたC言語のライブラリをベースに、大平駿介様の了解を得て次のサイトの記事を参考にMicroPuthonで作成しました。
https://github.com/ohira-s/YMF825pico

開発環境

  • PicoMain PicoSub、それぞれを、Raspberry Pi 4BとUSB接続し、標準でインストールされていたThonnyでソフト開発しました。
  • シリアル出力と、Picoに接続したLEDのみでデバッグしました。
  • 回路図にはデバッグに使用したLEDの配線を省略しています。

編集画面の紹介

初期画面

初期画面は、音源選択画面になっています。YMF825初期設定の16音源の名称一覧を表示し、どの音源を編集するか選択します。
初期画面

YMF825にはYAMAHAのサイトからダウンロードした16音源を初期セットしています。新しく編集する場合でも初期設定の音源から近いものを選んで編集し、編集の最後で名称変更できるようにしています。

音源編集画面

音源編集画面は、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)の編集画面があります。
音源編集画面

  • 各要素の項目移動には、キーボードの矢印キー、または、マウスを動かします。Enterキー、または、マウスの左クリックで項目の編集になります。
  • 3要素の編集画面、または、17要素の編集画面から次の編集画面に移行するには、マウスで右クリック、または、Escキーです。
  • パラメータの値変更は、マウスのスクロール、または、テンキーを使います。(BackSpaceキーで末尾をクリア、Deleteキーで項目をクリア)

音源編集の最後に保存場所(0-15)と名称編集します。
キャプションを入力できます

  • 設定したパラメータは、Pico のメモリには保存されません。
  • RFIDのタグ(またはカード)を利用してパラメータの保存と読み込みができるようRead RFID と Write RFID のメニューを用意してます。保存しておくと後で音源のパラメータの読み込みができます。(次項で説明)

音源編集以外のメニュー

音源編集以外のメニューは、初期画面の音源選択画面で、キーボードの「PtSc」(PrintScreen)キーで表示します。
音源編集以外のメニュー

音源編集以外のメニューとしては、

  • Edit Tone:前記で紹介した音源編集
  • Read RFID:RFID Tag(または Card)からの読み込み(音源設定パラメータの読み込み)
  • Write RFID:RFID Tag(または Card)への書き込み(音源設定パラメータの書き込み)
  • Play MIDI:MIDI入力を演奏(パソコンとつなぐ、鍵盤とつなぐ)
    などがあります。

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)合計71項目のパラメータがあります。
  • 各パラメータの概要は次のサイトを参照してください。
  • https://fukuno.jig.jp/1867
  • 音色編集は奥が深く、最初は何から手をつけたらよいか分かりません。YMF825は、4オペレータですが、最初は直列接続の2オペレータ(YMF825では、ALG=2)にして初段(モジュレータ)側の出力を0(YMF825では、TL=63)にし後段(キャリア)側のみ有効にして始めると分かりやすいようです。
  • 経験的に音量への影響度の大きなパラメータは、TL、SL、SR、DRなどです。
  • 音色は、倍音の構成で決まってきます。倍音への影響度の大きなパラメータは、MUL、WS、KSLなどです。このあたりが音色設定のキモでしょうね。
  • 今回、ワイングラスの音色を真似るために利用したのは、初期設定で「TENOR_SAX」をベースに編集しました。

編集前と編集後のパラメータの一覧

編集前と編集後のパラメータの一覧は次のようになります。
編集前と編集後のパラメータの一覧

「Edt」または「e1」~「e4」の項目が編集後、「Org」または「o1」~「o4」の項目が編集前の初期状態の値です。「Max」または「Mx」と書かれているのは、そのパラメータに設定できる最大値です。最小値は、どのパラメータも0です。
(編集画面上でも、右側の方に編集前の初期値と設定できる最大値の項目があります)

余談

この作品は、「手持ちのワイングラスの音色を楽器にしてMIDI演奏する」をテーマとして紹介しましたが、回路とプログラムは、色々な音出しの実験を兼ねています。
本テーマの以外に次のようなことができます。(ご参考)
MIDI-OUTにポケットミク(またはeVY1)を接続してミクの音声を外してMIDI演奏(16音源16和音、GM対応)、ミクの音声で演奏、ミクの音声で百人一首読み上げ、AquesTalkPicoを使った音声出力、DFPlayerを利用したSDカードのmp3ファイルの再生などです。
(ポケットミク、または、eVY1は、USBインターフェースなので、MIDI-OUTに接続するにはUSB MIDIコンバーターが必要です)

プログラム

  • プログラムはすべてMicroPythonですが、PS/2キーボードとPS/2マウスのドライバの一部はPicoのPIO(機械語)を利用しています。
  • MicroPythonコードの一部が、PIO(機械語)対応になっています。

PicoMainプログラム

PicoM_main_py.py

PicoM_main_py.py

############################################################################# # PicoM_main_py.py Programed by Hyodo # PicoMainに「main.py」として保存するか、Thonnyからこのプログラムを実行する。 # # ps2KeyBoard と PicoMain との接続 ps2KeyBoard # <<< Pico >>> レベル変換 USB-A USB-A # (メス) (オス) # gpio-No (pin) 3V 5V GND (4) | | # gpio-13 (17)---clock -- 青------------- LV2 HV2 --- D+ --(3)--| | # gpio-12 (16)---data -- 緑------------- LV1 HV1 --- D- --(2)--| | # +5V (1) |___| # (TopView) # # ps2Mouse と PicoMain との接続 ps2Mouse # <<< Pico >>> 74HC07 レベル変換 USB-A USB-A # (バッファ) (メス) (オス) # gpio-No (pin) 3V 5V GND (4) | | # gpio-27 (32)---clock -- 青------+------ LV4 HV4 --- D+ --(3)--| | # gpio-26 (31)---data -- 緑----- | -+--- LV3 HV3 --- D- --(2)--| | # | | +5V (1) |___| # gpio-21 (27)----(13) ▷ (12)-----+ | (TopView) # gpio-20 (26)----(11) ▷ (10)--------+ # # # ST7789 との接続 # <<< Pico >>> <<< ST7789 >>> # gpio-No (pin) (pin) # gpio-6 ( 9) ----赤---- (7) RT # gpio-7 (10) ----青---- (8) DC # gpio-8 MISO (11) ----緑---- (5) SD # gpio-9 CE (12) ----黄---- (6) CS # gpio-10 CKL (14) ----白---- (3) CK # gpio-11 MOSI (15) ----紫---- (4) SI # 3.3V ----赤---- (1) V # GND ----白---- (2) G # # # RFID-RC522 との接続 # <<< Pico >>> <<< RFID-RC522 >>> # gpio-No (pin) (pin) # gpio-22 (29) ----紫---- (7) RST # 3.3V ----灰---- (8) 3V3 # gpio-19 MOSI (24) ----橙---- (3) MOSI # gpio-18 SKL (23) ----赤---- (2) SCK # GND ----青---- (6) GND # gpio-17 CE (21) ----茶---- (1) SDA-CE # gpio-16 MISO (20) ----黄---- (4) MISO # pull-up 10K No Connect--緑---- (5) IRQ # # # # PicoMain と PicoSub との接続 # <<< PicoMain >>> <<< PicoSub >>> # gpio-No (pin) (pin) # 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 # # # MIDI-OUT側に、ポケットミク、または、eVY1 を接続する場合 # ポケット・ミクは、Channel 0 がミクの音声固定になっている。(GM音源指定を無視する) # ミクの音声ではなく楽器に割り当てて演奏するために、機能追加として # Channel 1(ミクの音声になる)を 別のチャンネル(Swapping Ch)に割り当てて # MIDI-OUTに出力する機能(Play MIDI)を用意した。 # Swapping Chは、MIDI信号が無音のチャンネルを指定する。 # 発音のあるチャンネルだとミクの音声に変換されて発音されるので注意。 # # Channel 1 ------------ --- Channel 1(ミクの音声になる) # X # Swapping Ch(無音) --- --- Swapping Ch(GM TONE指定) # # そのチャンネルの音源を GM TONE NO 1-128 で指定できるようにした。 # GM TONE NO 1-128 以外を指定すると、Grand Pianoにする。 # 但し、MIDI信号の中に「プログラムチェンジ」=音色変更があれば、それに従うので留意。 # ############################################################################# from machine import Timer, SPI, UART, Pin import time import utime import uos # from micropython import const # メモリ使用状況 micropython.mem_info() を表示させるため、すべてをインポート import micropython from mfrc522 import MFRC522 import ymf825py as ymf825 import midipy2 as midi import mojipy as moji import st7789py as st7789 from fonts import vga2_8x8 as font1 from fonts import vga1_16x32 as font2 from ps2mus import PS2MouseCommand from ps2mus import PS2MouseRecive from ps2kb3 import PS2KeyRecive ############################################################################### # 上記インポートファイルは、予め、Picoに書き込んでおくこと # Thonnyで 当該ファイルを開いて、Picoに書き込む。 # 直下に # ps2mus.py : PS2Mouse 接続用 # ps2kb3.py : PS2Keyboard 接続用 # mfrc522.py : RFID-RC522 接続用 # ymf825py.py : YMF825 接続用 # midipy2.py : MIDI 接続用 # mojipy.py : 文字処理用 # st7789py.py : ST7789 TFT用 # <<< fonts フォルダ下に >>> # vga1_16x32.py: ST7789用フォント1 # vga2_8x8.py : ST7789用フォント2 Non Use ############################################################################### # 20240813 百人一首用に設定 HectOne = [ # address, VoiceRome, OctKey, Velocity, onTime, offTime # adr, voi, key, vel, ont, oft # Title ['Ad', 'Voi', 'Key', 'Vel', 'oN', 'oF'], ['A1', 'a', '4C', 90, 3, 0], ['A2', 'ma', '4D', 90, 5, 0], ['A3', 'no', '4D', 90, 5, 0], ['A4', 'ha', '4D', 90, 5, 0], ['A5', 'ra', '4D', 90, 6, 3], # ['B1', 'hu', '4D', 90, 3, 0], ['B2', 'ri', '4F', 90, 5, 0], ['B3', 'sa', '4F', 90, 5, 0], ['B4', 'ke', '4F', 90, 5, 0], ['B5', 'mi', '4D', 90, 5, 0], ['B6', 're', '4D', 90, 5, 0], ['B7', 'ba', '4C', 90, 6, 3], # ['C1', 'ka', '4D', 90, 4, 0], ['C2', 'su', '4D', 90, 5, 0], ['C3', 'ga', '3A', 90, 5, 0], ['C4', 'na', '3A', 90, 5, 0], ['C5', 'ru', '3A', 90, 6, 3], # ['D1', 'mi', '4D', 90, 3, 0], ['D2', 'ka', '4F', 90, 5, 0], ['D3', 'sa', '4F', 90, 5, 0], ['D4', 'no', '4F', 90, 5, 0], ['D5', 'ya', '4F', 90, 5, 0], ['D6', 'ma', '4F', 90, 5, 0], ['D7', 'ni', '4F', 90, 6, 3], # ['E1', 'i', '4G', 90, 3, 0], ['E2', 'de', '4G', 90, 5, 0], ['E3', 'si', '4G', 90, 5, 0], ['E4', 'tu', '4G', 90, 5, 0], ['E5', 'ki', '4G', 90, 5, 0], ['E6', 'ka', '4F', 90, 5, 0], ['E7', 'mo', '4G', 90, 9, 0], ] HectOneVoice = [ # 01 tenchitennno- ['akinotano','karihonoiono', 'tomawoarami', 'wagakoromodeha', 'tuyuninuretutu'], # 02 jito-tennno- ['harusugite', 'natukinikerasi', 'sirotaeno', 'koromohosutyo', 'amanokaguyama'], # 03 kakinomotonmo hitomaro ['asibikino', 'yamadorinoono', 'sidariono', 'naganagasiyowo', 'hitorikamonenn'], # 04 yamabeno akahito ['tagonoura', 'utidetemireba', 'sirotaeno', 'fujinotakaneni', 'yukihafuritutu'], # 05 sarumaru dayu- ['okuyamani', 'momijikakiwake', 'nakusikano', 'koekikutokizo', 'akihakanasiki'], # 06 tyuunagionn nakamoti ['kasasagino', 'wataseruhasini', 'okusimono', 'sirokiwomireba', 'yozofukenikeru'], # 07 ['amanohara', 'furisakemireba', 'kasuganaru', 'mikasanoyamani', 'idesitukikamo'], # 08 ['', '', '', '', ''], # 09 ['', '', '', '', ''], # 10 ['', '', '', '', ''], # 11 ['', '', '', '', ''], # 12 ['', '', '', '', ''], # 13 ['', '', '', '', ''], # 14 ['', '', '', '', ''], # 15 ['', '', '', '', ''], ] ST7789_COL_SIZE = const(15) # st7789 Col Size 20240714 Adj 16->15 TONE_NAME_SIZE = const(15) # Tone Name Size CURSOL_MAX = const(15) # = Tone Name Size DOT_R = const(32) # charactor Dot size High = Row DOT_C = const(16) # charactor Dot size Width = colum RFID_OK = const(0) uartRespT = Pin(2, Pin.OUT) # Low TRUE uartRespT.value(1) uartRespR = Pin(3, Pin.IN) # Low TRUE # ST7789 SPI(1) default pins spi1_sck = const(10) spi1_mosi = const(11) spi1_miso = const(8) # not use # 20240418 Change # st7789_res = const(12) # st7789_dc = const(13) st7789_res = const(6) st7789_dc = const(7) st7789_cs = const(9) disp_width = const(240) disp_height = const(240) CENTER_Y = int(disp_width/2) CENTER_X = int(disp_height/2) # 20240723 Copy from ymf825py.py ここから # 配列の上限 ROW_SIZE = const(10) # 行の最大 COL_SIZE = const(10) # 列の最大 # 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) # 20240723 Copy from ymf825py.py ここまで # st7789 表示枠の大きさ DSP_ROW_SIZE = const(5) # 表示行の大きさ DSP_COL_SIZE = const(4) # 表示列の大きさ TONE_MENU_COL_NUM = const(2) # number of tones menu TONE_MENU_ROW_NUM = const(17) # number of tones menu TONE_TABLE_COL_NUM = const(2) # number of tones menu TONE_TABLE_ROW_NUM = const(17) # number of tones menu FUNCTION_COL_NUM = const(2) # Fxx FunctionName FUNCTION_ROW_NUM = const(13) # Index + F1 ~ F12 FunctionName = [None] * (FUNCTION_ROW_NUM) FunctionName[0] = ' Function' # Title FunctionName[1] = 'Edit Tone' # F1 FunctionName[2] = 'Read RFID' # F2 FunctionName[3] = 'Write RFID' # F3 FunctionName[4] = 'Play MIDI' # F4 FunctionName[5] = 'DFP(mp3)Test' # F5 FunctionName[6] = 'Edt Tn Table' # F6 FunctionName[7] = 'Edt Mk Voice' # F7 FunctionName[8] = '' # F8 FunctionName[9] = '' # F9 FunctionName[10] = '' # F10 FunctionName[11] = '' # F11 FunctionName[12] = '' # F12 # FunctionTable の生成 FunctionTable = [None] * FUNCTION_ROW_NUM # 13 for i in range(FUNCTION_ROW_NUM): FunctionTable[i] = [None] * FUNCTION_COL_NUM # 2 for i in range(FUNCTION_ROW_NUM): FunctionTable[i][0] = i FunctionTable[i][1] = FunctionName[i] SubMenu = [None] *7 for i in range(7): SubMenu[i] = '' AlarmMsg = [None] *7 for i in range(7): AlarmMsg[i] = '' InputMsg = [None] *7 for i in range(7): InputMsg[i] = '' # clorFont, Msg EditMsg = [None] *7 for i in range(7): EditMsg[i] = [None] *2 for i in range(7): EditMsg[i][0] = st7789.WHITE EditMsg[i][1] = '' # PS2 Keyboard PIO Pin設定 # 5V ⇔ 3.3V レベル変換回路入れること(Key側:5V、Pico側:3V) KB_DATA = const(12) # PS2 keyboard data GPIO-12 KB_CLOCK = const(13) # PS2 keyboard clock GPIO-13 KB_PIO_FRQ = const(1000000) # PS2 Keyboard 設定 kb_freq = KB_PIO_FRQ kb_data = Pin(KB_DATA, Pin.IN, Pin.PULL_UP) # PS2 Keyboard Data kb_clock = Pin(KB_CLOCK, Pin.IN, Pin.PULL_UP) # PS2 Keyboard Clock # PS2 Mouse PIO Pin設定 # 5V ⇔ 3.3V レベル変換回路入れること(Key側:5V、Pico側:3V) RCV_DATA = const(26) # PS2 mouse data 入力 GPIO-26 RCV_CLOCK = const(27) # PS2 mouse clock 入力 GPIO-27 SEND_DATA = const(20) # 出力 GPIO-20 バッファを介して GPIO-26 に接続 SEND_CLOCK = const(21) # 出力 GPIO-21 バッファを介して GPIO-27 に接続 # PIO PS/2 Mouse 動作周波数 ps2mus.py PS2KeyRecive PIO 動作周波数:1MHz # PIO_KB_FRQ = const(1000000) MUS_PIO_FRQ = const(1000000) # PS2 Mouse 設定 pio_freq = MUS_PIO_FRQ rcv_data = Pin(RCV_DATA, Pin.IN, Pin.PULL_UP) # PS2 Mouse Recive Data rcv_clock = Pin(RCV_CLOCK, Pin.IN, Pin.PULL_UP) # PS2 Mouse Recive Clock send_data = Pin(SEND_DATA, Pin.OUT) # PS2 Mouse Send Data send_clock = Pin(SEND_CLOCK, Pin.OUT) # PS2 Mouse Send Clock # PS2MouseCommand ドライバ および StateMachine の設定と起動 ---------------------- ps2mus_cmd = PS2MouseCommand(pio_freq, send_data, send_clock, rcv_data, rcv_clock) ################################################################################## # PS2MouseCommand ドライバの起動・・・ここでは、まだ、行わない # ps2mus_cmd.set_active() ############################################################ # PS2MouseRecive ドライバ および StateMachine の設定と起動 ---------------------- ps2mus_rcv = PS2MouseRecive(pio_freq, rcv_data, rcv_clock) ################################################################################## # PS2MouseRecive ドライバの起動とタイマー設定・・・ここでは、まだ、行わない # ps2mus_rcv.set_active() ############################################################ # 1Frame Time の設定 # マウスを連続して動かすと、12ms周期くらいでデータ送信してくる。 # 何もない時間が 4ms続けば区切りとして、インターラプトを発生させる。 # 4ms:(1MHz*1ms*1000us)/PIOクロック数 2 # time_out = int((MUS_PIO_FRQ * 4) / (1000 * 2)) ############################################################ # 時分割処理のためのタイマー # global変数定義。関数で利用するグローバル変数は、関数の定義前に書くのが無難。 uart_timer = 0 # UART RTS CTS Timer # 10ms 毎に割り込みが発生する なぜか引数 (t) は必須である。 def every10ms(t): ########################################################## global uart_timer ########################################################## if uart_timer < 10: uart_timer = 0 else: uart_timer -= 10 # 20240416 10ms # 10ms 毎に every10ms を呼び出す呪文。これ以前に callback関数を定義のこと。 # Timer(period=10, mode=Timer.PERIODIC, callback=every10ms) # mode=Timer.PERIODIC は、指定しなくても大丈夫のようだ。 # xxx Timer(period=10, callback=every10ms) でも動作するが # MicroPython説明サイトに従ったタイマーの初期化 tim10 = Timer(period=10, mode=Timer.PERIODIC, callback=every10ms) tim10.init(period=10, callback=every10ms) # 97ms 毎に割り込みが発生する なぜか引数 (t) は必須である。 def every97ms(t): if midi.stop == 0 and midi.end == 0: # PS2Keyboard 「Esc」キーのみ受け付ける # ファンクション・キー入力なら if ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) midi.stop = 1 # midi_play() に停止を送信 # MicroPython説明サイトに従ったタイマーの初期化 tim97 = Timer(period=97, mode=Timer.PERIODIC, callback=every97ms) tim97.init(period=97, callback=every97ms) timer997sw = 0 backColor = st7789.RED # 編集箇所をわかりやすくするため、背景色を白と黄色にする仕掛け # 997ms 毎に割り込みが発生する なぜか引数 (t) は必須である。 def every997ms(t): global timer997sw, backColor if timer997sw == 0: backColor = st7789.WHITE timer997sw = 1 else: backColor = st7789.YELLOW timer997sw = 0 # MicroPython説明サイトに従ったタイマーの初期化 tim997 = Timer(period=997, mode=Timer.PERIODIC, callback=every997ms) tim997.init(period=997, callback=every997ms) ####################################################################### # HandShake Send RTS & Recive CTS Cross Connection # PicoMain と PicoSub との接続 # <<< PicoMain >>> <<< 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) 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(tone_num): print('setToneDataPicoSub(tone_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') # ToneEdit をシリアル出力 # 20240727 Comment Out # ymf825.serialOutToneData(tone_num) # ToneVoice をシリアル出力 ymf825.copyTone2_Voice(tone_num) ymf825.serialOutVoiceData(tone_num) # Tone_Com_Edit, Tone_Op_Edit を ASCII2文字の send_buffに変換 ymf825.takeOutToneData(tone_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) ####################################################################### 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) ####################################################################### # PicoSubに接続された PrintDFP用の mp3再生メッセージ # 先頭に %DFP コマンド 末尾に \n改行 def setDFP_PicoSub(command): print('setDFP_PicoSub(buffDFP)') # 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') # commandを UARTで PicoSubに送出 commandDFP = '%DFP '+ command + '\n' print('PrintDFP Command = ', commandDFP) print(f'ymf825.uart_write_multi({commandDFP})') ####################################################### ymf825.uart_write_multi(commandDFP) ####################################################### 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) ####################################################################### # line_n(0-6)で、画面上の編集行を指定する。 # new_name = editName(EditMsg, line_n, old_name) def editName(EditMsg, line_n, old_name): line_n = line_n % 7 # 表示枠外に出ないよう規制 # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(old_name, TONE_NAME_SIZE) temp_name = new_name # ST7789 画面をクリア display.fill(st7789.BLACK) # 編集画面を表示、文字色指定あり col_n = 0 for i in range(7): if len(EditMsg[i][1]) > 0: # DOT_C = 16 : col_n , DOT_R = 32 : line_n display.text(font2, EditMsg[i][1],\ DOT_C * col_n, DOT_R * i, EditMsg[i][0]) # 編集行全体を表示 col_n = 0 # DOT_C = 16 : col_n , DOT_R = 32 : line_n display.text(font2, moji.strFixL_n(new_name, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, st7789.WHITE) # 初期表示・カーソル now_cursol = 0 # now_cursol 文字 表示 cursol_data = new_name[now_cursol] col_n = now_cursol # DOT_C = 16 : col_n , DOT_R = 32 : line_n display.text(font2, cursol_data,\ DOT_C * col_n, DOT_R * line_n, st7789.RED, st7789.WHITE) old_cursol = now_cursol # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 while True: # 文字入力 または カーソル移動があれば表示する # Enter または Esc で終了 if temp_name != new_name or old_cursol != now_cursol: # 編集行全体を表示 col_n = 0 display.text(font2, moji.strFixL_n(new_name, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, st7789.WHITE) # now_cursol 文字 表示 cursol_data = new_name[now_cursol] col_n = now_cursol display.text(font2, cursol_data,\ DOT_C * col_n, DOT_R * line_n, st7789.RED, st7789.WHITE) temp_name = new_name old_cursol = now_cursol # PS2Keyboard # 1文字・記号入力なら if ps2key.rcv_size() == 1: ps2key_data = ps2key.get_code() # if now_cursol >= 0 and now_cursol < TONE_NAME_SIZE: # 0-14 ############################################################ # 挿入モードで編集(表示) temp_name = new_name[:] # copy new_name = temp_name[: now_cursol] + ps2key_data + temp_name[now_cursol:TONE_NAME_SIZE -1] ############################################################ old_cursol = now_cursol now_cursol += 1 # ファンクション・キー入力なら elif ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) new_name = moji.strFixL_n(old_name, TONE_NAME_SIZE) break elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) break elif ps2key_data.lower() == "BS".lower(): msg_f = "BS" print(msg_f) if now_cursol > 0 and now_cursol < TONE_NAME_SIZE: # 1-14 temp_name = new_name[:] # copy new_name = temp_name[: now_cursol -1] + temp_name[now_cursol:TONE_NAME_SIZE] + ' ' now_cursol -= 1 elif ps2key_data.lower() == "Del".lower(): msg_f = "Del" print(msg_f) if now_cursol >= 0 and now_cursol < TONE_NAME_SIZE: # 0-14 temp_name = new_name[:] # copy new_name = temp_name[: now_cursol] + temp_name[now_cursol +1:TONE_NAME_SIZE] + ' ' elif ps2key_data.lower() == "Arw_L".lower(): # ← msg_f = "ArwL" print(msg_f) if now_cursol > 0 and now_cursol < (TONE_NAME_SIZE): # 1-14 old_cursol = now_cursol now_cursol -= 1 elif ps2key_data.lower() == "Arw_R".lower(): # → msg_f = "ArwR" print(msg_f) if now_cursol >= 0 and now_cursol < (TONE_NAME_SIZE -1): # 0-13 old_cursol = now_cursol now_cursol += 1 elif ps2key_data.lower() == "Space".lower(): # ' ' msg_f = "Space" print(msg_f) if now_cursol >= 0 and now_cursol < TONE_NAME_SIZE: # 0-14 temp_name = new_name[:] # copy new_name = temp_name[: now_cursol] + ' ' + temp_name[now_cursol:TONE_NAME_SIZE -1] old_cursol = now_cursol now_cursol += 1 elif ps2key_data == "F1": msg_f = "F1" print(msg_f) # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt # 左クリック・ボタンが新たに押されたなら if busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) break # 右クリック・ボタンが新たに押されたなら elif busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) break # break でここに来る return new_name ####################################################################### # PrintMtxLED へのコマンド編集と UART送信 # 上段表示は、左から右へ、キャラクター(charU)が移動 # 下段表示は、右から左へ、キャラクター(charL)が移動 # 移動間隔時間を、timeで指定する。 def printMtxLedChr(charU, charL, time): # PrintMtxLED 画面消去 ymf825.uart_write_multi('%IJ.CLS\n') # % I J sp mtxled_header = [37, 73, 74, 32, ] mtxled_col = 4 mtxled_upper = [32] *mtxled_col mtxled_lower = [32] *mtxled_col mtxled_LF = [10] # LF \n for i in range(mtxled_col): mtxled_upper[i] = charU mtxled_lower[mtxled_col -i -1] = charL mtxledB = bytes(mtxled_header + mtxled_upper + mtxled_lower + mtxled_LF) # PrintMtxLED へシリアル送信 ymf825.uart_write_multi(mtxledB) # データを元に戻す mtxled_upper[i] = 32 mtxled_lower[mtxled_col -i -1] = 32 utime.sleep_ms(time) # PrintMtxLED 画面消去 # ymf825.uart_write_multi('%IJ.CLS\n') ####################################################################### # PrintMtxLED へのコマンド編集と UART送信 # 上段表示は、左から右へ、キャラクター(msgU)が移動 # 下段表示は、右から左へ、キャラクター(msgL)が移動 # 移動間隔時間を、timeで指定する。 def printMtxLedMsg(msgU, msgL, time): # PrintMtxLED 画面消去 ymf825.uart_write_multi('%IJ.CLS\n') # % I J sp mtxled_header = [37, 73, 74, 32, ] mtxled_col = 4 mtxled_upper = [32] *mtxled_col mtxled_lower = [32] *mtxled_col mtxled_LF = [10] # LF \n for i in range(mtxled_col): mtxled_upper[i] = msgU[i] mtxled_lower[i] = msgL[i] mtxledB = bytes(mtxled_header + mtxled_upper + mtxled_lower + mtxled_LF) # PrintMtxLED へシリアル送信 ymf825.uart_write_multi(mtxledB) utime.sleep_ms(time) # PrintMtxLED 画面消去 # utime.sleep_ms(1000) # ymf825.uart_write_multi('%IJ.CLS\n') ####################################################################### # PrintDFP へのコマンド編集と UART送信 # line_n(0-6)で、画面上の編集行を指定する。 def printDFP(EditMsg, line_n, old_name): line_n = line_n % 7 # 表示枠外に出ないよう規制 # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(old_name, TONE_NAME_SIZE) temp_name = new_name # ST7789 画面をクリア display.fill(st7789.BLACK) # 編集画面を表示、文字色指定あり col_n = 0 for i in range(7): if len(EditMsg[i][1]) > 0: # DOT_C = 16 : col_n , DOT_R = 32 : line_n display.text(font2, EditMsg[i][1],\ DOT_C * col_n, DOT_R * i, EditMsg[i][0]) # 編集行全体を表示 col_n = 0 # DOT_C = 16 : col_n , DOT_R = 32 : line_n display.text(font2, moji.strFixL_n(new_name, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, st7789.WHITE) # 初期表示・カーソル now_cursol = 0 # now_cursol 文字 表示 cursol_data = new_name[now_cursol] col_n = now_cursol # DOT_C = 16 : col_n , DOT_R = 32 : line_n display.text(font2, cursol_data,\ DOT_C * col_n, DOT_R * line_n, st7789.RED, st7789.WHITE) old_cursol = now_cursol # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 while True: # 文字入力 または カーソル移動があれば表示する # Enter または Esc で終了 if temp_name != new_name or old_cursol != now_cursol: # 編集行全体を表示 col_n = 0 display.text(font2, moji.strFixL_n(new_name, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, st7789.WHITE) # now_cursol 文字 表示 cursol_data = new_name[now_cursol] col_n = now_cursol display.text(font2, cursol_data,\ DOT_C * col_n, DOT_R * line_n, st7789.RED, st7789.WHITE) temp_name = new_name old_cursol = now_cursol # PS2Keyboard # 1文字・記号入力なら if ps2key.rcv_size() == 1: ps2key_data = ps2key.get_code() # if now_cursol >= 0 and now_cursol < TONE_NAME_SIZE: # 0-14 ############################################################ # 挿入モードで編集(表示) temp_name = new_name[:] # copy new_name = temp_name[: now_cursol] + ps2key_data + temp_name[now_cursol:TONE_NAME_SIZE -1] ############################################################ old_cursol = now_cursol now_cursol += 1 # ファンクション・キー入力なら elif ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) new_name = moji.strFixL_n(old_name, TONE_NAME_SIZE) break elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED charU = 0xEE charL = 0xEE time = 400 ####################################################### printMtxLedChr(charU, charL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data.lower() == "BS".lower(): msg_f = "BS" print(msg_f) if now_cursol > 0 and now_cursol < TONE_NAME_SIZE: # 1-14 temp_name = new_name[:] # copy new_name = temp_name[: now_cursol -1] + temp_name[now_cursol:TONE_NAME_SIZE] + ' ' now_cursol -= 1 elif ps2key_data.lower() == "Del".lower(): msg_f = "Del" print(msg_f) if now_cursol >= 0 and now_cursol < TONE_NAME_SIZE: # 0-14 temp_name = new_name[:] # copy new_name = temp_name[: now_cursol] + temp_name[now_cursol +1:TONE_NAME_SIZE] + ' ' elif ps2key_data.lower() == "Arw_L".lower(): # ← msg_f = "ArwL" print(msg_f) if now_cursol > 0 and now_cursol < (TONE_NAME_SIZE): # 1-14 old_cursol = now_cursol now_cursol -= 1 elif ps2key_data.lower() == "Arw_R".lower(): # → msg_f = "ArwR" print(msg_f) if now_cursol >= 0 and now_cursol < (TONE_NAME_SIZE -1): # 0-13 old_cursol = now_cursol now_cursol += 1 elif ps2key_data.lower() == "Space".lower(): # ' ' msg_f = "Space" print(msg_f) if now_cursol >= 0 and now_cursol < TONE_NAME_SIZE: # 0-14 temp_name = new_name[:] # copy new_name = temp_name[: now_cursol] + ' ' + temp_name[now_cursol:TONE_NAME_SIZE -1] old_cursol = now_cursol now_cursol += 1 elif ps2key_data == "F1": msg_f = "F1" print(msg_f) temp_name = new_name[:] new_name = 'PLAY 1 59' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # Hart msgU = [0xE5, 0xE5, 0xE5, 0xE5] # Hart msgL = [0xE5, 0xE5, 0xE5, 0xE5] time = 10 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F2": msg_f = "F2" print(msg_f) new_name = 'PLAY 1 55' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # Clover msgU = [0xE6, 0xE6, 0xE6, 0xE6] # Clover msgL = [0xE6, 0xE6, 0xE6, 0xE6] time = 10 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F3": msg_f = "F3" print(msg_f) new_name = 'PLAY 1 3' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # Spade msgU = [0xE4, 0xE4, 0xE4, 0xE4] # Spade msgL = [0xE4, 0xE4, 0xE4, 0xE4] time = 10 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(8000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F4": msg_f = "F4" print(msg_f) new_name = 'PLAY 1 4' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # Diamonds msgU = [0xE7, 0xE7, 0xE7, 0xE7] # Diamonds msgL = [0xE7, 0xE7, 0xE7, 0xE7] time = 10 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(8000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F5": msg_f = "F5" print(msg_f) new_name = 'PLAY 1 45' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED charU = 0xED charL = 0xED time = 400 ####################################################### printMtxLedChr(charU, charL, time) ####################################################### utime.sleep_ms(6000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F6": msg_f = "F6" print(msg_f) new_name = 'PLAY 1 50' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED charU = 0xFB charL = 0xFD time = 400 ####################################################### printMtxLedChr(charU, charL, time) ####################################################### utime.sleep_ms(6000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F7": msg_f = "F7" print(msg_f) new_name = 'PLAY 2 131' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # wa nn wa nn msgU = [0x20, 0xDC, 0xDD, 0x20] # msgL = [0x20, 0x20, 0x20, 0x20] time = 400 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F8": msg_f = "F8" print(msg_f) new_name = 'PLAY 2 141' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED charU = 0xEC charL = 0xEC time = 400 ####################################################### printMtxLedChr(charU, charL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F9": msg_f = "F9" print(msg_f) new_name = 'PLAY 2 231' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # ka ko msgU = [0xB6, 0xAF, 0xBA, 0x2D] # msgL = [0x20, 0x20, 0x20, 0x20] time = 10 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F10": msg_f = "F10" print(msg_f) new_name = 'PLAY 3 12' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED # ji " a ne msgU = [0xBC, 0xDE, 0xAC, 0xC8] # yo ro si ku msgL = [0xD6, 0xDB, 0xBC, 0xB8] time = 200 ####################################################### printMtxLedMsg(msgU, msgL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F11": msg_f = "F11" print(msg_f) new_name = 'PLAY 1 11' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED charU = 0xEF charL = 0xEF time = 400 ####################################################### printMtxLedChr(charU, charL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') elif ps2key_data == "F12": msg_f = "F12" print(msg_f) new_name = 'PLAY 1 12' old_cursol = now_cursol now_cursol = len(new_name) # 末尾にスペースを入れて15桁にする new_name = moji.strFixL_n(new_name, TONE_NAME_SIZE) # PrintDFP command = new_name.strip() setDFP_PicoSub(command) utime.sleep_ms(100) # PrintMtxLED charU = 0xF1 charL = 0xF1 time = 400 ####################################################### printMtxLedChr(charU, charL, time) ####################################################### utime.sleep_ms(4000) ymf825.uart_write_multi('%IJ.CLS\n') # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt # 左クリック・ボタンが新たに押されたなら if busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) # commandDFP = 'PRINT"%DFP '+ new_name.strip() + '"' commandDFP = '%DFP '+ new_name.strip() + '\n' print('PrintDFP Command = ', commandDFP) print(f'ymf825.uart_write_multi({commandDFP})') ####################################################### ymf825.uart_write_multi(commandDFP) ####################################################### # 右クリック・ボタンが新たに押されたなら elif busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) new_name = moji.strFixL_n(old_name, TONE_NAME_SIZE) break # break でここに来る return new_name ####################################################################### # 数文字入力。return値を、int(num)で、「数値」に変換できる。 # line_n(0-6)で、画面上の入力行を指定する。 # prompt は、入力行でのプロンプト(例 'ch ? ') # num_asc(文字列 ='000')は初期値、'000'を入力桁数のサイズとする。 # prompt の桁数と、num_asc の桁数合計が、st7789の桁数(15)を超えないこと。 def inputNum(InputMsg, line_n, prompt, num_asc): # line_n = line_n % 7 # 表示枠外に出ないよう規制 # prompt の桁数 try: if len(prompt) >= 1: prompt_size = len(prompt) else: prompt = '?' prompt_size = len(prompt) except: prompt = '?' prompt_size = len(prompt) # 念のため、文字列の先頭と末尾、および、文字間のスペースを取り除く num_asc = num_asc.replace(' ', '') # num_size = len(num_asc) の桁数内で編集する。最低でも1桁とする。 try: if len(num_asc) >= 1: num_size = len(num_asc) else: num_asc = '0' num_size = len(num_asc) except: num_asc = '0' num_size = len(num_asc) # 先頭にスペースを入れて num_size 桁にする old_num = moji.strFixR_n(str(int(num_asc)), num_size) new_num = old_num temp_num = new_num # ST7789 画面をクリア display.fill(st7789.BLACK) # InputMsg の表示 0行目〜6行目 for i in range(7): if len(InputMsg[i]) > 0: display.text(font2, moji.strFixL_n(InputMsg[i], ST7789_COL_SIZE), 0, \ DOT_R *i, st7789.WHITE) # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 # 表示位置変数の設定 col_n = 0 cursol = prompt_size + num_size -1 # 初期表示・全体 # DOT_C = 16 : col_n , DOT_R = 32 : line_n dsp_data = prompt + moji.strFixR_n(str(int(new_num)), num_size) display.text(font2, moji.strFixL_n(dsp_data, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, \ st7789.WHITE) # 初期表示・カーソル cursol_data = str(int(new_num) % 10) display.text(font2, cursol_data,\ DOT_C * cursol, DOT_R * line_n, \ st7789.RED, st7789.WHITE) while True: # 数字入力があれば表示する Enter または Esc で終了 if temp_num != new_num: col_n = 0 dsp_data = prompt + moji.strFixR_n(str(int(new_num)), num_size) display.text(font2, moji.strFixL_n(dsp_data, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, \ st7789.WHITE) cursol_data = str(int(new_num) % 10) display.text(font2, cursol_data,\ DOT_C * cursol, DOT_R * line_n, \ st7789.RED, st7789.WHITE) temp_num = new_num[:] # PS2Keyboard # 1文字・記号入力なら if ps2key.rcv_size() == 1: ps2key_data = ps2key.get_code() if ps2key_data >= '0' and ps2key_data <= '9': ####################################################### # 右詰め表示で編集 temp_num = new_num[:] # copy new_num += ps2key_data new_num = moji.strFixR_n(str(int(new_num)), num_size) ####################################################### # ファンクション・キー入力なら elif ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) new_num = moji.strFixR_n(str(int(old_num)), num_size) break elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) break elif ps2key_data.lower() == "BS".lower(): msg_f = "BS" print(msg_f) temp_num = new_num[:] # copy new_num = str(int(int(new_num) / 10)) new_num = moji.strFixR_n(str(int(new_num)), num_size) elif ps2key_data.lower() == "Del".lower(): msg_f = "Del" print(msg_f) temp_num = new_num[:] # copy new_num = str(int(int(new_num) / 10)) new_num = moji.strFixR_n(str(int(new_num)), num_size) # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt # 左クリック・ボタンが新たに押されたなら if busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) break # 右クリック・ボタンが新たに押されたなら elif busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) new_num = moji.strFixR_n(str(int(old_num)), num_size) break return new_num ####################################################################### # 数文字入力。return値を、int(num)で、「数値」に変換できる。 # line_n(0-6)で、画面上の入力行を指定する。末尾に tableの検索結果を表示するので 0-5 # prompt は、入力行でのプロンプト(例 'ch ? ') # num_asc(文字列 ='000')は初期値、'000'を入力桁数のサイズとする。 # prompt の桁数と、num_asc の桁数合計が、st7789の桁数(15)を超えないこと。 # 入力された整数で、tableを検索して、prompt の次の行に表示する。 def inputNumTable(InputMsg, table, line_n, prompt, num_asc): # line_n = line_n % 6 # 表示枠外に出ないよう規制 name_line = line_n +1 # tableの検索結果を表示する # prompt の桁数 try: if len(prompt) >= 1: prompt_size = len(prompt) else: prompt = '?' prompt_size = len(prompt) except: prompt = '?' prompt_size = len(prompt) # 念のため、文字列の先頭と末尾、および、文字間のスペースを取り除く num_asc = num_asc.replace(' ', '') # num_size = len(num_asc) の桁数内で編集する。最低でも1桁とする。 try: if len(num_asc) >= 1: num_size = len(num_asc) else: num_asc = '0' num_size = len(num_asc) except: num_asc = '0' num_size = len(num_asc) # 先頭にスペースを入れて num_size 桁にする old_num = moji.strFixR_n(str(int(num_asc)), num_size) new_num = old_num temp_num = new_num # ST7789 画面をクリア display.fill(st7789.BLACK) # InputMsg の表示 0行目〜6行目 for i in range(7): if len(InputMsg[i]) > 0: display.text(font2, moji.strFixL_n(InputMsg[i], ST7789_COL_SIZE), 0, \ DOT_R *i, st7789.WHITE) # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 # 20240725 Change # cnt_s = 0 new_num_int = int(new_num) cnt_s = new_num_int # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 # 表示位置変数の設定 col_n = 0 cursol = prompt_size + num_size -1 # 初期表示・全体 # DOT_C = 16 : col_n , DOT_R = 32 : line_n dsp_data = prompt + moji.strFixR_n(str(int(new_num)), num_size) display.text(font2, moji.strFixL_n(dsp_data, ST7789_COL_SIZE),\ DOT_C * col_n, DOT_R * line_n, \ st7789.WHITE) # 初期表示・カーソル cursol_data = str(int(new_num) % 10) display.text(font2, cursol_data,\ DOT_C * cursol, DOT_R * line_n, \ st7789.RED, st7789.WHITE) while True: # 数字入力があれば表示する Enter または Esc で終了 if temp_num != new_num: col_n = 0 dsp_data = prompt + moji.strFixR_n(str(int(new_num)), num_size) display.text(font2, moji.strFixL_n(dsp_data, ST7789_COL_SIZE),\ DOT_C * col_n,\ DOT_R * line_n,\ st7789.WHITE) # GmName表示 table の有効範囲に限定 if new_num_int > 0 and new_num_int < len(table): ######################################## dsp_data = table[new_num_int] ######################################## display.text(font2, moji.strFixL_n(dsp_data, ST7789_COL_SIZE),\ DOT_C * col_n,\ DOT_R * name_line,\ st7789.WHITE) else: dsp_data = '' display.text(font2, moji.strFixL_n(dsp_data, ST7789_COL_SIZE),\ DOT_C * col_n,\ DOT_R * name_line,\ st7789.WHITE) # cursol_data 1文字を赤文字/白背景で表示する cursol_data = str(int(new_num) % 10) display.text(font2, cursol_data,\ DOT_C * cursol,\ DOT_R * line_n,\ st7789.RED, st7789.WHITE) temp_num = new_num[:] # PS2Keyboard # 1文字・記号入力なら if ps2key.rcv_size() == 1: ps2key_data = ps2key.get_code() if ps2key_data >= '0' and ps2key_data <= '9': ####################################################### # 右詰め表示で編集 temp_num = new_num[:] # copy new_num += ps2key_data new_num = moji.strFixR_n(str(int(new_num)), num_size) ####################################################### new_num_int = int(new_num) # 整数にする # マウス座標・現在地を更新 スクロールカウント ps2mus_rcv.set_cnt(cnt_x, cnt_y, new_num_int) ####################################################### # ファンクション・キー入力なら elif ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) new_num = moji.strFixR_n(str(int(old_num)), num_size) break elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) break elif ps2key_data.lower() == "BS".lower(): msg_f = "BS" print(msg_f) temp_num = new_num[:] # copy new_num = str(int(int(new_num) / 10)) new_num = moji.strFixR_n(str(int(new_num)), num_size) elif ps2key_data.lower() == "Del".lower(): msg_f = "Del" print(msg_f) temp_num = new_num[:] # copy new_num = str(int(int(new_num) / 10)) new_num = moji.strFixR_n(str(int(new_num)), num_size) # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt print('cnt_s = ', cnt_s) # スクロールが変化しているなら if cnt_s != new_num_int: ####################################################### # 右詰め表示で編集 cnt_s で更新 temp_num = new_num[:] # copy new_num = moji.strFixR_n(str(cnt_s), num_size) ####################################################### new_num_int = int(new_num) # 整数にする # 左クリック・ボタンが新たに押されたなら elif busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) break # 右クリック・ボタンが新たに押されたなら elif busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) new_num = moji.strFixR_n(str(int(old_num)), num_size) break return new_num ####################################################################### # ymf825 def selectTone(num): をベースに、マウスとキーボード入力に変更 # Tone情報を、メモリから読み出す場所(tone_num) # または、Tone情報を、メモリに保存する場所(tone_num)を指定する # 初期値として numとして与え、デフォルトの位置とする # dsp_msg は、画面の表題表示する内容 # return は、tone_name のみとし、SysRq は global変数とする def selectTone(dsp_msg, num): tone_num = num & 0x0F # 0 - 15 tone_num_old = tone_num tone_num_now = tone_num # SysRq は結果を returnするのではなく、global変数として扱う global SysRq SysRq = 0 # SysRq キーは押されていない # 4 10 # ymf825.Voice_Op_Edit # 4 4 # ymf825.Voice_Com_Edit # 4 2 # ymf825.ToneMenuTable if DSP_COL_SIZE < TONE_MENU_COL_NUM: dsp_col_max = DSP_COL_SIZE else: dsp_col_max = TONE_MENU_COL_NUM -1 # 5 18 # ymf825.Voice_Op_Edit # 5 4 # ymf825.Voice_Com_Edit # 5 17 # ymf825.ToneMenuTable if DSP_ROW_SIZE < TONE_MENU_ROW_NUM: dsp_row_max = DSP_ROW_SIZE else: dsp_row_max = TONE_MENU_ROW_NUM -1 # 与えられた tone_num に表示を合わせるため cell_y home_y を求める # cell_y を計算 cell_y = tone_num +1 # tone_num:0-15 ==> cell_y:1-16 # home_y を計算 if cell_y <= DSP_ROW_SIZE: home_y = 1 # 表示エリアホーム y else: home_y = cell_y - DSP_ROW_SIZE +1 cell_x = 1 # 列 home_x = 1 # 表示エリアホーム x display.fill(st7789.BLACK) # 「Menu」表示内容 関数呼び出し時に dsp_msg = 'Select Tone' などと指定する display.text(font2, moji.strFixL_n(dsp_msg, ST7789_COL_SIZE), \ 16*0, 32*0, st7789.YELLOW) # 画面2行目に、セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 画面2行目に、列タイトルの表示 [Select Tone] for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(ymf825.ToneMenuTable[0][j], 12), \ 16*3 + 16*3*(j - home_x), 32, st7789.CYAN) # 行タイトルの表示 [ 0] [ 1] [ 2] ... for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.int2str_n(ymf825.ToneMenuTable[i][0], 2), \ 0, 32*2 + 32*(i - home_y), st7789.CYAN) # ymf825.ToneMenuTable データの表示 for i in range(home_y, home_y + dsp_row_max): for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(ymf825.ToneMenuTable[i][j], 12), \ 16*3 + 16*3*(j - home_x), \ 32*2 + 32*(i - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする display.text(font2, moji.strFixL_n(ymf825.ToneMenuTable[cell_y][cell_x], 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 col = 0 row = 0 col_old = col row_old = row while True: # SysRq Enter または Esc で終了 if home_y_old != home_y: # 行タイトルの表示 [ 0] [ 1] [ 2] ... for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.int2str_n(ymf825.ToneMenuTable[i][0], 2), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # ymf825.ToneMenuTable データの表示 for i in range(home_y, home_y + dsp_row_max): for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(ymf825.ToneMenuTable[i][j], 12), \ 16*3 + 16*3*(j - home_x), \ 32*2 + 32*(i - home_y), st7789.WHITE) if cell_y_old != cell_y: # 画面2行目に、セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 直前のセル表示を [WHITE] に戻す display.text(font2, moji.strFixL_n(ymf825.ToneMenuTable[cell_y_old][cell_x_old], 12), \ 16*3 + 16*3*(cell_x_old - home_x), \ 32*2 + 32*(cell_y_old - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする display.text(font2, moji.strFixL_n(ymf825.ToneMenuTable[cell_y][cell_x], 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) if cell_y_old != cell_y or home_y_old != home_y: cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x # PS2Keyboard # 入力は Arw_U:「↑」 Arw_D:「↓」 「Enter」 「Esc」キーのみ受け付ける # ファンクション・キー入力なら if ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "PrtSc".lower(): msg_f = "PrtSc = SysRq" print(msg_f) tone_num = tone_num_old ################################################### SysRq = 1 # PrtSc を SysRq として扱う ################################################### break elif ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) tone_num = tone_num_old break elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) tone_num = cell_y -1 # 0-15 break elif ps2key_data.lower() == "Arw_U".lower(): # ↑ msg_f = "ArwU" print(msg_f) if cell_y > 1 and cell_y < (TONE_MENU_ROW_NUM): # 2-16 cell_y_old = cell_y cell_y -= 1 # Table表示位置を調整(home_y の計算) if cell_y < home_y: home_y_old = home_y home_y = cell_y elif ps2key_data.lower() == "Arw_D".lower(): # ↓ msg_f = "ArwD" print(msg_f) if cell_y > 0 and cell_y < (TONE_MENU_ROW_NUM -1): # 1-15 cell_y_old = cell_y cell_y += 1 # Table表示位置を調整(home_y の計算) if cell_y > (home_y + (dsp_row_max -1)): home_y_old = home_y home_y = cell_y - (dsp_row_max -1) elif ps2key_data == "F1": msg_f = "F1" print(msg_f) # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt # 左クリック、右クリック、ともに押されていないなら if busy_l == 0 and busy_r == 0: # マウスの座標の差分を取り出し、ArwD、ArwU キーと同じように扱う # 列 if cnt_x > 50: col_direc = 1 elif cnt_x < -50: col_direc = -1 else: col_direc = 0 # 行 if cnt_y < -50: row_direc = 1 elif cnt_y > 50: row_direc = -1 else: row_direc = 0 # 差分だけ取り出すので、クリア cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) if row_direc == 1: # ↓ msg_f = "Down" print(msg_f) if cell_y > 0 and cell_y < (TONE_MENU_ROW_NUM -1): # 1-15 cell_y_old = cell_y cell_y += 1 # Table表示位置を調整(home_y の計算) if cell_y > (home_y + (dsp_row_max -1)): home_y_old = home_y home_y = cell_y - (dsp_row_max -1) elif row_direc == -1: # ↑ msg_f = "Up" print(msg_f) if cell_y > 1 and cell_y < (TONE_MENU_ROW_NUM): # 2-16 cell_y_old = cell_y cell_y -= 1 # Table表示位置を調整(home_y の計算) if cell_y < home_y: home_y_old = home_y home_y = cell_y # 左クリック・ボタンが新たに押されたなら if busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) tone_num = cell_y -1 # 0-15 break # 右クリック・ボタンが新たに押されたなら elif busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) tone_num = tone_num_old break utime.sleep_ms(100) return tone_num ####################################################################### # 処理メニューの選択 # 初期値として numとして与え、デフォルトの位置とする # dsp_msg は、画面の表題表示する内容 # return は、tone_name のみとし、SysRq は global変数とする def selectFunction(dsp_msg, num): function_num = num % FUNCTION_ROW_NUM # 0 - 12 function_num_old = function_num function_num_now = function_num # SysRq は結果を returnするのではなく、global変数として扱う global SysRq SysRq = 0 # SysRq キーは押されていない # 4 10 # ymf825.Voice_Op_Edit # 4 4 # ymf825.Voice_Com_Edit # 4 2 # ymf825.ToneMenuTable # 4 2 # FunctionTable if DSP_COL_SIZE < FUNCTION_COL_NUM: dsp_col_max = DSP_COL_SIZE else: dsp_col_max = FUNCTION_COL_NUM -1 # 5 18 # ymf825.Voice_Op_Edit # 5 4 # ymf825.Voice_Com_Edit # 5 17 # ymf825.ToneMenuTable # 5 13 # FunctionTable if DSP_ROW_SIZE < FUNCTION_ROW_NUM: dsp_row_max = DSP_ROW_SIZE else: dsp_row_max = FUNCTION_ROW_NUM -1 # 与えられた function_num に表示を合わせるため cell_y home_y を求める # cell_y を計算 cell_y = function_num # function_num:1-12 ==> cell_y:1-12 # home_y を計算 if cell_y <= DSP_ROW_SIZE: home_y = 1 # 表示エリアホーム y else: home_y = cell_y - DSP_ROW_SIZE +1 cell_x = 1 # 列 home_x = 1 # 表示エリアホーム x display.fill(st7789.BLACK) # 「Menu」表示内容 関数呼び出し時に dsp_msg = 'Select Function' などと指定する display.text(font2, moji.strFixL_n(dsp_msg, ST7789_COL_SIZE), \ 16*0, 32*0, st7789.MAGENTA, st7789.YELLOW) # 画面2行目に、セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 画面2行目に、列タイトルの表示 [Select Tone] for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(FunctionTable[0][j], 12), \ 16*3 + 16*3*(j - home_x), 32, st7789.CYAN) # 行タイトルの表示 [ 0] [ 1] [ 2] ... for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.int2str_n(FunctionTable[i][0], 2), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # FunctionTable データの表示 for i in range(home_y, home_y + dsp_row_max): for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(FunctionTable[i][j], 12), \ 16*3 + 16*3*(j - home_x), \ 32*2 + 32*(i - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする display.text(font2, moji.strFixL_n(FunctionTable[cell_y][cell_x], 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 col = 0 row = 0 col_old = col row_old = row while True: # if home_y_old != home_y: # 行タイトルの表示 [ 0] [ 1] [ 2] ... for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.int2str_n(FunctionTable[i][0], 2), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # FunctionTable データの表示 for i in range(home_y, home_y + dsp_row_max): for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(FunctionTable[i][j], 12), \ 16*3 + 16*3*(j - home_x), \ 32*2 + 32*(i - home_y), st7789.WHITE) if cell_y_old != cell_y: # 画面2行目に、セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 直前のセル表示を [WHITE] に戻す display.text(font2, moji.strFixL_n(FunctionTable[cell_y_old][cell_x_old], 12), \ 16*3 + 16*3*(cell_x_old - home_x), \ 32*2 + 32*(cell_y_old - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする display.text(font2, moji.strFixL_n(FunctionTable[cell_y][cell_x], 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) if cell_y_old != cell_y or home_y_old != home_y: cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x # PS2Keyboard # 入力は Arw_U:「↑」 Arw_D:「↓」 「Enter」 「Esc」キーのみ受け付ける # ファンクション・キー入力なら if ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "PrtSc".lower(): msg_f = "PrtSc = SysRq" print(msg_f) function_num = function_num_old ################################################### # 20240712 この関数では、SysRq として扱わない # SysRq = 1 # PrtSc を SysRq として扱う ################################################### break elif ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) function_num = function_num_old break elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) function_num = cell_y # 1-12 break elif ps2key_data.lower() == "Arw_U".lower(): # ↑ msg_f = "ArwU" print(msg_f) if cell_y > 1 and cell_y < (FUNCTION_ROW_NUM): # 2-12 cell_y_old = cell_y cell_y -= 1 # Table表示位置を調整(home_y の計算) if cell_y < home_y: home_y_old = home_y home_y = cell_y elif ps2key_data.lower() == "Arw_D".lower(): # ↓ msg_f = "ArwD" print(msg_f) if cell_y > 0 and cell_y < (FUNCTION_ROW_NUM -1): # 1-11 cell_y_old = cell_y cell_y += 1 # Table表示位置を調整(home_y の計算) if cell_y > (home_y + (dsp_row_max -1)): home_y_old = home_y home_y = cell_y - (dsp_row_max -1) elif ps2key_data == "F1": msg_f = "F1" print(msg_f) function_num = 1 break elif ps2key_data == "F2": msg_f = "F2" print(msg_f) function_num = 2 break elif ps2key_data == "F3": msg_f = "F3" print(msg_f) function_num = 3 break elif ps2key_data == "F4": msg_f = "F4" print(msg_f) function_num = 4 break elif ps2key_data == "F5": msg_f = "F5" print(msg_f) function_num = 5 break elif ps2key_data == "F6": msg_f = "F6" print(msg_f) function_num = 6 break elif ps2key_data == "F7": msg_f = "F7" print(msg_f) function_num = 7 break # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt # 左クリック、右クリック、ともに押されていないなら if busy_l == 0 and busy_r == 0: # マウスの座標の差分を取り出し、ArwD、ArwU キーと同じように扱う # 列 if cnt_x > 50: col_direc = 1 elif cnt_x < -50: col_direc = -1 else: col_direc = 0 # 行 if cnt_y < -50: row_direc = 1 elif cnt_y > 50: row_direc = -1 else: row_direc = 0 # 差分だけ取り出すので、クリア cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) if row_direc == 1: # ↓ msg_f = "Down" print(msg_f) if cell_y > 0 and cell_y < (FUNCTION_ROW_NUM -1): # 1-11 cell_y_old = cell_y cell_y += 1 # Table表示位置を調整(home_y の計算) if cell_y > (home_y + (dsp_row_max -1)): home_y_old = home_y home_y = cell_y - (dsp_row_max -1) elif row_direc == -1: # ↑ msg_f = "Up" print(msg_f) if cell_y > 1 and cell_y < (FUNCTION_ROW_NUM): # 2-12 cell_y_old = cell_y cell_y -= 1 # Table表示位置を調整(home_y の計算) if cell_y < home_y: home_y_old = home_y home_y = cell_y # 左クリック・ボタンが新たに押されたなら if busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) function_num = cell_y # 1-12 break # 右クリック・ボタンが新たに押されたなら elif busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) function_num = function_num_old break utime.sleep_ms(100) return function_num ####################################################################### # SubMenu の選択 # リスト SubMenu[0]~SubMenu[6] は、画面表示する内容 # return は、Enter=True または Esc=False のみとする def selectSubMenu(SubMenu): display.fill(st7789.BLACK) # SubMenu の表示 for i in range(7): display.text(font2, moji.strFixL_n(SubMenu[i], ST7789_COL_SIZE), \ DOT_C *0, DOT_R *i, st7789.WHITE) # マウス data_cnt_old = 999 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 cnt_y = 0 cnt_s = 0 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # マウスの左クリックが押されていない状態 busy_l = 0 # マウスの右クリックが押されていない状態 busy_r = 0 while True: # PS2Keyboard # 入力は 「Enter」 「Esc」キーのみ受け付ける # ファンクション・キー入力なら if ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) return False elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) return True # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt # 左クリック・ボタンが新たに押されたなら if busy_l == 0 and btn_l ==1: busy_l = 1 # 左クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_l == 1 and btn_l ==0: busy_l = 0 msg_f = "Mouse L cricked" print(msg_f) return True # 右クリック・ボタンが新たに押されたなら if busy_r == 0 and btn_r ==1: busy_r = 1 # 右クリック・ボタンが押された状態から離れた(=クリック)なら elif busy_r == 1 and btn_r ==0: busy_r = 0 msg_f = "Mouse R cricked" print(msg_f) return False utime.sleep_ms(100) ####################################################################### # Alarm 画面表示のみ # 全画面の 文字色(colorFont)を指定できる def alarm(AlarmMsg, colorFont=st7789.RED): # display.fill(st7789.BLACK) # AlarmMsg の表示 for i in range(7): if len(AlarmMsg[i]) > 0: display.text(font2, moji.strFixL_n(AlarmMsg[i], ST7789_COL_SIZE), \ 0, 32 *i, colorFont, st7789.WHITE) ####################################################################### # MFRC522(13.56MHz)RFID にタグやカードが置かれるか、取り除かれるまで待つ # タグやカードが置かれるか、取り除かれるまで Alarm画面を表示する # OnOff(True False)で論理指定する # True:取り除かれるまで待つ False:置かれるまで待つ def waitTag(AlarmMsg, OnOff=False): ptn = 0 display.fill(st7789.BLACK) while midi.checkOnRfid() == OnOff: if ptn == 0: colorFont = st7789.RED alarm(AlarmMsg, colorFont) ptn = 1 else: colorFont = st7789.BLUE alarm(AlarmMsg, colorFont) ptn = 0 utime.sleep_ms(500) ####################################################################### # def selectTone(num): をベースに、チャンネル・トーンのテーブルをキー入力で作成する # # def editToneTable(ToneTable, ToneName): tone_num = 16 tone_num_old = tone_num display.fill(st7789.BLACK) # ST7789 表示窓の設定 # 4 10 # ymf825.Voice_Op_Edit # 4 4 # ymf825.Voice_Com_Edit # 4 2 # ymf825.ToneMenuTable # 4 2 # ymf825.ToneTable if DSP_COL_SIZE < TONE_TABLE_COL_NUM: dsp_col_max = DSP_COL_SIZE else: dsp_col_max = TONE_TABLE_COL_NUM -1 # 5 18 # ymf825.Voice_Op_Edit # 5 4 # ymf825.Voice_Com_Edit # 5 17 # ymf825.ToneMenuTable # 5 17 # ymf825.ToneTable if DSP_ROW_SIZE < TONE_TABLE_ROW_NUM: dsp_row_max = DSP_ROW_SIZE else: dsp_row_max = TONE_TABLE_ROW_NUM -1 cell_x = 1 # 列 cell_y = 1 # home_x = 1 # 表示エリアホーム x home_y = 1 # 表示エリアホーム x # ST7789 初期画面表示 # 「Menu」= 'Save Tone As...' の場合 dsp_data = 'Edit Tone Table' display.text(font2, dsp_data, 16*0, 32*0, st7789.YELLOW) # 画面2行目に、セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 画面2行目に、列タイトルの表示 [ Select Tone] for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixL_n(ToneTable[0][j], 12), \ 16*3 + 16*3*(j - home_x), 32, st7789.CYAN) # 行タイトルの表示 [ 0] [ 1] [ 2] ... for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.int2str_n(ToneTable[i][0], 2), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # ToneTable データの表示 for i in range(home_y, home_y + dsp_row_max): for j in range(home_x, home_x + dsp_col_max): dsp_data = ToneName[ToneTable[i][j]] display.text(font2, moji.strFixL_n(dsp_data, 12), \ 16*3 + 16*3*(j - home_x), \ 32*2 + 32*(i - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする dsp_data = ToneName[ToneTable[cell_y][cell_x]] display.text(font2, moji.strFixL_n(dsp_data, 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x end = 0 # end != 0 で終了 while end == 0: # Enter または Esc で終了 if home_y_old != home_y: # 行タイトルの表示 [ 0] [ 1] [ 2] ... for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.int2str_n(ToneTable[i][0], 2), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # ToneTable データの表示 for i in range(home_y, home_y + dsp_row_max): for j in range(home_x, home_x + dsp_col_max): dsp_data = ToneName[ToneTable[i][j]] display.text(font2, moji.strFixL_n(dsp_data, 12), \ 16*3 + 16*3*(j - home_x), \ 32*2 + 32*(i - home_y), st7789.WHITE) if cell_y_old != cell_y: # 画面2行目に、セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 直前のセル表示を [WHITE] に戻す dsp_data = ToneName[ToneTable[cell_y_old][cell_x_old]] display.text(font2, moji.strFixL_n(dsp_data, 12), \ 16*3 + 16*3*(cell_x_old - home_x), \ 32*2 + 32*(cell_y_old - home_y), st7789.WHITE) # 現在セルの tone_num を取得する tone_num = ToneTable[cell_y][cell_x] # 現在のセル表示を [RED] にする dsp_data = ToneName[ToneTable[cell_y][cell_x]] display.text(font2, moji.strFixL_n(dsp_data, 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) if tone_num_old != tone_num: # 現在セルの tone_num を取得する tone_num_old = ToneTable[cell_y][cell_x] # 現在のセル表示を [RED] にする dsp_data = ToneName[ToneTable[cell_y][cell_x]] display.text(font2, moji.strFixL_n(dsp_data, 12), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) if cell_y_old != cell_y or home_y_old != home_y: cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x # PS2Keyboard # 入力は Arw_U:「↑」 Arw_D:「↓」 Arw_L:「←」 Arw_R:「→」 # 「Enter」 「Esc」キーのみ受け付ける # ファンクション・キー入力なら if ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) end = 1 elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) end = 1 elif ps2key_data.lower() == "Arw_U".lower(): # ↑ msg_f = "ArwU" print(msg_f) if cell_y > 1 and cell_y < (TONE_TABLE_ROW_NUM): # 2-16 cell_y_old = cell_y cell_y -= 1 # Table表示位置を調整(home_y の計算) if cell_y < home_y: home_y_old = home_y home_y = cell_y elif ps2key_data.lower() == "Arw_D".lower(): # ↓ msg_f = "ArwD" print(msg_f) if cell_y > 0 and cell_y < (TONE_TABLE_ROW_NUM -1): # 1-15 cell_y_old = cell_y cell_y += 1 # Table表示位置を調整(home_y の計算) if cell_y > (home_y + (dsp_row_max -1)): home_y_old = home_y home_y = cell_y - (dsp_row_max -1) elif ps2key_data.lower() == "Arw_L".lower(): # ← msg_f = "ArwL" print(msg_f) if tone_num > 0: # 1-16 tone_num_old = tone_num tone_num -= 1 else: tone_num_old = tone_num tone_num = 16 # data keep ToneTable[cell_y][cell_x] = tone_num elif ps2key_data.lower() == "Arw_R".lower(): # → msg_f = "ArwR" print(msg_f) if tone_num < (TONE_TABLE_ROW_NUM -1): # 0-15 tone_num_old = tone_num tone_num += 1 else: tone_num_old = tone_num tone_num = 0 # data keep ToneTable[cell_y][cell_x] = tone_num elif ps2key_data == "F1": msg_f = "F1" print(msg_f) ############################################################################# # 20240723 Move Here frm ymf825py.py # Edit Voice Operation Parameter # old def editVoiceOp(num, OpNum): def editVoiceOp(Voice_Op_Edit, VoiceOpName, num, OpNum): tone_num = num & 0x0F # global Voice_Op_Edit # global VoiceOpName global backColor display.fill(st7789.BLACK) # 4 10 # Voice_Op_Edit # 4 4 # Voice_Com_Edit # 4 2 # ToneMenuTable if DSP_COL_SIZE < VOICE_OP_COL_NUM: dsp_col_max = DSP_COL_SIZE else: dsp_col_max = VOICE_OP_COL_NUM -1 # 5 18 # Voice_Op_Edit # 5 4 # Voice_Com_Edit # 5 17 # ToneMenuTable if DSP_ROW_SIZE < VOICE_OP_ROW_NUM: dsp_row_max = DSP_ROW_SIZE else: dsp_row_max = VOICE_OP_ROW_NUM -1 try: if OpNum >= VOICE_OP_ROW_NUM: OpNum = VOICE_OP_ROW_NUM -1 elif OpNum <= 0: OpNum = 1 except: print('TypeError ComNum in def editVoiceOp(Voice_Op_Edit, VoiceOpName, num, OpNum):') OpNum = 0 # OpNum の範囲を 1 - 17 に制限する if OpNum >= VOICE_OP_ROW_NUM: OpNum = VOICE_OP_ROW_NUM -1 elif OpNum <= 0: OpNum = 1 # 与えられた OpNum に表示を合わせるため cell_y home_y を求める # cell_y を計算 cell_y = OpNum # 行 1 - 17 # home_y を計算 if cell_y <= DSP_ROW_SIZE: home_y = 1 # 表示エリアホーム y else: home_y = cell_y - DSP_ROW_SIZE +1 cell_x = 1 # 列 home_x = 1 # 表示エリアホーム x menu_num = 4 # ホーム座標表示 Menu_bar の表示 「 OK」「 BK」「 DF」 menu_bar = [None] * menu_num menu_bar[0] = " " # 6 menu_bar[1] = " OK" # 3 menu_bar[2] = " BK" # 3 menu_bar[3] = " DF" # 3 dsp_data = "" for i in range(menu_num): dsp_data += menu_bar[i] display.text(font2, dsp_data, 16*0, 32*0, st7789.GREEN) # セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 列タイトルの表示 [ e1] [ e2] [ e3] [ e4] [ o1] [ o2] [ o3] [ o4] [ Mx] for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixR_n(Voice_Op_Edit[OPT][j], 3), \ 16*3 + 16*3*(j - home_x), 32, st7789.CYAN) # 行タイトルの表示 [SR ] [XOF] ... [WS ] [FB ] for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.strFixL_n(Voice_Op_Edit[i][OP0], 3), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # Voice_Op_Edit データの表示 for y in range(home_y, home_y + dsp_row_max): for x in range(home_x, home_x + dsp_col_max): display.text(font2, moji.int2str_n(Voice_Op_Edit[y][x], 3), \ 16*3 + 16*3*(x - home_x), \ 32*2 + 32*(y - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする display.text(font2, moji.int2str_n(Voice_Op_Edit[cell_y][cell_x], 3), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 # 20240727 Add cell_x_now = cell_x cell_y_now = cell_y home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x cnt_y = (cell_y *100 +50) *-1 data_cnt = 0 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 # cnt_y = 0 cnt_s = 0 # data_cnt_old = data_cnt btn_l_old = btn_l btn_r_old = btn_r btn_c_old = btn_c cnt_x_old = cnt_x cnt_y_old = cnt_y cnt_s_old = cnt_s # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # mode:0 編集セルを選択するモード、mode:1 選択したセルを編集するモード mode = 0 # マウスの左クリックが押された状態(離れたことを確認できていない状態) busy_l = 0 # マウスの右クリックが押された状態(離れたことを確認できていない状態) busy_r = 0 # mode == 3 で終了 while mode != 3: flag_M = 0 # Mouse flag_K = 0 # Key msg_f = '' # FunctionKey ############################################################## # PS2Keyboard入力があれば、マウス情報に置き換える。 # マウスのクリック押下時点で反応するように設計したのだ。 # 入力は Arw_U:「↑」, Arw_D:「↓」, Arw_L:「←」, Arw_R:「→」 # 「Enter」 「Esc」キーのみ受け付ける ############################################################## # 1文字・記号入力なら if ps2key.rcv_size() == 1: ps2key_data = ps2key.get_code() # 数字キーならば if ps2key_data >= '0' and ps2key_data <= '9': flag_K = 1 ####################################################### # 右詰め表示で編集 # Voice_Com_Editの場合は、Maxが10以上なら2桁 if Voice_Op_Edit[cell_y_now][OP9] > 10: cnt_s = cnt_s *10 + int(ps2key_data) else: cnt_s = int(ps2key_data) # マウス座標・現在地を更新 スクロールカウント ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) ####################################################### # ファンクション・キー入力なら elif ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() flag_K = 1 # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "PrtSc".lower(): msg_f = "PrtSc = SysRq" print(msg_f) ################################################### SysRq = 1 # PrtSc を SysRq として扱う ################################################### # break elif ps2key_data.lower() == "BS".lower(): msg_f = "BS" print(msg_f) # 末尾の1桁を消すということは、1/10にすること cnt_s = int(cnt_s / 10) flag_M = 1 elif ps2key_data.lower() == "Del".lower(): msg_f = "Del" print(msg_f) # 0クリア cnt_s = 0 flag_M = 1 elif ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) return OpNum elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) flag_M = 1 elif ps2key_data.lower() == "Arw_U".lower(): # ↑ msg_f = "ArwU" print(msg_f) cnt_y += 100 print(f'{cnt_y} cnt_y += 100') flag_M = 1 elif ps2key_data.lower() == "Arw_D".lower(): # ↓ msg_f = "ArwD" print(msg_f) cnt_y -= 100 print(f'{cnt_y} cnt_y -= 100') flag_M = 1 elif ps2key_data.lower() == "Arw_L".lower(): # ← msg_f = "ArwL" print(msg_f) cnt_x -= 100 print(f'{cnt_x} cnt_x -= 100') flag_M = 1 elif ps2key_data.lower() == "Arw_R".lower(): # → msg_f = "ArwR" print(msg_f) cnt_x += 100 print(f'{cnt_x} cnt_x += 100') flag_M = 1 elif ps2key_data.lower() == "PgUp".lower(): # PageUp msg_f = "PageUp" print(msg_f) cnt_y += 100 *8 print(f'{cnt_y} cnt_y += 100 *8') flag_M = 1 elif ps2key_data.lower() == "PgDn".lower(): # PageDown msg_f = "PageDown" print(msg_f) cnt_y -= 100 *8 print(f'{cnt_y} cnt_y -= 100 *8') flag_M = 1 elif ps2key_data.lower() == "Home".lower(): # Home msg_f = "Home" print(msg_f) cnt_x -= 100 *7 print(f'{cnt_x} cnt_x -= 100 *7') flag_M = 1 elif ps2key_data.lower() == "End".lower(): # End msg_f = "End" print(msg_f) cnt_x += 100 *7 print(f'{cnt_x} cnt_x += 100 *7') flag_M = 1 elif ps2key_data == "F1": msg_f = "F1" print(msg_f) if flag_M == 1: # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # マウス入力ありなら else: # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt flag_M = 1 # マウス入力か、キー入力があれば if flag_M == 1 or flag_K == 1: # セル・選択モード #################################################### if mode == 0: # 左クリック・ボタンが押されたままでないなら if busy_l == 0: # 列 Voice_Op_Edit VOICE_OP_COL_NUM if cnt_x > VOICE_OP_COL_NUM *100 -1: cnt_x = VOICE_OP_COL_NUM *100 -1 elif cnt_x < 100: cnt_x = 100 # 行 Voice_Op_Edit VOICE_OP_ROW_NUM if cnt_y < (VOICE_OP_ROW_NUM *100 -1) *-1: cnt_y = (VOICE_OP_ROW_NUM *100 -1) *-1 elif cnt_y > -100: cnt_y = -100 # セル・アドレスの表示データ生成 [x:1-9, y:1-9] # 列 cell_x = int(cnt_x / 100) # 行 cell_y = int((-1 * cnt_y) / 100) if cell_x_old < cell_x: cell_x_direc = 1 elif cell_x_old > cell_x: cell_x_direc = -1 else: cell_x_direc = 0 if cell_y_old < cell_y: cell_y_direc = 1 elif cell_y_old > cell_y: cell_y_direc = -1 else: cell_y_direc = 0 # Table表示位置を調整(home_x home_y の計算) ############################################################ if cell_x_direc == 1 and cell_x > (home_x + (dsp_col_max -1)): home_x = cell_x - (dsp_col_max -1) elif cell_x_direc == -1 and cell_x < home_x: home_x = cell_x ############################################################ if cell_y_direc == 1 and cell_y > (home_y + (dsp_row_max -1)): home_y = cell_y - (dsp_row_max -1) elif cell_y_direc == -1 and cell_y < home_y: home_y = cell_y ############################################################ # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル・アドレス表示 [A99] adr_dsp = chr(64 + cell_x) + moji.int2str_n(cell_y, 2) display.text(font2, adr_dsp, 16*0, 32*1, st7789.CYAN) ########################################################### # DEBUG home_x home_y を左上隅に表示 # menu_bar[0] = moji.int2str_n(home_x, 3) + moji.int2str_n(home_y, 3) # display.text(font2, menu_bar[0], 0, 0, st7789.GREEN) ########################################################### # セル値を、左上隅に表示 val = Voice_Op_Edit[cell_y][cell_x] display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED) # home_x または home_y に変化があれば、Voice_Op_Edit を再表示する if home_x_old != home_x or home_y_old != home_y: for y in range(home_y, home_y + dsp_row_max): for x in range(home_x, home_x + dsp_col_max): display.text(font2, moji.int2str_n(Voice_Op_Edit[y][x], 3), \ 16*3 + 16*3*(x - home_x), \ 32*2 + 32*(y - home_y), st7789.WHITE) # home_x に変化があれば、列タイトルの再表示 [ e1] [ e2] ... [ o1] [ o2] ... [ Mx] if home_x_old != home_x: for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixR_n(Voice_Op_Edit[OPT][j], 3), \ 16*3 + 16*3*(j - home_x), 32, st7789.CYAN) # home_y に変化があれば、行タイトルの再表示 [SR ] [XOF] ... [WS ] [FB ] if home_y_old != home_y: for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.strFixL_n(Voice_Op_Edit[i][OP0], 3), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # 現在セル座標に変化があれば if cell_x_old != cell_x or cell_y_old != cell_y: # 直前のセル表示を [WHITE] に戻す display.text(font2, moji.int2str_n(Voice_Op_Edit[cell_y_old][cell_x_old], 3), \ 16*3 + 16*3*(cell_x_old - home_x_old), \ 32*2 + 32*(cell_y_old - home_y_old), st7789.WHITE) # 現在のセル表示を 文字色:[RED] 背景色[WHITE] にする display.text(font2, moji.int2str_n(Voice_Op_Edit[cell_y][cell_x], 3), \ 16*3 + 16*3*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) # セルの値を、左上隅に表示 val = Voice_Op_Edit[cell_y][cell_x] display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED) # セル座標を更新 cell_y_old = cell_y cell_x_old = cell_x home_y_old = home_y home_x_old = home_x # 左クリック・ボタンが押されていたら、セル・編集モードに移行 if btn_l == 1 or msg_f == 'Enter': if btn_l == 1: busy_l = 1 elif msg_f == 'Enter': msg_f = '' # 編集中の座標を保存しておく cell_x_now = cell_x cell_y_now = cell_y # 編集中のセル値を、左上隅に表示 if cell_x_now >= 1 and cell_x_now <= 4: # 変更前の内容を表示 OpNum = cell_y_now OpName = Voice_Op_Edit[cell_y_now][cell_x_now] print(f'Sub OK Voice_Op_Edit {VoiceOpName[cell_y_now]} {cell_x_now} = ', OpName, end = '') val = Voice_Op_Edit[cell_y_now][cell_x_now] display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED, st7789.WHITE) else: display.text(font2, moji.strFixL_n("N/A", 6), \ 16*0, 32*0, st7789.RED, st7789.WHITE) # menu_bar[1] = " OK", menu_bar[2] = " BK" menu_bar[3] = " DF" # [ OK]の位置にセル座標を合わせる cnt_x = 250 cnt_y = 50 cnt_s = val # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル編集モードに移行 mode = 1 # 左クリック・ボタンが押されたままなら、離れるまで待つ elif btn_l == 0: busy_l = 0 # 新たに右クリック・ボタンが押されていたら if busy_r == 0 and btn_r == 1: busy_r = 1 mode = 2 # セル・編集モード #################################################### elif mode == 1: # 左クリック・ボタンが押されたままでないなら if busy_l == 0: # 列 if cnt_x > (menu_num +1) *100 -1: # cnt_x = cnt_x > (menu_num +1) *100 -1 cnt_x = (menu_num +1) *100 -1 elif cnt_x < 200: cnt_x = 200 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル・アドレスの生成 # menu_bar[1] = " OK", menu_bar[2] = " BK" menu_bar[3] = " DF" # 列 1, 2, 3 cell_x_edt = int(cnt_x / 100) -1 # 行 cell_y_edt = 0 # メニューバー表示を編集用にする(選択メニューの背景をマゼンタ色) for i in range(1, menu_num): if i == cell_x_edt: display.text(font2, menu_bar[i], \ 16*6 + 16*3*(i - 1), 0, st7789.GREEN, st7789.MAGENTA) else: display.text(font2, menu_bar[i], \ 16*6 + 16*3*(i - 1), 0, st7789.GREEN) # 編集中のセル値を、左上隅に表示 if cell_x_now >= 1 and cell_x_now <= 4: # 最大値を超えない if cnt_s > Voice_Op_Edit[cell_y_now][OP9]: val = Voice_Op_Edit[cell_y_now][OP9] # マイナス値はなし elif cnt_s < 0: val = 0 else: val = cnt_s ##################################################### # display.text(font2, moji.int2str_n(val, 6), \ # 16*0, 32*0, st7789.RED, st7789.WHITE) ##################################################### display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED, backColor) ##################################################### # 編集対象外のセルなら #N/A を表示 else: display.text(font2, moji.strFixL_n("#N/A", 6), \ 16*0, 32*0, st7789.RED, st7789.WHITE) # 左クリック・ボタンが押されていたら、 # Voice_Op_Edit に代入して、セル・編集モードを終了 if btn_l == 1 or msg_f == 'Enter': if btn_l == 1: busy_l = 1 elif msg_f == 'Enter': msg_f = '' # 左クリックしたセルが menu_bar[1] = " OK" なら # 編集中のセル値を、Voice_Op_Edit に代入して表示する if cell_x_edt == 1: Voice_Op_Edit[cell_y_now][cell_x_now] = val display.text(font2, moji.int2str_n(Voice_Op_Edit[cell_y_now][cell_x_now], 3), \ 16*3 + 16*3*(cell_x_now - home_x), \ 32*2 + 32*(cell_y_now - home_y), st7789.RED, st7789.WHITE) OpNum = cell_y_now OpName = Voice_Op_Edit[cell_y_now][cell_x_now] print(f' to {VoiceOpName[cell_y_now]} {cell_x_now} = ', OpName) # 左クリックしたセルが menu_bar[2] = " BK" なら、元の値に戻す elif cell_x_edt == 2: val = Voice_Op_Edit[cell_y_now][cell_x_now] # 左クリックしたセルが menu_bar[3] = " DF" なら # Voice_Op_Edit の Orig 値を、Voice_Op_Edit に代入して表示する elif cell_x_edt == 3 and (cell_x_now >= 1 and cell_x_now <= 4): Voice_Op_Edit[cell_y_now][cell_x_now] = Voice_Op_Edit[cell_y_now][cell_x_now +4] val = Voice_Op_Edit[cell_y_now][cell_x_now] display.text(font2, moji.int2str_n(Voice_Op_Edit[cell_y_now][cell_x_now], 3), \ 16*3 + 16*3*(cell_x_now - home_x), \ 32*2 + 32*(cell_y_now - home_y), st7789.RED, st7789.WHITE) # 編集が終了したら、セル・選択モードに戻る # メニューバー表示を元に戻す for i in range(1, menu_num): display.text(font2, menu_bar[i], \ 16*6 + 16*3*(i - 1), 0, st7789.GREEN) # 編集中の左上隅に表示を元に戻す display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED) # 編集前の座標にセット cnt_x = cell_x_now *100 + 50 cnt_y = (cell_y_now *100 + 50) * -1 # cnt_s = 0 #マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル選択モードに移行 mode = 0 # 左クリック・ボタンが押されたままなら、離れるまで待つ elif btn_l == 0: busy_l = 0 # 編集終了・確認 モード ############################################### # mode:0 で、右クリック・ボタンが押されていたらここにくる elif mode == 2: # 右クリック・ボタンが押されたままなら、離れるまで待つ if btn_r == 0: print('right button clicked ... End of editVoiceOp.') busy_r = 0 mode = 3 # End of editVoiceOp else: return OpNum ############################################################################# # 20240723 Move Here frm ymf825py.py # Edit Voice Commonn Parameter # old def editVoiceCom(num, ComNum): def editVoiceCom(Voice_Com_Edit, VoiceComName, num, ComNum): tone_num = num & 0x0F # global Voice_Com_Edit # global VoiceComName global backColor display.fill(st7789.BLACK) CELL_WIDTH = const(4) # 4 10 # 4 4 if DSP_COL_SIZE < VOICE_COM_COL_NUM: dsp_col_max = DSP_COL_SIZE else: dsp_col_max = VOICE_COM_COL_NUM -1 # 5 18 # 5 4 if DSP_ROW_SIZE < VOICE_COM_ROW_NUM: dsp_row_max = DSP_ROW_SIZE else: dsp_row_max = VOICE_COM_ROW_NUM -1 try: if ComNum >= VOICE_COM_ROW_NUM: ComNum = VOICE_COM_ROW_NUM -1 elif ComNum <= 0: ComNum = 1 except: print(f'TypeError ComNum in def editVoiceCom(Voice_Com_Edit, VoiceComName, num, ComNum):') ComNum = 0 # ComNum の範囲を 1 - 3 に制限する if ComNum >= VOICE_COM_ROW_NUM: ComNum = VOICE_COM_ROW_NUM -1 elif ComNum <= 0: ComNum = 1 # 与えられた ComNum に表示を合わせるため cell_y home_y を求める # cell_y を計算 cell_y = ComNum # 行 1 - 3 # home_y を計算 if cell_y <= DSP_ROW_SIZE: home_y = 1 # 表示エリアホーム y else: home_y = cell_y - DSP_ROW_SIZE +1 cell_x = 1 # 列 home_x = 1 # 表示エリアホーム x menu_num = 4 # ホーム座標表示 Menu_bar の表示 「 OK」「 BK」「 DF」 menu_bar = [None] * menu_num menu_bar[0] = " " # 6 menu_bar[1] = " OK" # 3 menu_bar[2] = " BK" # 3 menu_bar[3] = " DF" # 3 dsp_data = "" for i in range(menu_num): dsp_data += menu_bar[i] display.text(font2, dsp_data, 16*0, 32*1, st7789.GREEN) # セル・アドレス表示 [A99] display.text(font2, chr(64 + cell_x) + moji.int2str_n(cell_y, 2), \ 16*0, 32*1, st7789.CYAN) # 列タイトルの表示 [ Edt] [ Org] [ Max] for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixR_n(Voice_Com_Edit[COM][j], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(j - home_x), 32, st7789.CYAN) # 行タイトルの表示 [BO ] [LFO] [ALG] for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.strFixL_n(Voice_Com_Edit[i][CM0], 3), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) for y in range(home_y, home_y + dsp_row_max): for x in range(home_x, home_x + dsp_col_max): display.text(font2, moji.int2str_n(Voice_Com_Edit[y][x], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(x - home_x), \ 32*2 + 32*(y - home_y), st7789.WHITE) # 現在のセル表示を [RED] にする display.text(font2, moji.int2str_n(Voice_Com_Edit[cell_y][cell_x], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) cell_y_old = cell_y # 行 cell_x_old = cell_x # 列 home_y_old = home_y # 表示エリアホーム y home_x_old = home_x # 表示エリアホーム x cnt_y = (cell_y *100 +50) *-1 data_cnt = 0 btn_l = 0 btn_r = 0 btn_c = 0 cnt_x = 0 # cnt_y = 0 cnt_s = 0 # data_cnt_old = data_cnt btn_l_old = btn_l btn_r_old = btn_r btn_c_old = btn_c cnt_x_old = cnt_x cnt_y_old = cnt_y cnt_s_old = cnt_s # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # mode:0 編集セルを選択するモード、mode:1 選択したセルを編集するモード mode = 0 # マウスの左クリックが押された状態(離れたことを確認できていない状態) busy_l = 0 # マウスの右クリックが押された状態(離れたことを確認できていない状態) busy_r = 0 # 直前の選択を表示する cell_y = ComNum cnt_y = (cell_y *100 +50) *-1 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) data_cnt_old = 999 # mode == 3 で終了 while mode != 3: flag_M = 0 # Mouse flag_K = 0 # Key msg_f = '' # FunctionKey ############################################################## # PS2Keyboard入力があれば、マウス情報に置き換える。 # マウスのクリック押下時点で反応するように設計したのだ。 # 入力は Arw_U:「↑」, Arw_D:「↓」, Arw_L:「←」, Arw_R:「→」 # 「Enter」 「Esc」キーのみ受け付ける ############################################################## # 1文字・記号入力なら if ps2key.rcv_size() == 1: ps2key_data = ps2key.get_code() # 数字キーならば if ps2key_data >= '0' and ps2key_data <= '9': flag_K = 1 ####################################################### # 右詰め表示で編集 # Voice_Com_Editの場合は、1桁なので上書き cnt_s = int(ps2key_data) # マウス座標・現在地を更新 スクロールカウント ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) ####################################################### # ファンクション・キー入力なら elif ps2key.rcv_size() > 1: ps2key_data = ps2key.get_code() flag_K = 1 # .lower 文字の一致を取りやすくするため、shift low で照合 if ps2key_data.lower() == "PrtSc".lower(): msg_f = "PrtSc = SysRq" print(msg_f) ################################################### SysRq = 1 # PrtSc を SysRq として扱う ################################################### # break elif ps2key_data.lower() == "BS".lower(): msg_f = "BS" print(msg_f) # 末尾を消すということは、1/10 cnt_s = int(cnt_s / 10) flag_M = 1 elif ps2key_data.lower() == "Del".lower(): msg_f = "Del" print(msg_f) # 0クリア cnt_s = 0 flag_M = 1 elif ps2key_data.lower() == "Esc".lower(): msg_f = "Esc" print(msg_f) return ComNum elif ps2key_data.lower() == "Enter".lower(): msg_f = "Enter" print(msg_f) flag_M = 1 elif ps2key_data.lower() == "Arw_U".lower(): # ↑ msg_f = "ArwU" print(msg_f) cnt_y += 100 print(f'{cnt_y} cnt_y += 100') flag_M = 1 elif ps2key_data.lower() == "Arw_D".lower(): # ↓ msg_f = "ArwD" print(msg_f) cnt_y -= 100 print(f'{cnt_y} cnt_y -= 100') flag_M = 1 elif ps2key_data.lower() == "Arw_L".lower(): # ← msg_f = "ArwL" print(msg_f) cnt_x -= 100 print(f'{cnt_x} cnt_x -= 100') flag_M = 1 elif ps2key_data.lower() == "Arw_R".lower(): # → msg_f = "ArwR" print(msg_f) cnt_x += 100 print(f'{cnt_x} cnt_x += 100') flag_M = 1 elif ps2key_data == "F1": msg_f = "F1" print(msg_f) if flag_M == 1: # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # マウス入力なら else: # マウスからボタンクリックの情報、座標情報を取得する (data_cnt, btn_l, btn_r, btn_c, cnt_x, cnt_y, cnt_s) = ps2mus_rcv.get_data() # PS2 Mouse に入力があるなら if data_cnt_old != data_cnt: data_cnt_old = data_cnt flag_M = 1 # マウス入力か、キー入力があれば if flag_M == 1 or flag_K == 1: # セル・選択モード #################################################### if mode == 0: # 左クリック・ボタンが押されたままでないなら if busy_l == 0: # 列 Voice_Com_Edit Voice_Com_COL_NUM if cnt_x > VOICE_COM_COL_NUM *100 -1: cnt_x = VOICE_COM_COL_NUM *100 -1 elif cnt_x < 100: cnt_x = 100 # 行 Voice_Com_Edit Voice_Com_ROW_NUM if cnt_y < (VOICE_COM_ROW_NUM *100 -1) *-1: cnt_y = (VOICE_COM_ROW_NUM *100 -1) *-1 elif cnt_y > -100: cnt_y = -100 # セル・アドレスの表示データ生成 [x:1-9, y:1-9] # 列 cell_x = int(cnt_x / 100) # 行 cell_y = int((-1 * cnt_y) / 100) if cell_x_old < cell_x: cell_x_direc = 1 elif cell_x_old > cell_x: cell_x_direc = -1 else: cell_x_direc = 0 if cell_y_old < cell_y: cell_y_direc = 1 elif cell_y_old > cell_y: cell_y_direc = -1 else: cell_y_direc = 0 # Table表示位置を調整(home_x home_y の計算) ############################################################ if cell_x_direc == 1 and cell_x > (home_x + (dsp_col_max -1)): home_x = cell_x - (dsp_col_max -1) elif cell_x_direc == -1 and cell_x < home_x: home_x = cell_x ############################################################ if cell_y_direc == 1 and cell_y > (home_y + (dsp_row_max -1)): home_y = cell_y - (dsp_row_max -1) elif cell_y_direc == -1 and cell_y < home_y: home_y = cell_y ############################################################ # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル・アドレス表示 [A99] adr_dsp = chr(64 + cell_x) + moji.int2str_n(cell_y, 2) display.text(font2, adr_dsp, 16*0, 32*1, st7789.CYAN) # セル値を、左上隅に表示 val = Voice_Com_Edit[cell_y][cell_x] display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED) # home_x または home_y に変化があれば、Voice_Com_Edit を再表示する if home_x_old != home_x or home_y_old != home_y: for y in range(home_y, home_y + dsp_row_max): for x in range(home_x, home_x + dsp_col_max): display.text(font2, moji.int2str_n(Voice_Com_Edit[y][x], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(x - home_x), \ 32*2 + 32*(y - home_y), st7789.WHITE) # home_x に変化があれば、列タイトルの再表示 [ edt] [ Org] [ Max]... if home_x_old != home_x: for j in range(home_x, home_x + dsp_col_max): display.text(font2, moji.strFixR_n(Voice_Com_Edit[COM][j], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(j - home_x), 32, st7789.CYAN) # home_y に変化があれば、行タイトルの再表示 [BO ] [LFO] [ALG]... if home_y_old != home_y: for i in range(home_y, home_y + dsp_row_max): display.text(font2, moji.strFixL_n(Voice_Com_Edit[i][CM0], 3), 0, \ 32*2 + 32*(i - home_y), st7789.CYAN) # 現在セル座標に変化があれば if cell_x_old != cell_x or cell_y_old != cell_y: # 直前のセル表示を [WHITE] に戻す display.text(font2, moji.int2str_n(Voice_Com_Edit[cell_y_old][cell_x_old], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(cell_x_old - home_x_old), \ 32*2 + 32*(cell_y_old - home_y_old), st7789.WHITE) # 現在のセル表示を 文字色:[RED] 背景色[WHITE] にする display.text(font2, moji.int2str_n(Voice_Com_Edit[cell_y][cell_x], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(cell_x - home_x), \ 32*2 + 32*(cell_y - home_y), st7789.RED, st7789.WHITE) # セルの値を、左上隅に表示 val = Voice_Com_Edit[cell_y][cell_x] display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED) # セル座標を更新 cell_y_old = cell_y cell_x_old = cell_x home_y_old = home_y home_x_old = home_x # 左クリック・ボタンが押されていたら、セル・編集モードに移行 # if btn_l == 1: if btn_l == 1 or msg_f == 'Enter': if btn_l == 1: busy_l = 1 elif msg_f == 'Enter': msg_f = '' # 編集中の座標を保存しておく cell_x_now = cell_x cell_y_now = cell_y # 編集中のセル値を、左上隅に表示 if cell_x_now == 1: # 変更前の内容を表示 ComNum = Voice_Com_Edit[cell_y_now][cell_x_now] print(f'Sub OK Voice_Com_Edit {VoiceComName[cell_y_now]} = ', ComNum, end = '') val = Voice_Com_Edit[cell_y_now][cell_x_now] display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED, st7789.WHITE) else: display.text(font2, moji.strFixL_n("N/A", 6), \ 16*0, 32*0, st7789.RED, st7789.WHITE) # menu_bar[1] = " OK", menu_bar[2] = " BK" menu_bar[3] = " DF" # [ OK]の位置にセル座標を合わせる cnt_x = 250 cnt_y = 50 cnt_s = val #マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル編集モードに移行 mode = 1 # 左クリック・ボタンが離れるのを待って elif btn_l == 0: busy_l = 0 # 新たに右クリック・ボタンが押されていたら if busy_r == 0 and btn_r == 1: busy_r = 1 mode = 2 # セル・編集モード #################################################### elif mode == 1: # 左クリック・ボタンが押されたままでないなら if busy_l == 0: # 列 print(f'mode == 1 cnt_x = {cnt_x}') if cnt_x > (menu_num +1) *100 -1: # cnt_x = cnt_x > (menu_num +1) *100 -1 cnt_x = (menu_num +1) *100 -1 elif cnt_x < 200: cnt_x = 200 # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル・アドレスの生成 # menu_bar[1] = " OK", menu_bar[2] = " BK" menu_bar[3] = " DF" # 列 1, 2, 3 cell_x_edt = int(cnt_x / 100) -1 # 行 cell_y_edt = 0 # メニューバー表示を編集用にする(選択メニューの背景をマゼンタ色) for i in range(1, menu_num): if i == cell_x_edt: display.text(font2, menu_bar[i], \ 16*6 + 16*3*(i - 1), 0, st7789.GREEN, st7789.MAGENTA) else: display.text(font2, menu_bar[i], \ 16*6 + 16*3*(i - 1), 0, st7789.GREEN) # 編集中のセル値を、左上隅に表示 if cell_x_now == 1: # 最大値を超えない if cnt_s > Voice_Com_Edit[cell_y_now][CM3]: val = Voice_Com_Edit[cell_y_now][CM3] # マイナス値はなし elif cnt_s < 0: val = 0 else: val = cnt_s ###################################################### # display.text(font2, moji.int2str_n(val, 6), \ # 16*0, 32*0, st7789.RED, st7789.WHITE) display.text(font2, moji.int2str_n(val, 6), \ 16*0, 32*0, st7789.RED, backColor) ###################################################### # 編集対象外のセルなら #N/A を表示 else: display.text(font2, moji.strFixL_n("#N/A", 6), \ 16*0, 32*0, st7789.RED, st7789.WHITE) # 左クリック・ボタンが押されていたら、 # Voice_Com_Edit に代入して、セル・編集モードを終了 if btn_l == 1 or msg_f == 'Enter': if btn_l == 1: busy_l = 1 elif msg_f == 'Enter': msg_f = '' # 左クリックしたセルが menu_bar[1] = " OK" なら # 編集中のセル値を、Voice_Com_Edit に代入して表示する if cell_x_edt == 1: Voice_Com_Edit[cell_y_now][cell_x_now] = val display.text(font2, moji.int2str_n(Voice_Com_Edit[cell_y_now][cell_x_now], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(cell_x_now - home_x), \ 32*2 + 32*(cell_y_now - home_y), st7789.RED, st7789.WHITE) ComNum = Voice_Com_Edit[cell_y_now][cell_x_now] print(f' to {VoiceComName[cell_y_now]} = ', ComNum) # 左クリックしたセルが menu_bar[2] = " BK" なら、元の値に戻す elif cell_x_edt == 2: val = Voice_Com_Edit[cell_y_now][cell_x_now] # 左クリックしたセルが menu_bar[3] = " DF" なら # Voice_Com_Edit の Orig 値を、Voice_Com_Edit に代入して表示する elif cell_x_edt == 3 and cell_x_now == 1: # Voice_Com_Edit[cell_y_now][cell_x_now] = Voice_Com_Edit[cell_y_now][cell_x_now +4] Voice_Com_Edit[cell_y_now][cell_x_now] = Voice_Com_Edit[cell_y_now][CM2] val = Voice_Com_Edit[cell_y_now][cell_x_now] display.text(font2, moji.int2str_n(Voice_Com_Edit[cell_y_now][cell_x_now], 3), \ 16*CELL_WIDTH + 16*CELL_WIDTH*(cell_x_now - home_x), \ 32*2 + 32*(cell_y_now - home_y), st7789.RED, st7789.WHITE) # 編集が終了したら、セル・選択モードに戻る # メニューバー表示を元に戻す for i in range(1, menu_num): display.text(font2, menu_bar[i], \ 16*6 + 16*3*(i - 1), 0, st7789.GREEN) # 編集中の左上隅に表示を元に戻す display.text(font2, moji.int2str_n(val, 6), \ 0, 0, st7789.RED) # 編集前の座標にセット cnt_x = cell_x_now *100 + 50 cnt_y = (cell_y_now *100 + 50) * -1 cnt_s = val # マウス座標・現在地を更新 ps2mus_rcv.set_cnt(cnt_x, cnt_y, cnt_s) # セル選択モードに移行 mode = 0 # 左クリック・ボタンが押されたままなら、離れるまで待つ elif btn_l == 0: busy_l = 0 # 編集終了・確認 モード ############################################### # mode:0 で、右クリック・ボタンが押されていたらここにくる elif mode == 2: # 右クリック・ボタンが押されたままなら、離れるまで待つ if btn_r == 0: busy_r = 0 print('right button clicked ... End of editVoiceCom.') mode = 3 # End of editVoiceCom else: return ComNum ####################################################################### # Main Python Start ####################################################################### print('Main Python Start') print() print('uos.uname = ', uos.uname()) print() print('Main Python Start メモリ使用状況') micropython.mem_info() # st7789 spi Setting # 20240321 polarity=1, phase=1 OK spi1 = SPI(1, baudrate=40000000, polarity=1, phase=1) print('spi1 = ', spi1) print() # st7789 display Setting display = st7789.ST7789(spi1, disp_width, disp_width,\ reset=Pin(st7789_res, Pin.OUT),\ dc=Pin(st7789_dc, Pin.OUT),\ xstart=0, ystart=0, rotation=0) # 変数の初期設定 ps2kb_timer = 0 ps2key_buff = "" # init_ps2mouse() ps2mus_cmd.init_ps2cmd_1() ps2mus_rcv.init_ps2rcv_1(MUS_PIO_FRQ) ps2mus_cmd.init_ps2cmd_2() ps2mus_rcv.init_ps2rcv_2(MUS_PIO_FRQ) ###################################### # PS2mouseCommnd PIO プログラムの削除 # いろいろ試したが、唯一うまく動作する方法 rp2.PIO(0).remove_program() ###################################### # PS2KeyRecive ドライバ および StateMachine の設定と起動 ---------------------- # PS2KeyRecive ドライバの初期化 ps2key = PS2KeyRecive(kb_freq, kb_data, kb_clock) # PS2KeyRecive ドライバの起動 ps2key.set_active() # 連続して文字入力がある場合・・・1Frame Time の設定 # TenKey 機能ボタンなどでは、最短で 2.5ms周期くらいで文字データが発生する。 # 5ms:(10MHz*50ms*1000us)/PIOクロック数 2 time_out = int((KB_PIO_FRQ * 5) / (1000 * 2)) ps2key.put_timer(time_out) tone_num = 0 ComNum = 0 OpNum = 0 print('Main Loop メモリ使用状況') micropython.mem_info() # PrintMtxLED 画面消去 ymf825.uart_write_multi('%IJ.CLS\n') #---------------------------------------------------------------------------- # MicroPython Main Loop while True: SysRq = 0 while SysRq == 0: # Tone(音色:楽器)指定 # tone_num = ymf825.selectTone(tone_num)をベースに内蔵した # SysRq(PrtSc)キーが押される、または、RFID-CARD、TAGが置かれても終了する dsp_msg = 'Select Tone' tone_num = selectTone(dsp_msg, tone_num) if SysRq == 0: # SysRq(PrtSc)キー押下による終了ではなく # tone_num が指定された=中心的な処理ルーチン # 指定された ToneEdit リストを編集用リスト(VoiceEdit)にコピー ymf825.copyTone2_Voice(tone_num) # Edit Voice Common parameter ComNum = editVoiceCom(ymf825.Voice_Com_Edit, ymf825.VoiceComName, tone_num, ComNum) # Edit Voice Operator Parameter OpNum = editVoiceOp(ymf825.Voice_Op_Edit, ymf825.VoiceOpName, tone_num, OpNum) # 編集結果(VoiceEdit)をシリアル出力 ymf825.serialOutVoiceData(tone_num) # 編集結果(VoiceEdit)を ToneEdit リストにコピーする(戻す) ymf825.copyVoice2_Tone(tone_num) # ToneNameの編集と ToneName の更新 old_name = ymf825.ToneName[tone_num] # 20240716 Change into main # new_name = editToneName(old_name) for i in range(7): EditMsg[i][0] = st7789.WHITE EditMsg[i][1] = '' EditMsg[0][0] = st7789.YELLOW EditMsg[0][1] = 'Edit Tone Name' EditMsg[1][0] = st7789.MAGENTA EditMsg[1][1] = 'Before Name' EditMsg[2][0] = st7789.WHITE EditMsg[2][1] = old_name EditMsg[3][0] = st7789.CYAN EditMsg[3][1] = 'After Name' # Line_n は、編集行 line_n = 4 new_name = editName(EditMsg, line_n, old_name) print('new_name =', new_name) # YMF825 ToneName の更新 ################################################ ymf825.ToneName[tone_num] = new_name ################################################ # ST7789表示用 ToneMenuTable の更新 ################################################ ymf825.ToneMenuTable[tone_num +1][1] = new_name ################################################ # Toneデータを、転送用に準備 # Tone_Com_Edit, Tone_Op_Edit を ASCII2文字の send_buffに変換 ymf825.takeOutToneData(tone_num) # UARTに送信する前に、文字列の先頭と末尾から、スペースを取り除く # RFID用に編集した名残で末尾にスペースが16個入っているのを取り除く # PicoSub側でも、受信前に空読みするよう対応済みだが ymf825.send_buff = ymf825.send_buff.strip() # PicoSub に ToneData を送信 setToneDataPicoSub(tone_num) else: if SysRq == 1: # Keyboard SysRq [PrtSc] キー押下なら 全メニューを表示して選択する dsp_msg = 'Select Function' num = 1 # 1:Edit Tone is Default num = selectFunction(dsp_msg, num) print(f'{num} = selectFunction(dsp_msg, num)') # メニュー画面で選択された num に応じた Functionを実行 if num == 1: # 1:Edit Tone pass elif num == 2: # 2:Read RFID for i in range(7): AlarmMsg[i] = '' AlarmMsg[0] = 'Set RFID' AlarmMsg[1] = ' CARD or TAG' # MFRC522(13.56MHz)RFID にタグやカードが置かれるまで待つ OnOff = False # On:False Off:True waitTag(AlarmMsg, OnOff) # RFID カード または タグを読み込み rcv_buff に格納 print('(stat, rcv_size, headerID, tone_name, rcv_tone) = midi.readRfidTone()') print('4秒以内に RFID-CAD または RFID-TAG を置いてください。') midi.tag_read_timer = midi.NO_TAG_TIME (stat, rcv_size, headerID, tone_name, rcv_tone) = midi.readRfidTone() print(f'stat={stat} rcv_size={rcv_size} headerID={headerID} tonename={tone_name}') if stat == RFID_OK: # RFID 読み取りOK if headerID == '0': # headerID == '0': Tone Data # SubMenuを表示して取り込むか、キャンセルかを選択する for i in range(7): SubMenu[i] = '' SubMenu[0] = 'RFID Data is...' SubMenu[1] = '0:ToneData' SubMenu[2] = tone_name SubMenu[4] = 'Select Action' SubMenu[5] = 'TakeIn Cancel' SubMenu[6] = '=Enter =Esc' if selectSubMenu(SubMenu): # Enter:True なら # RFID から読み込んだ ToneData をどの場所に保存するか。 print('tone_num =', tone_num) print(f'tone_num = selectTone(dsp_msg, {tone_num})') # 20240710 Change # tone_num = ymf825.selectTone(tone_num) から変更 dsp_msg = 'Save Tone As...' tone_num = selectTone(dsp_msg, tone_num) print(f'{tone_num} =selectTone(dsp_msg, tone_num)') #################################################### ymf825.rcv_tone = rcv_tone #################################################### # 指定された保存場所に ToneData を保存する print(f'ymf825.rcv_tone[0] = {tone_num}') #################################################### ymf825.rcv_tone[0] = tone_num ymf825.takeInToneData() #################################################### # ToneNameの更新、ST7789表示用 ToneMenuTable の更新 #################################################### ymf825.ToneName[tone_num] = tone_name ymf825.ToneMenuTable[tone_num +1][1] = tone_name #################################################### # MFRC522(13.56MHz)RFID にタグやカードが取り除かれるまで待つ for i in range(7): AlarmMsg[i] = '' AlarmMsg[0] = 'Read End RFID' AlarmMsg[2] = 'Remove RFID' AlarmMsg[3] = ' CARD or TAG' OnOff = True # On:False Off:True waitTag(AlarmMsg, OnOff) else: # Esc:False なら pass # 何もせず終了 else: # headerID=='0' 以外の場合 # MIDI Data ? # ToneTable ? pass # 組み込む必要あり elif num == 3: # 3:Write RFID for i in range(7): AlarmMsg[i] = '' AlarmMsg[0] = 'Set RFID' AlarmMsg[1] = ' CARD or TAG' # MFRC522(13.56MHz)RFID にタグやカードが置かれるまで待つ OnOff = False # On:False Off:True waitTag(AlarmMsg, OnOff) # RFID カード または タグを読み込み rcv_buff に格納 print('(stat, rcv_size, headerID, tone_name, rcv_tone) = midi.readRfidTone()') print('4秒以内に RFID-CAD または RFID-TAG を置いてください。') midi.tag_read_timer = midi.NO_TAG_TIME (stat, rcv_size, headerID, tone_name, rcv_tone) = midi.readRfidTone() print(f'stat={stat} rcv_size={rcv_size} headerID={headerID} tonename={tone_name}') if stat == RFID_OK: # RFID 読み取りOK # SubMenuを表示して書き込むか、キャンセルかを選択する for i in range(7): SubMenu[i] = '' SubMenu[0] = 'RFID Data is...' SubMenu[4] = 'Select Action' SubMenu[5] = 'WriteOn Cancel' SubMenu[6] = '=Enter =Esc' if headerID == '0': # headerID == '0': Tone Data SubMenu[1] = '0:ToneData' SubMenu[2] = tone_name else: # headerID != '0': Tone Data ではない SubMenu[1] = 'Not ToneData' SubMenu[2] = '' if selectSubMenu(SubMenu): # Enter:True # 書き込みを選択 # Tone_Com_Edit, Tone_Op_Edit を ASCII2文字の send_buffに変換 ymf825.takeOutToneData(tone_num) # send_buff を RFID で書き込み print('midi.writeRfidTone(ymf825.send_buff)') print('ymf825.send_buff size= ', len(ymf825.send_buff)) print('ymf825.send_buff = ', ymf825.send_buff) print('4秒以内に RFID-CAD または RFID-TAG を置いてください。') ######################################################## midi.tag_write_timer = midi.NO_TAG_TIME midi.writeRfidTone(ymf825.send_buff) ######################################################## print('書き込みが完了しました。 RFID-CAD または RFID-TAG を取り除いてください。') # MFRC522(13.56MHz)RFID にタグやカードが取り除かれるまで待つ for i in range(7): AlarmMsg[i] = '' AlarmMsg[0] = 'Write End RFID' AlarmMsg[2] = 'Remove RFID' AlarmMsg[3] = ' CARD or TAG' OnOff = True # On:False Off:True waitTag(AlarmMsg, OnOff) elif num == 4: # 4:Play MIDI # Select Swapping Channel for i in range(7): InputMsg[i] = '' InputMsg[0] = 'Play MIDI' InputMsg[1] = 'Select' InputMsg[2] = ' Channel 1' InputMsg[3] = ' Swap to 1-16' InputMsg[4] = 'No Swapping = 1' prompt_row = 5 prompt = 'ch ? ' ch_asc = '00' ch_asc = inputNum(InputMsg, prompt_row, prompt, ch_asc) print(f'{ch_asc} = inputNum(InputMsg, prompt_row, {prompt}, ch_asc)') ch_num = int(ch_asc) if ch_num < 1 or ch_num > 16: # 1-16 以外が選択されたなら 1(No Swapping)にする。 ch_num = 1 # 1-16が選択されたなら 0-15にする midi_ex_ch = int(ch_num -1) % 16 # 整数を2桁の16進数文字(0-9 A-F)に変換 (asc_Hn, asc_Ln) = moji.int2asc2(midi_ex_ch) # Select GM Musical No for i in range(7): InputMsg[i] = '' InputMsg[0] = 'Play MIDI' InputMsg[1] = "Swapping Ch's" InputMsg[2] = ' TONE is' InputMsg[3] = ' GM No 1-128' InputMsg[4] = ' 0:Grand Piano' prompt_row = 5 prompt = 'GM Tone ? ' gm_asc = '000' # '000':3桁の編集を指示 table = ymf825.GmName gm_asc = inputNumTable(InputMsg, table, prompt_row, prompt, gm_asc) print(f'{gm_asc} = inputNumTable(InputMsg, table, prompt_row, {prompt}, gm_asc)') # 数字文字を整数に変換 gm_num = int(gm_asc) print(f'{gm_num} = int(gm_asc)') if gm_num < 1 or gm_num > 128: # 1-128 以外が選択されたなら 1(Grand Piano)にする。 gm_num = 1 # 1-128が選択されたなら 0-127にする。 # 整数を2桁の16進数文字(0-9 A-F)に変換 (asc_H, asc_L) = moji.int2asc2(gm_num -1) print(f'({asc_H}, {asc_L}) = moji.int2asc2({gm_num -1})') # Program Change 文字列の生成(CnXX) prgChangeB = 'C' + asc_Ln + asc_H + asc_L # Program Change 文字列の生成(CnXX)を MIDI-Outに出力する ########################################## midi.midi_writeB(prgChangeB) ########################################## display.fill(st7789.BLACK) for i in range(7): AlarmMsg[i] = '' AlarmMsg[0] = 'Playing MIDI' # 選択された楽器の名称を表示 AlarmMsg[1] = moji.strFixL_n(ymf825.GmName[gm_num], ST7789_COL_SIZE) AlarmMsg[2] = ' STOP' AlarmMsg[3] = ' =Esc' # colorFont = backColor # def every997ms(t): で決まる色 colorFont = st7789.RED alarm(AlarmMsg) # 「Esc」キー押下で終了 # MIDI-Inから入力、チャンネル変換し MIDI-Outに出力、midi_listに保存する。 ################################################ # midi.midi_frame_timer = midi.NO_VOICE_TIME # 時間制限をなくした midi.midi_play(midi_ex_ch) ################################################ elif num == 5: # 5:'Print DFP Test' # F5 for i in range(7): EditMsg[i][0] = st7789.WHITE EditMsg[i][1] = '' EditMsg[0][0] = st7789.YELLOW EditMsg[0][1] = 'Print DFP' EditMsg[1][0] = st7789.WHITE EditMsg[1][1] = 'PLAY mp3' EditMsg[2][0] = st7789.CYAN EditMsg[2][1] = 'Command ?' # Line_n は、編集行 line_n = 3 old_command = 'PLAY 1 1' new_command = printDFP(EditMsg, line_n, old_command) elif num == 6: # 6:Edt Tn Table ################################################### # ToneTable を使う場面はありや? # この関数は、キーボード対応のみ(マウスは対応できていない) ################################################### # editToneTable() 関数の入力テスト editToneTable(ymf825.ToneTable, ymf825.ToneName) # PicoSub に ToneTable を送信 setToneTablePicoSub() elif num == 7: # 7:Edt Mk Voice midi.playHectOne(HectOne) # Copy HectOnVoice to HectOne # Test 7 syu for i in range(7): # ローマ字 31文字文を連結する voiceRm = HectOneVoice[i][0] + \ HectOneVoice[i][1] + \ HectOneVoice[i][2] + \ HectOneVoice[i][3] + \ HectOneVoice[i][4] # 文字数が不足するとエラーが発生するはず try: pt = 0 for j in range(31): if voiceRm[pt].lower() == 'a'.lower() or \ voiceRm[pt].lower() == 'i'.lower() or \ voiceRm[pt].lower() == 'u'.lower() or \ voiceRm[pt].lower() == 'e'.lower() or \ voiceRm[pt].lower() == 'o'.lower(): HectOne[j +1][1] = voiceRm[pt] pt += 1 elif voiceRm[pt +1].lower() == 'y'.lower() or \ voiceRm[pt +1].lower() == 'h'.lower() or \ voiceRm[pt +1].lower() == 'w'.lower() or \ voiceRm[pt +1].lower() == 's'.lower(): HectOne[j +1][1] = voiceRm[pt] + \ voiceRm[pt +1] + \ voiceRm[pt +2] pt += 3 else: HectOne[j +1][1] = voiceRm[pt] + \ voiceRm[pt +1] pt += 2 except: print('Error In Copy HectOnVoice to HectOne') pass midi.playHectOne(HectOne)

PicoSubプログラム

PicoS_main_py.py

PicoS_main_py.py

############################################################################# # PicoS_main_py.py Programed by Hyodo # PicoS(YMF825)HectOne-026.py をベースに、イコライザー(フィルター)機能を追加 # # MIDI Keyboard(鍵盤)からの入力で和音を実現するため、MONO TONEで # チャンネルを割り振って利用する方法を試行する。 # # PicoMain と PicoSub で分担して処理する。 # このプログラムは、PicoSub用のプログラムである。 # PicoSub には、YMF825のみが接続されており、 # PicoMain とシリアル通信で接続し、PicoMain からシリアルで送られてくる # ToneData と ToneTable を利用して、YMF825 から音出し(演奏)する。 # MIDI信号を受信し、音出し(演奏)ができる。 # # 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 >>> <<< 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 # # ############################################################################# 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 >>> <<< 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 # 念のために確認 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) 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) ####################################################################### # 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 midiKeyboardPlayYmf825(): 関数を内蔵して自動切り替えする。 # 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 !') allNoteOff() uartRtsBusy = 1 return ####################################################################### # MIDI 入力を演奏する # Keyboardからの MIDIは、ch=0 だけなので、 MONO TONE にして和音対応する。 # 20240717:def midiKeyboardPlayYmf825(): 関数を内蔵して自動切り替えする。 # PicoMain からの送信要求(uartRtsReq)があれば、中断する。 def midiPlayYmf825(): 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() # 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) 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 !') allNoteOff() uartRtsBusy = 1 return ####################################################################### # note off = 8n kk vv or 9n kk 00 # note on = 9n kk vv # 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 # ymf825.set_MasterVolume(32) ymf825.set_MasterVolume(24) ymf825.init_tone() print('初期設定の音源で発音テスト(= ToneTable の登録に従って音出し)') domisoTest() 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() tone_num = 0 # ComNum = 0 # OpNum = 0 uartRtsReq = 0 # PicoMain からの送信要求 uartRtsBusy = 0 # UART COM RECIVE 実行中 ############################################################################## # Main 直前で起動する Timer(period=10, callback=every10ms) ############################################################################## #---------------------------------------------------------------------------- # MicroPython Main Loop while True: if uartRtsReq == 1 and uartRtsBusy == 1: uartComRcv() # PicoMain からの受信処理 uartRtsBusy = 0 # UART COM RECIVE 実行終了 uartRtsReq = 0 # PicoMain からの送信要求 クリア else: # MIDI 受信・演奏をここに ・・・ midiPlayYmf825() # uartRtsReq == 1: PicoMain からの送信要求 あれば、処理を中断し、 # uartRtsBusy = 1: UART COM RECIVE 実行開始 をセットして戻る。 # 中断がない限り戻ってこない。 ############################### # 20240705 Change # midiPlayYmf825() # 20240927 Change midiPlayChaimeModeYmf825() ############################### # midiKeyboardPlayYmf825()

PicoM_Lib

(以下のプログラムは予めPicoMainに書き込んでおいてください)
mfrc522.py

mfrc522.py

from machine import Pin, SPI from os import uname class MFRC522: DEBUG = False OK = 0 NOTAGERR = 1 ERR = 2 REQIDL = 0x26 REQALL = 0x52 AUTHENT1A = 0x60 AUTHENT1B = 0x61 PICC_ANTICOLL1 = 0x93 PICC_ANTICOLL2 = 0x95 PICC_ANTICOLL3 = 0x97 def __init__(self, sck, mosi, miso, rst, cs,baudrate=1000000,spi_id=0): self.sck = Pin(sck, Pin.OUT) self.mosi = Pin(mosi, Pin.OUT) self.miso = Pin(miso) self.rst = Pin(rst, Pin.OUT) self.cs = Pin(cs, Pin.OUT) self.rst.value(0) self.cs.value(1) board = uname()[0] if board == 'WiPy' or board == 'LoPy' or board == 'FiPy': self.spi = SPI(0) self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso)) elif (board == 'esp8266') or (board == 'esp32'): self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) self.spi.init() elif board == 'rp2': self.spi = SPI(spi_id,baudrate=baudrate,sck=self.sck, mosi= self.mosi, miso= self.miso) else: raise RuntimeError("Unsupported platform") self.rst.value(1) self.init() def _wreg(self, reg, val): self.cs.value(0) self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) self.spi.write(b'%c' % int(0xff & val)) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) val = self.spi.read(1) self.cs.value(1) return val[0] def _sflags(self, reg, mask): self._wreg(reg, self._rreg(reg) | mask) def _cflags(self, reg, mask): self._wreg(reg, self._rreg(reg) & (~mask)) def _tocard(self, cmd, send): recv = [] bits = irq_en = wait_irq = n = 0 stat = self.ERR if cmd == 0x0E: irq_en = 0x12 wait_irq = 0x10 elif cmd == 0x0C: irq_en = 0x77 wait_irq = 0x30 self._wreg(0x02, irq_en | 0x80) self._cflags(0x04, 0x80) self._sflags(0x0A, 0x80) self._wreg(0x01, 0x00) for c in send: self._wreg(0x09, c) self._wreg(0x01, cmd) if cmd == 0x0C: self._sflags(0x0D, 0x80) i = 2000 while True: n = self._rreg(0x04) i -= 1 if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): break self._cflags(0x0D, 0x80) if i: if (self._rreg(0x06) & 0x1B) == 0x00: stat = self.OK if n & irq_en & 0x01: stat = self.NOTAGERR elif cmd == 0x0C: n = self._rreg(0x0A) lbits = self._rreg(0x0C) & 0x07 if lbits != 0: bits = (n - 1) * 8 + lbits else: bits = n * 8 if n == 0: n = 1 elif n > 16: n = 16 for _ in range(n): recv.append(self._rreg(0x09)) else: stat = self.ERR return stat, recv, bits def _crc(self, data): self._cflags(0x05, 0x04) self._sflags(0x0A, 0x80) for c in data: self._wreg(0x09, c) self._wreg(0x01, 0x03) i = 0xFF while True: n = self._rreg(0x05) i -= 1 if not ((i != 0) and not (n & 0x04)): break return [self._rreg(0x22), self._rreg(0x21)] def init(self): self.reset() self._wreg(0x2A, 0x8D) self._wreg(0x2B, 0x3E) self._wreg(0x2D, 30) self._wreg(0x2C, 0) self._wreg(0x15, 0x40) self._wreg(0x11, 0x3D) self.antenna_on() def reset(self): self._wreg(0x01, 0x0F) def antenna_on(self, on=True): if on and ~(self._rreg(0x14) & 0x03): self._sflags(0x14, 0x03) else: self._cflags(0x14, 0x03) def request(self, mode): self._wreg(0x0D, 0x07) (stat, recv, bits) = self._tocard(0x0C, [mode]) if (stat != self.OK) | (bits != 0x10): stat = self.ERR return stat, bits def anticoll(self,anticolN): ser_chk = 0 ser = [anticolN, 0x20] self._wreg(0x0D, 0x00) (stat, recv, bits) = self._tocard(0x0C, ser) if stat == self.OK: if len(recv) == 5: for i in range(4): ser_chk = ser_chk ^ recv[i] if ser_chk != recv[4]: stat = self.ERR else: stat = self.ERR return stat, recv def PcdSelect(self, serNum,anticolN): backData = [] buf = [] buf.append(anticolN) buf.append(0x70) #i = 0 ###xorsum=0; for i in serNum: buf.append(i) #while i<5: # buf.append(serNum[i]) # i = i + 1 pOut = self._crc(buf) buf.append(pOut[0]) buf.append(pOut[1]) (status, backData, backLen) = self._tocard( 0x0C, buf) if (status == self.OK) and (backLen == 0x18): return 1 else: return 0 def SelectTag(self, uid): byte5 = 0 #(status,puid)= self.anticoll(self.PICC_ANTICOLL1) #print("uid",uid,"puid",puid) for i in uid: byte5 = byte5 ^ i puid = uid + [byte5] if self.PcdSelect(puid,self.PICC_ANTICOLL1) == 0: return (self.ERR,[]) return (self.OK , uid) def tohexstring(self,v): s="[" for i in v: if i != v[0]: s = s+ ", " s=s+ "0x{:02X}".format(i) s= s+ "]" return s def SelectTagSN(self): valid_uid=[] (status,uid)= self.anticoll(self.PICC_ANTICOLL1) #print("Select Tag 1:",self.tohexstring(uid)) if status != self.OK: return (self.ERR,[]) if self.DEBUG: print("anticol(1) {}".format(uid)) if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0: return (self.ERR,[]) if self.DEBUG: print("pcdSelect(1) {}".format(uid)) #check if first byte is 0x88 if uid[0] == 0x88 : #ok we have another type of card valid_uid.extend(uid[1:4]) (status,uid)=self.anticoll(self.PICC_ANTICOLL2) #print("Select Tag 2:",self.tohexstring(uid)) if status != self.OK: return (self.ERR,[]) if self.DEBUG: print("Anticol(2) {}".format(uid)) rtn = self.PcdSelect(uid,self.PICC_ANTICOLL2) if self.DEBUG: print("pcdSelect(2) return={} uid={}".format(rtn,uid)) if rtn == 0: return (self.ERR,[]) if self.DEBUG: print("PcdSelect2() {}".format(uid)) #now check again if uid[0] is 0x88 if uid[0] == 0x88 : valid_uid.extend(uid[1:4]) (status , uid) = self.anticoll(self.PICC_ANTICOLL3) #print("Select Tag 3:",self.tohexstring(uid)) if status != self.OK: return (self.ERR,[]) if self.DEBUG: print("Anticol(3) {}".format(uid)) if self.MFRC522_PcdSelect(uid,self.PICC_ANTICOLL3) == 0: return (self.ERR,[]) if self.DEBUG: print("PcdSelect(3) {}".format(uid)) valid_uid.extend(uid[0:5]) # if we are here than the uid is ok # let's remove the last BYTE whic is the XOR sum return (self.OK , valid_uid[:len(valid_uid)-1]) #return (self.OK , valid_uid) def auth(self, mode, addr, sect, ser): return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] def authKeys(self,uid,addr,keyA=None, keyB=None): status = self.ERR if keyA is not None: status = self.auth(self.AUTHENT1A, addr, keyA, uid) elif keyB is not None: status = self.auth(self.AUTHENT1B, addr, keyB, uid) return status def stop_crypto1(self): self._cflags(0x08, 0x08) def read(self, addr): data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) return stat, recv def write(self, addr, data): buf = [0xA0, addr] buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR else: buf = [] for i in range(16): buf.append(data[i]) buf += self._crc(buf) (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR return stat def writeSectorBlock(self,uid, sector, block, data, keyA=None, keyB = None): absoluteBlock = sector * 4 + (block % 4) if absoluteBlock > 63 : return self.ERR if len(data) != 16: return self.ERR if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR : return self.write(absoluteBlock, data) return self.ERR def readSectorBlock(self,uid ,sector, block, keyA=None, keyB = None): absoluteBlock = sector * 4 + (block % 4) if absoluteBlock > 63 : return self.ERR, None if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR : return self.read(absoluteBlock) return self.ERR, None def MFRC522_DumpClassic1K(self,uid, Start=0, End=64, keyA=None, keyB=None): for absoluteBlock in range(Start,End): status = self.authKeys(uid,absoluteBlock,keyA,keyB) # Check if authenticated print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock//4 , absoluteBlock % 4),end="") if status == self.OK: status, block = self.read(absoluteBlock) if status == self.ERR: break else: for value in block: print("{:02X} ".format(value),end="") print(" ",end="") for value in block: if (value > 0x20) and (value < 0x7f): print(chr(value),end="") else: print('.',end="") print("") else: break if status == self.ERR: print("Authentication error") return self.ERR return self.OK

midipy2.py

midipy2.py

############################################################################### # MIDI i/f Programed by Hyodo # midipy2.py # 2024/04/15:Rfid2Midi-542.py の MIDI i/f 部分を分離して # ライブラリとして利用できるように再構成した。 # 20240603:不要となった st7789,ps/2Mouseなどのコマンドを削除して # テスト デバッグ用に if __name__ == '__main__': を用意した。 # # RFID-RC522 と PicoMain との接続 # RFID-RC522 <<< Pico >>> # RST (7) --紫-- (29) gpio-22 # 3V3 (8) --灰-- 3.3V # MOSI (3) --橙-- (24) gpio-19 MOSI # SCK (2) --赤-- (23) gpio-18 MISO # GND (6) --青-- (22) GND # SDA-CE (1) --茶-- (21) gpio-17 CE # MISO (4) --黄-- (20) gpio-16 MISO # IRQ (5) --緑-- pull-up 10K No Connect # # ############################################################################### from machine import Timer, SPI, UART, Pin import utime from micropython import const import mojipy as moji from mfrc522 import MFRC522 ############################################################################### # Thonnyで 当該ファイルを開いて、Pico直下に書き込む。 # mojipy.py : 文字変換用 # mfrc522.py : RFID-RC522 接続用 ############################################################################### # Pocket Miku 用の文字辞書 # ローマ字からコードに変換する exRmPkMiku = {'a':0, 'i':1, 'u':2, 'e':3, 'o':4, 'ka':5, 'ki':6, 'ku':7, 'ke':8, 'ko':9, 'ga':10, 'gi':11, 'gu':12, 'ge':13, 'go':14, 'kya':15, 'kyu':16, 'kyo':17, 'gya':18, 'gyu':19, 'gyo':20, 'sa':21, 'swi':22, 'su':23, 'se':24, 'so':25, 'za':26, 'zwi':27, 'zu':28, 'ze':29, 'zo':30, 'sya':31, 'si':32, 'syu':33, 'sye':34, 'syo':35, 'ja':36, 'ji':37, 'ju':38, 'je':39, 'jo':40, 'ta':41, 'thi':42, 'twu':43, 'te':44, 'to':45, 'da':46, 'dhi':47, 'dwu':48, 'de':49, 'do':50, 'thu':51, 'dhu':52, 'tya':53, 'ti':54, 'tyu':55, 'tye':56, 'tyo':57, 'tsa':58, 'tsi':59, 'tu':60, 'tse':61, 'tso':62, 'na':63, 'ni':64, 'nu':65, 'ne':66, 'no':67, 'nya':68, 'nyu':69, 'nyo':70, 'ha':71, 'hi':72, 'hu':73, 'he':74, 'ho':75, 'ba':76, 'bi':77, 'bu':78, 'be':79, 'bo':80, 'pa':81, 'pi':82, 'pu':83, 'pe':84, 'po':85, 'hya':86, 'hyu':87, 'hyo':88, 'bya':89, 'byu':90, 'byo':91, 'pya':92, 'pyu':93, 'pyo':94, 'fa':95, 'fi':96, 'fu':97, 'fe':98, 'fo':99, 'ma':100, 'mi':101, 'mu':102, 'me':103, 'mo':104, 'mya':105, 'myu':106, 'myo':107, 'ya':108, 'yu':109, 'yo':110, 'ra':111, 'ri':112, 'ru':113, 're':114, 'ro':115, 'rya':116, 'ryu':117, 'ryo':118, 'wa':119, 'wi':120, 'we':121, 'wo':122, 'nn':123, 'm':124, 'n':125, 'j':126, } TONE_HEADER = const(16) TONE_DATA_ROW_NUM = const(42) TONE_TABLE_ROW_NUM = const(17) TONE_NUM = const(16) TONE_ANL_COL = const(10) RFID_BLOCK_SIZE = const(16) # RFID のブロックサイズ RFID_ADDRESS_MAX = const(45) # RFID の最大アドレス # プログラムチェンジ(音色変更)記録用のポインタ ChTnPt = [None] * TONE_NUM for i in range(TONE_NUM): ChTnPt[i] = 0 # プログラムチェンジ(音色変更)記録用のリスト ChTnList = [None] * TONE_NUM for i in range(TONE_NUM): ChTnList[i] = [None] * TONE_ANL_COL # MFRC522 SPI 設定 # どういう訳か、Pin() ではダメ・・・多分受け入れ側(ライブラリ)の仕組みか? # xxx rfid_13M_reader=MFRC522(spi_id=0,sck=Pin(6),miso=Pin(4),mosi=Pin(7),cs=Pin(5),rst=Pin(22)) rfid_13M_reader = MFRC522(spi_id=0, sck=18, miso=16, mosi=19, cs=17, rst=22) # シリアル uart_midi を生成 # MIDI は、31250bpsである。 MIDI_BAUD_RATE = 31250 uart_midi = UART(0, MIDI_BAUD_RATE,bits=8,parity=None,stop=1,tx=Pin(0),rx=Pin(1)) # 待ち時間タイマー値 NO_VOICE_TIME = const(4000) # 4000ms=4秒以上の無音空白時間で受信終了とみなす NO_TAG_TIME = const(4000) # 4000ms=4秒以上、TAG が置かれないと終了とみなす # 20240417 Change # TAG_BLOCK_TIME = const(250) # TAG BLOCK 読み取り中断を検出する TAG_BLOCK_TIME = const(300) # TAG BLOCK 読み取り中断を検出する MASK_NEXT_READ = const(500) # 次の TAG 読み込み可能までの不感時間 SWITCH_TASK_TIME = const(500) # マルチタスク処理のための時間管理 # Main との通信用(参照し制御する) # 停止状態にセット stop = 1 end = 1 # 時分割処理のためのタイマー # global変数定義。関数で利用するグローバル変数は、関数の定義前に書くのが無難。 midi_frame_timer = 0 # 無音空白時間カウント(減算) midi_ikg_timer = 0 # midi inter key gap time:(積算) midi_ikg_wait = 0 # midi inter key gap wait:(減算) tag_read_timer = 0 # > 0 で TAG 読み取り優先(減算) tag_write_timer = 0 # > 0 で TAG 書き込み優先(減算) tag_play_timer = 0 # > 0 で TAG 再生を優先(減算) tag_block_timer = 0 # == 0 で TAG BLOCK 読み取り中断を検出(減算) wait_next_read = 0 # TAG 先読み禁止時間(減算)MASK_NEXT_READ で設定 wait_midi_write = 0 # TAG 先読み許可時間(減算)SWITCH_TASK_TIME で設定 ps2kb_timer = 0 # = 0 で Key buff を空読み(減算) rfid_interval = 0 # 500ms 毎に、RFIDにタグやカードがあるかチェックする。 # 10ms 毎に割り込みが発生する なぜか引数 (t) は必須である。 def every10ms(t): ########################################################## global midi_frame_timer, midi_ikg_timer, midi_ikg_wait global tag_read_timer, tag_write_timer, rfid_interval global tag_play_timer, tag_block_timer, wait_next_read global wait_midi_write, ps2kb_timer ########################################################## if midi_frame_timer < 10: midi_frame_timer = 0 else: midi_frame_timer -= 10 if midi_ikg_timer < 10000: midi_ikg_timer += 10 if midi_ikg_wait < 10: midi_ikg_wait = 0 else: midi_ikg_wait -= 10 if tag_read_timer < 10: tag_read_timer = 0 else: tag_read_timer -= 10 if tag_write_timer < 10: tag_write_timer = 0 else: tag_write_timer -= 10 if tag_play_timer < 10: tag_play_timer = 0 else: tag_play_timer -= 10 if tag_block_timer < 10: tag_block_timer = 0 else: tag_block_timer -= 10 if wait_next_read < 10: wait_next_read = 0 else: wait_next_read -= 10 if wait_midi_write < 10: wait_midi_write = 0 else: wait_midi_write -= 10 if ps2kb_timer < 10: ps2kb_timer = 0 else: ps2kb_timer -= 10 if rfid_interval < 0: rfid_interval = 0 else: rfid_interval -= 10 # 20240416 10ms # 10ms 毎に every1ms を呼び出す呪文。これ以前に callback関数を定義のこと。 # Timer(period=10, mode=Timer.PERIODIC, callback=every10ms) # mode=Timer.PERIODIC は、指定しなくても大丈夫のようだ。 # Timer(period=10, callback=every10ms) でも動作するが # MicroPython説明サイトに従ったタイマーの初期化 tim10 = Timer(period=10, mode=Timer.PERIODIC, callback=every10ms) tim10.init(period=10, callback=every10ms) #---------------------------------------------------------------------------- # 楽譜音階データを MIDIデータに変換関数 # channel、octave、keycode、velocity から、MIDI信号を構成する関数 # 音符(時間)情報は、別管理が必要 def key2midi(channel, octave, key, velocity): channel = channel & 0x0F # 0~F に制限 ビット演算 and byte_1 = 0x90 | channel # ビット演算 or if octave < 0: octave = 0 elif octave > 8: octave = 8 # # print("key.lower() = " ,key.lower()) # if key.lower() == 'c': byte_2 = (octave + 1) * 12 + 0 elif key.lower() == 'c$': byte_2 = (octave + 1) * 12 + 1 elif key.lower() == 'd': byte_2 = (octave + 1) * 12 + 2 elif key.lower() == 'd$': byte_2 = (octave + 1) * 12 + 3 elif key.lower() == 'e': byte_2 = (octave + 1) * 12 + 4 elif key.lower() == 'f': byte_2 = (octave + 1) * 12 + 5 elif key.lower() == 'f$': byte_2 = (octave + 1) * 12 + 6 elif key.lower() == 'g': byte_2 = (octave + 1) * 12 + 7 elif key.lower() == 'g$': byte_2 = (octave + 1) * 12 + 8 elif key.lower() == 'a': byte_2 = (octave + 1) * 12 + 9 elif key.lower() == 'a$': byte_2 = (octave + 1) * 12 + 10 elif key.lower() == 'b': byte_2 = (octave + 1) * 12 + 11 # 変換範囲外の音を、この高い音にする。・・・いいのか、悪いのか? else: byte_2 = 120 # 上限(0x7F:127)を超えないようにする if byte_2 > 127: byte_2 = 127 # 上限(0x7F:127)を超えないようにする # velocity = 0 は、ノートオフ byte_3 = velocity & 0x7F # 20240814 Change # return list([byte_1, byte_2, byte_3]) (asc_H, asc_L) = moji.int2asc2(byte_1) asc_1 = asc_H + asc_L (asc_H, asc_L) = moji.int2asc2(byte_2) asc_2 = asc_H + asc_L (asc_H, asc_L) = moji.int2asc2(byte_3) asc_3 = asc_H + asc_L # 文字列を返す return asc_1 + asc_2 + asc_3 #---------------------------------------------------------------------------- # プログラムチェンジ(音色変更)記録用のポインタ、および、リストの用意 def init_ChTnList(): global ChTnPt global ChTnList # プログラムチェンジ(音色変更)記録用のポインタ ChTnPt = [None] * TONE_NUM for i in range(TONE_NUM): ChTnPt[i] = 0 # プログラムチェンジ(音色変更)記録用のリスト ChTnList = [None] * TONE_NUM for i in range(TONE_NUM): ChTnList[i] = [None] * TONE_ANL_COL #---------------------------------------------------------------------------- # 受信した MIDIプログラムチェンジ(音色変更)をリストへに追加記録 def add_ChTnList(ch, tn): global ChTnPt global ChTnList # プログラムチェンジ(音色変更)記録用のポインタ if ChTnPt[ch & 0x0F] < TONE_ANL_COL: ChTnList[ch & 0x0F][ChTnPt[ch & 0x0F]] = tn & 0x7F ChTnPt[ch & 0x0F] += 1 #---------------------------------------------------------------------------- # 記録した MIDIプログラムチェンジ(音色変更)リストをシリアルアウト def serialOutChTnList(): global ChTnPt global ChTnList for i in range(TONE_NUM): print('PROGRAM CHANGE ', i, ' ', end='') for j in range(ChTnPt[i]): print(ChTnList[i][j], ' ', end='') print() #---------------------------------------------------------------------------- # MIDI ALL SOUND OFF def midiSoundOff(): for i in range(TONE_NUM): midi_buff = moji.byte2chr2(chr(0xB0 | i)) midi_buff += moji.byte2chr2(chr(0x78)) midi_buff += moji.byte2chr2(chr(0x00)) midi_writeB(midi_buff) #---------------------------------------------------------------------------- # 文字列("CB0B" や "B07B00"など)を MIDI に出力 # リスト形式を出力する場合は play_midiList() を利用してネ def midi_writeB(midi_buff): if len(midi_buff) > 0: midi_num_list = [] print(" >>> midi_sendbuff = ", midi_buff) for i in range(0, len(midi_buff), 2): midi_data = midi_buff[i] midi_data += midi_buff[i+1] midi_data_num = moji.chr2dec(midi_data) midi_num_list.append(midi_data_num) # 整数リストから、バイト文字列に変換してコピー midi_data_str = bytes(midi_num_list) # バイト文字列を UART で MIDI送信 uart_midi.write(midi_data_str) #---------------------------------------------------------------------------- # リスト形式([['90', '3C', '40'], ['90', '3C', '40'],...])を MIDI に出力 # 文字列を出力する場合は midi_writeB(midi_buff) を利用してネ # 20240603 Change # def play_midiList(): def play_midiList(midi_list): if midi_list != None: if len(midi_list) > 0: print("UART MIDI Writing...") midi_sendbuff = "" wait_ms = 0 wait_CMD = 0 for i in range(len(midi_list)): for j in range(len(midi_list[i])): # 1バイトを数値に変換 midi_data = moji.chr2dec(midi_list[i][j]) # ステータスバイトなら if midi_data >= 0x80: # F2 タイマー値なら、待ち時間を入れる if midi_data == 0xF2: wait_CMD = 1 # F0 Miku Voice情報なら、メッセージを補完する。 # F0 43 79 09 11 0A 00 # 発音文字コード(00~7F)と、末尾に F7が追加されて完成する。 elif midi_data == 0xF0: midi_sendbuff = 'F0437909110A00' # 0xF7(ユニバーサル・システム・エクスクルーシブ)なら # midi_sendbuff に追加する(データとして扱う) # elif midi_data == 0xF7 and wait_CMD == 0: elif midi_data == 0xF7: midi_sendbuff += midi_list[i][j] # 0xF0 , 0xF2 , 0xF7 以外の ステータスバイトなら # midi_sendbuff の先頭にデータを入れる else: midi_sendbuff = midi_list[i][j] # タイマー値ならば タイマー値の計算をする elif wait_CMD == 1: wait_ms += wait_ms * 128 + moji.chr2dec(midi_list[i][j]) if wait_ms > 10000: wait_ms = 10000 # ステータスバイトでなく、かつ、タイマー値でもなければ # midi_sendbuff に追加する(データとして扱う) else: midi_sendbuff += midi_list[i][j] # MIDI 送信バッファにデータがあれば、USART に出力 if len(midi_sendbuff) > 0: # 文字列を UART で MIDI に送信する print("midi i = ", i, end="") ###################################### midi_writeB(midi_sendbuff) ###################################### midi_sendbuff = "" # 必要ないかもしれないが・・・ if wait_ms > 0: print("midi i = ", i, end="") print(" >>> wait_time = ", wait_ms) utime.sleep_ms(wait_ms) wait_ms = 0 wait_CMD = 0 else: print("midi_list has no data ! ") else: print("midi_list is None ! ") #---------------------------------------------------------------------------- # 「F4」キーを押してから、4秒(=tag_read_timer)以内にTAG を置くこと # 「F4」キーを押す前に、TAGを置くと、常時 TAG Read が動作する # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら読み込む # タグやカードが4秒以内に置かれなければ、何もせず終了 def tag_read(): global tag_read_timer while tag_read_timer > 0: # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら読み込む rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) if stat == rfid_13M_reader.OK: (stat, uid) = rfid_13M_reader.SelectTagSN() if stat == rfid_13M_reader.OK: # Read Data 準備 key_A = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] # tag_rcvbuff = "" tag_address = 0 for tag_address in range(42): # tag_address を sector と block に換算 sector = int(tag_address / 3) + 1 block = tag_address % 3 # TAG を読み込む (stat, block_data_r) = rfid_13M_reader.readSectorBlock(uid ,sector, block, keyA=key_A, keyB = None) if stat == rfid_13M_reader.OK: # print("BLOCK DATA = ", block_data_r) # # 読み込んだ1ブロックを、文字列(tag_rcvbuff)に追加する flag_tag_EOB = 0 # 1:以降のデータを読み取り不要 flag_tag_EOF = 0 # 1:以降のブロックを読み取り不要 for i in range(len(block_data_r)): # スペース、または、Null('00')ならば、 if block_data_r[i] == 0x20 or block_data_r[i] == 0x00: # ブロックの先頭なら、EOF と判断する if i == 0: flag_tag_EOF = 1 break # ブロックの先頭でなければ、EOB ブロック終了 else: flag_tag_EOB = 1 break # スペース、または、Null('00')でなければ、受信バッファに追加する # 整数リストから文字列に変換する else: tag_rcvbuff += chr(block_data_r[i]) # 常時稼働時には、エラー表示が邪魔なので、出さない else: print ("rfid_13M_reader Read Error") # EOF を検出したら、以降のブロックを読まないで終了する。 if flag_tag_EOF == 1: break # tag_rcvbuf を midi_list に収納する midi_list = [] if len(tag_rcvbuff) > 0: print("tag_rcvbuff Size = ", len(tag_rcvbuff)) temp_list = [] temp_buff = "" begin = 1 for i in range(len(tag_rcvbuff)): # 偶数ならば if (i % 2) == 0: # 直前の temp_list を midi_list に追加する # ただし、一番先頭(空データ)は追加しない if ord(tag_rcvbuff[i]) >= 0x38 and ord(tag_rcvbuff[i]) != 0xF7: if begin == 1: begin = 0 else: midi_list.append(temp_list) temp_list = [] # temp_buff に追加する temp_buff += tag_rcvbuff[i] # 奇数ならば、偶数桁と合わせて、temp_buff に追加する else: temp_buff += tag_rcvbuff[i] temp_list.append(temp_buff) temp_buff = "" # temp_list を midi_list にコピーする midi_list.append(temp_list) print("MIDI List = ", midi_list) # return midi_list break # tag_read_timer == 0 ならの else を skip # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print("No TAG or CARD") # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print ("rfid_13M_reader is not Raedy") # # tag_read_timer == 0 なら else: print("TAG Read Time Over") #---------------------------------------------------------------------------- # MFRC522(13.56MHz)RFID にタグやカードが置かれているかチェックする def checkOnRfid(): rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら取り除かれるまで待つ if stat == rfid_13M_reader.OK: # print('checkOnRfid(): stat == rfid_13M_reader.OK') return True else: # print('checkOnRfid(): stat != rfid_13M_reader.OK') return False ''' #---------------------------------------------------------------------------- # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら取り除かれるまで待つ def waitRemoveRfid(): rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら取り除かれるまで待つ while stat == rfid_13M_reader.OK: print('RFID-CAD または RFID-TAG を 取り除いてください。') utime.sleep_ms(1000) (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) ''' #---------------------------------------------------------------------------- # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら # headerID と headerName を読み込む # 1回のみ実行する。タグやカードが置かれていなければ、何もせず終了 # rcv_buff は、ASCII 2文字の文字列 def readRfidHeader(): # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら # tag_address = 0(セクター1、ブロック0) の16バイトを読み込む rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) if stat == rfid_13M_reader.OK: (stat, uid) = rfid_13M_reader.SelectTagSN() if stat == rfid_13M_reader.OK: # Read Data 準備 key_A = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] tag_rcvbuff = "" tag_address = 0 # tag_address を sector と block に換算 sector = int(tag_address / 3) + 1 block = tag_address % 3 # TAG を読み込む (stat, block_data_r) = rfid_13M_reader.readSectorBlock(uid ,sector, block, keyA=key_A, keyB = None) if stat == rfid_13M_reader.OK: # 読み込んだ1ブロックを、文字列(tag_rcvbuff)に追加する flag_tag_EOF = 0 # 1:以降のブロックを読み取り不要 for i in range(len(block_data_r)): # ブロックの先頭スペース、または、Null('00')ならば、 if block_data_r[i] == 0x20 or block_data_r[i] == 0x00: # ブロックの先頭なら、EOF と判断する if i == 0: flag_tag_EOF = 1 break else: tag_rcvbuff += chr(block_data_r[i]) # スペース、または、Null('00')でなければ、受信バッファに追加する # 整数リストから文字列に変換する else: tag_rcvbuff += chr(block_data_r[i]) # 常時稼働時には、エラー表示が邪魔なので、出さない else: # DEBUG print # print ("readRfidHeader(): rfid_13M_reader Read Error") headerID = 'Error' headerName = 'RFID Read Error' # EOF を検出したら、以降のブロックを読まないで終了する。 if flag_tag_EOF == 1: headerID = 'Null' headerName = 'Null Data' # 読み取り後の処理 elif len(tag_rcvbuff) > 0: headerID = tag_rcvbuff[0] headerName = tag_rcvbuff[1:TONE_HEADER] # DEBUG print # print('readRfidHeader(): headerID = ', headerID) # print('readRfidHeader(): headerName = ', headerName) return headerID, headerName # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print("No TAG or CARD") # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print ("rfid_13M_reader is not Raedy") #---------------------------------------------------------------------------- # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら読み込む # タグやカードが4秒以内に置かれなければ、何もせず終了 # rcv_buff は、ASCII 2文字の文字列 # tag_read_timer を設定して呼び出すこと def readRfidTone(): global tag_read_timer while tag_read_timer > 0: # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら読み込む rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) if stat == rfid_13M_reader.OK: (stat, uid) = rfid_13M_reader.SelectTagSN() if stat == rfid_13M_reader.OK: # Read Data 準備 key_A = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] # tag_rcvbuff = "" tag_address = 0 # # 最大で、全アドレス(RFID_ADDRESS_MAX:45 未満)を読み込む for tag_address in range(RFID_ADDRESS_MAX): # tag_address を sector と block に換算 sector = int(tag_address / 3) + 1 block = tag_address % 3 # TAG を読み込む (stat, block_data_r) = rfid_13M_reader.readSectorBlock(uid ,sector, block, keyA=key_A, keyB = None) if stat == rfid_13M_reader.OK: print("BLOCK DATA = ", block_data_r) # 読み込んだ1ブロックを、文字列(tag_rcvbuff)に追加する flag_tag_EOF = 0 # 1:以降のブロックを読み取り不要 for i in range(len(block_data_r)): # ブロックの先頭スペース、または、Null('00')ならば、 if block_data_r[i] == 0x20 or block_data_r[i] == 0x00: # ブロックの先頭なら、EOF と判断する if i == 0: flag_tag_EOF = 1 break else: tag_rcvbuff += chr(block_data_r[i]) # スペース、または、Null('00')でなければ、受信バッファに追加する # 整数リストから文字列に変換する else: tag_rcvbuff += chr(block_data_r[i]) # 常時稼働時には、エラー表示が邪魔なので、出さない else: print ("rfid_13M_reader Read Error") # EOF を検出したら、以降のブロックを読まないで終了する。 if flag_tag_EOF == 1: break # 読み取り後の処理 rcv_size = len(tag_rcvbuff) if rcv_size > 0: print("tag_rcvbuff Size = ", rcv_size) print("tag_rcvbuff = ", tag_rcvbuff) headerID = tag_rcvbuff[0] tone_name = tag_rcvbuff[1:TONE_HEADER] print('Recive Data = ', tone_name) # Tone Data if headerID == '0': # 2文字の ASCIIコード(0-9 A-F)を1byteの整数に変換する。 rcv_tone = [] for i in range(TONE_DATA_ROW_NUM): # 42 # rcv_tone.append(moji.asc2int(chr(tag_rcvbuff[TONE_HEADER + i *2]) \ # + chr(tag_rcvbuff[TONE_HEADER + i *2 +1]))) rcv_tone.append(moji.asc2int(tag_rcvbuff[TONE_HEADER + i *2] \ + tag_rcvbuff[TONE_HEADER + i *2 +1])) # DEBUG print print('rcv_tone = ', rcv_tone) return stat, rcv_size, headerID, tone_name, rcv_tone elif headerID == '1': # 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(tag_rcvbuff[TONE_HEADER + i *2]) \ + chr(tag_rcvbuff[TONE_HEADER + i *2 +1]))) # DEBUG print print('ToneTable = ', rcv_tone) return stat, rcv_size, headerID, tone_name, rcv_tone # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print("No TAG or CARD") # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print ("rfid_13M_reader is not Raedy") # tag_read_timer == 0 なら else: print("TAG Read Time Over") # return stat, rcv_size = None, headerID = None, tone_name = None, rcv_tone = None return stat, None, None, None, None #---------------------------------------------------------------------------- # tag_sendbuff を tag_address から算定した TAG のブロックに書き込む # def tag_write2(midi_list) の付属関数 # TAG の 書き込み領域の sector が 15 を超えたら書き込めないので result = 2 # result = 1 は、正常に書き込み完了したとき def tag_block_write(uid, tag_sendbuff, tag_address): # Write Data 準備 key_A = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] # 末尾にスペースを入れて16桁にする tag_sendbuff = moji.strFixL_n(tag_sendbuff, 16) # Tag 書き込み用に整数化したリストに展開する block_data_w = [] for k in range(len(tag_sendbuff)): block_data_w.append(ord(tag_sendbuff[k])) print("BLOCK DATA = ", block_data_w) # tag_address を sector と block に換算 sector = int(tag_address / 3) + 1 block = tag_address % 3 print("tag_address=", tag_address, " sector=", sector, " block=", block, end="") # TAG 書き込み領域外なら、書き込みせずに終了 if sector > 15: result = 2 else: # Tag に書き込みする stat = rfid_13M_reader.writeSectorBlock(uid ,sector, block, data=block_data_w[:], keyA=key_A, keyB=None) # 正常終了なら if stat == rfid_13M_reader.OK: result = 1 # 異常終了なら else: result = 0 print(" result=", result) return result, sector, block #---------------------------------------------------------------------------- # MFRC522(13.56MHz)RFID にタグやカードが置かれたら、ToneData を書き込む # タグやカードが4秒以内に置かれなければ、何もせず終了 # send_buff は、ASCII 2文字の文字列 # tag_write_timer を設定して呼び出すこと def writeRfidTone(send_buff): global tag_write_timer # 書き込みデータが 0 でなら中断する if len(send_buff) <= 0: err_size = 1 print('len(send_buff) = ', len(send_buff), 'send_buff SIZE = 0') return else: # 読み取り時 EOF 検出用に 16個のスペースを付け加える send_buff += ' ' # space(16) # send_buff のサイズが RFID_BLOCK_SIZE =16 で余りがあるなら +1 if (len(send_buff) % RFID_BLOCK_SIZE) != 0: address_max = int(len(send_buff) /16) +1 else: address_max = int(len(send_buff) /16) # RFID への書き込み address が RFID_ADDRESS_MAX 未満か確認 if address_max >= RFID_ADDRESS_MAX: # 45 err_size = 1 print('len(send_buff) = ', len(send_buff), 'Bytes, Size is Over RFID_ADDRESS_MAX ',RFID_ADDRESS_MAX, n ) return else: # byte 文字列を 通常の文字列に戻す buffB = send_buff.decode('utf-8') # RFID への書き込み範囲が正しい範囲なら # 0 < send_buff < RFID_ADDRESS_MAX *16 while tag_write_timer > 0: # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら書き込む rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) if stat == rfid_13M_reader.OK: (stat, uid) = rfid_13M_reader.SelectTagSN() if stat == rfid_13M_reader.OK: for i in range(address_max): tag_address = i tag_sendbuff = buffB[i *RFID_BLOCK_SIZE : i *RFID_BLOCK_SIZE +RFID_BLOCK_SIZE] if len(tag_sendbuff) > 0: print('tag_address = ', i, 'tag_sendbuff = ', tag_sendbuff) ########################################################################## (result, sector, block) = tag_block_write(uid, tag_sendbuff, tag_address) ########################################################################## # RFID 書き込み時にエラー発生 if result != 1: break # 正常終了 if result == 1: print('Performed write Rfid Tone') break # RFIDモジュールでエラー発生 elif result == 0: print("Failed write Rfid Tone") break # RFID ユーザー領域を超えて書き込もうとするエラー発生 elif result == 2: print("Failed write Rfid Tone! TAG outside write area !! sector = ", sector, " block = ", block) break # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print("No TAG or CARD") # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print ("rfid_13M_reader is not Raedy") # tag_write_timer == 0 終了なら else: print("Time Over writeRfidTone() ") #---------------------------------------------------------------------------- # 「F5」キーを押してから、4秒(=tag_write_timer)以内にTAG を置くこと # 「F5」キーを押す前に、TAGを置くと、常時 TAG Read が動作する # MFRC522(13.56MHz)RFID にタグやカードが置かれたら書き込む # タグやカードが4秒以内に置かれなければ、何もせず終了 # def tag_write(midi_list): # 20240417 Change def tag_write(): global midi_list global tag_write_timer err_size = 0 result = 0 while tag_write_timer > 0: # MFRC522(13.56MHz)RFID にタグやカードが置かれていたら書き込む rfid_13M_reader.init() (stat, tag_type) = rfid_13M_reader.request(rfid_13M_reader.REQIDL) if stat == rfid_13M_reader.OK: (stat, uid) = rfid_13M_reader.SelectTagSN() if stat == rfid_13M_reader.OK: tag_sendbuff = "" print("tag_address in range(") tag_address = 0 for i in range(len(midi_list)): temp_buff = "" for j in range(len(midi_list[i])): temp_buff += midi_list[i][j] if len(temp_buff) > 16: err_size = 1 break else: err_size = 0 if len(tag_sendbuff + temp_buff) > 16: print("tag_sendbuff=", tag_sendbuff) ########################################################################## (result, sector, block) = tag_block_write(uid, tag_sendbuff, tag_address) ########################################################################## tag_address += 1 tag_sendbuff = "" if result != 1: break tag_sendbuff += temp_buff # if err_size == 1 or result != 1: break # tag_sendbuff に残っていれば if len(tag_sendbuff) > 0: print("tag_sendbuff=", tag_sendbuff) ########################################################################## (result, sector, block) = tag_block_write(uid, tag_sendbuff, tag_address) ########################################################################## tag_address += 1 tag_sendbuff = "" if result != 1: break if sector <= 15 and block < 2: data_EOF = " " print("data_EOF=", data_EOF) ##################################################################### (result, sector, block) = tag_block_write(uid, data_EOF, tag_address) ##################################################################### tag_address += 1 if result != 1: break # ここまで break なしで来るなら正常終了 if result == 1: break # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print("No TAG or CARD") # 常時稼働時には、エラー表示が邪魔なので、出さない # else: # print ("rfid_13M_reader is not Raedy") # tag_write_timer == 0 終了なら else: print("TAG Write Time Over") # break 終了なら if err_size == 1: print("midi_list has items over 16 bytes !!") if result == 0: print("Failed Tag Write !!") if result == 2: print("TAG outside write area !! sector = ", sector, " block = ", block) #---------------------------------------------------------------------------- # 与えられた文字列を2バイトを1アイテムとして リストを生成し返す # 例:midi_rcvbuff="9nkkvv" → temp_list = ['9n', 'kk', 'vv'] def midiB2list(midi_rcvbuff): temp_list = [] for i in range(len(midi_rcvbuff)): # 偶数ならば if (i % 2) == 0: temp_buff = midi_rcvbuff[i] # 奇数ならば、偶数桁と合わせて、temp_list に追加する else: temp_buff += midi_rcvbuff[i] temp_list.append(temp_buff) return temp_list #---------------------------------------------------------------------------- # def midi_play(): の付随関数 # midi_rcvbuff で midi_listR を書き換える # midi_rcvbuff の2バイトを1アイテムとして midi_listR 記録する # 例:midi_rcvbuff="9nkkvv" → midi_listR = ['9n', 'kk', 'vv'] def update_midi_listR(cnt_listR, vol_listR, midi_rcvbuff): global midi_listR temp_list = midiB2list(midi_rcvbuff) # vol_listR のアイテム数を持つリスト midi_listR の pt_listR の場所を # temp_list で書き換える。 # cnt_listR は、連番で積算しているので vol_listR よりも大きい場合がある。 # 記録場所の計算 pt_listR = cnt_listR % vol_listR # midi_listR 書き換え midi_listR[pt_listR] = temp_list #---------------------------------------------------------------------------- # MIDI-Inデータを MIDI-Outに 出力しながら記録する。Escキーが押されるまで動作する。 # MIDI入力データを、 midi_listR に記録し、最後に midi_list にコピーする。 # midi_listR は、サイズが vol_listR で一周で繋がったエンドレス構造とし、 # MIDI入力データで順次、上書きし、最後に残ったデータを midi_list にコピーする。 # midi_listの先頭に楽器設定情報を末尾にオールノートオフを追加する。プラス2アイテム # データが少ない場合でも、midi_listの先頭側に空のデータが入らないように工夫した。 # pt_listRは次に記録すべきポイントを示す。何度か書き換えられた場合は再生開始位置。 # 待ち時間を、F2 xx xx 形式で挿入する。 def midi_play(swap_ch = 0): global midi_list, midi_listR, midi_channel, midi_tone_data global midi_ikg_timer, midi_frame_timer global stop, end # Main との通信用(参照し制御する) pt_listR = 0 cnt_listR = 0 # 受信データの MIDI Item 数(積算) vol_listR = const(80) temp_list = ['00', '00', '00'] # 空の midi_listR を生成・・・[temp_list] と [] で括ることが重要 midi_listR = [temp_list] * vol_listR midi_rcvbuff = "" time_buff = "" midi_ikg_timer = 0 # 積算タイマー cnt_rcv = 0 esc_break = 0 begin = 1 data_cnt_old = 0 # プログラムチェンジ(音色変更)記録用のポインタ、および、リストの用意 init_ChTnList() # 演奏状態にセット stop = 0 end = 0 # while midi_frame_timer > 0: # 減算タイマー while end == 0: # end == 1 で終了 # 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="") cnt_rcv += 1 # 受信文字数カウント ######################################################################### # MIDIステータスが、 0x80 〜 0xCF であり、かつ、チャンネルが、0 であり、かつ、 # 指定されたスワッピング チャンネルが、0 でないなら # 20240626 上限を <= 0xF7 から <= 0xEF に変更 if ord(midi_data_rx) >= 0x80 and ord(midi_data_rx) <= 0xEF \ and swap_ch != 0: # 受信チャンネルが 0 なら、swap_ch に変換して出力する if ord(midi_data_rx) & 0x0F == 0x00: midi_data_rx = chr((ord(midi_data_rx) & 0xF0) | (swap_ch & 0x0F)) # 受信チャンネルが、swap_ch なら、チャンネル 0 に変換して出力する elif ord(midi_data_rx) & 0x0F == (swap_ch & 0x0F): midi_data_rx = chr((ord(midi_data_rx) & 0xF0)) uart_midi.write(midi_data_rx) ######################################################################## # 待ち時間の追加 # (受信したデータの上位4ビットが、8以上なら、ステータスバイト であり # かつ、0xF7(ユニバーサル・システム・エクスクルーシブ末尾)以外であり) # かつ、midi_ikg_timer が 20ms を超えているなら # 待ち時間を、F2 xx xx 形式で挿入する ######################################################################### if ord(midi_data_rx) >= 0x80 and ord(midi_data_rx) != 0xF7: # 最初のデータでは、何もせず midi_buff に保存する if begin == 1: begin = 0 else: # 直前のデータを記録する # midi_rcvbuff で midi_listR を書き換える print(" >>> cnt_listR = ", cnt_listR, end="") print(" >>> midi_rcvbuff = ", midi_rcvbuff) # 20240612 Add # 直前のデータが、プログラムチェンジならば、 if midi_rcvbuff[0] == 'C': # ChTnList に記録する ch = moji.asc2int(midi_rcvbuff[0:2]) % 16 tn = moji.asc2int(midi_rcvbuff[2:4]) ############################################### add_ChTnList(ch, tn) print('PROGRAM CHANGE ', midi_rcvbuff, ch, tn) ############################################### ###################################################### update_midi_listR(cnt_listR, vol_listR, midi_rcvbuff) ###################################################### # ポインタのカウントアップ cnt_listR += 1 #################### midi_rcvbuff = "" #################### # 直前のデータから 20ms を超えていれば、待ち時間を記録する if midi_ikg_timer > 20: waitMSB = int(midi_ikg_timer / 128) waitLSB = midi_ikg_timer % 128 time_buff = "F2" # 「F2」を記録する time_buff += moji.byte2chr2(chr(waitMSB)) time_buff += moji.byte2chr2(chr(waitLSB)) # time_buff で midi_listR を書き換える print(" >>> time_buff = ", time_buff) ##################################################### update_midi_listR(cnt_listR, vol_listR, time_buff) ##################################################### # ポインタのカウントアップ cnt_listR += 1 ################### midi_ikg_timer = 0 ################### # 受信データの一時保存 # 1バイトの受信データを2バイトの文字データにして保存する midi_rcvbuff += moji.byte2chr2(midi_data_rx) elif stop == 1: # Main def every97ms(t): でセットする] end = 1 # ESC キー押下で、終了なら if end == 1: print("ESC Key Break") ########################## midiSoundOff() ########################## # 直前のデータが残っていれば、midi_rcvbuff で midi_listR を書き換える # 通常、9n kk vv なので、6桁以上ある。 if len(midi_rcvbuff) >= 6: print("midi_rcvbuff = ", midi_rcvbuff) ##################################################### update_midi_listR(cnt_listR, vol_listR, midi_rcvbuff) ##################################################### # ポインタのカウントアップ cnt_listR += 1 midi_rcvbuff = "" # MIDI 受信記録があれば、midi_listR を midi_list にコピーする # 先頭に楽器設定コマンド、末尾にオールノートオフ コマンドを追加する if cnt_listR > 0: # 受信状況をシリアルに出力 print("cnt_rcv = ", cnt_rcv, end="") print(" cnt_listR = ", cnt_listR, end="") print(" pt_listR = ", pt_listR, end="") print(" vol_listR = ", vol_listR) midi_list = [] # 20240615 Comment Out # 先頭に、楽器設定コマンドを入れる # midi_tone_data ######################################## # temp_list = midiB2list(midi_tone_data) ######################################## # midi_list.append(temp_list) # 記録したデータ数が vol_listR 未満なら、midi_listR の先頭からコピーする if cnt_listR < vol_listR: for i in range(cnt_listR): midi_list.append(midi_listR[i]) # 記録したデータ数が vol_listR 以上なら(受信データ数が、一巡以上なら) # pt_listR から、一巡して、pt_listR の一つ手前までコピーする else: for i in range(pt_listR, pt_listR + vol_listR): midi_list.append(midi_listR[ i % vol_listR ]) # 末尾に オールノートオフ(0xB07B00)を追加する # 20240615 オールサウンドオフ(0xB07800)に変更する # すべてのチャンネルの発信しなければならないが、ここでは、チャンネル 0 のみ # midi_Noteoff = moji.byte2chr2(chr( 0xB0 | (midi_channel % 16))) midi_Noteoff = moji.byte2chr2(chr( 0xB0)) # midi_Noteoff += moji.byte2chr2(chr( 0x7B)) midi_Noteoff += moji.byte2chr2(chr( 0x78)) midi_Noteoff += moji.byte2chr2(chr( 0x00)) ######################################## temp_list = midiB2list(midi_Noteoff) ######################################## midi_list.append(temp_list) # midi_list をシリアルに出力 for i in range(len(midi_list)): print("midi_list = ", i, midi_list[i]) # 記録した MIDIプログラムチェンジ(音色変更)リストをシリアルアウト serialOutChTnList() #---------------------------------------------------------------------------- # 百人一首用に編集されたリスト HectOneを再生する。 # address, VoiceRome, OctKey, Velocity, onTime, offTime # Title = 先頭のデータ = ['Ad', 'Voi', 'Key', 'Vel', 'oN', 'oF'] # def playHectOne(HectOne): if HectOne != None: # HectOneが存在するなら for i in range(1, len(HectOne)): # [1]番目のデータは、音声データのローマ字である。 try: voice = exRmPkMiku.get(HectOne[i][1]) except: print(f'Error On : voice = exRmPkMiku.get({HectOne[i][1]})') voice = 0 midi_sendbuff = 'F0437909110A00' # voiceを 16進数表記のASCII文字に変換して midi_sendbuff末尾に追加する。 (asc_H, asc_L) = moji.int2asc2(voice) midi_sendbuff += asc_H + asc_L # 末尾に「F7」追加 midi_sendbuff += 'F7' ###################################### midi_writeB(midi_sendbuff) ###################################### # [2]番目のデータは、音階データ(オクターブとキー)である。 # Octave Key #(#は使いないので $で代用) octkey = HectOne[i][2] # ASCII octave = int(octkey[0]) # INT key = octkey[1] # ASCII if len(octkey) > 2: # 2桁超えならば、半音変化あり。半音は #として扱う key += '$' # ASCII # [3]番目のデータは、音量データ(velocity)である。 velocity = HectOne[i][3] # INT # 音階データを生成 [2]番目のデータと[3]番目のデータ channnel = 0 ############################################################ midi_writeB(key2midi(channel, octave, key, velocity)) ############################################################ # [4]番目のデータは、ノートオン持続時間である。 # F2 Msb Lsb の形式のしたがって、128msを1単位としたMSBとして扱う。 time = HectOne[i][4] * 128 # INT utime.sleep_ms(time) # velocityを 0 とした ノートオフを生成 # 他のデータは、直前のデータを活かす velocity = 0 ############################################################ midi_writeB(key2midi(channel, octave, key, velocity)) ############################################################ # [5]番目のデータは、ノートオフ持続時間である。 # F2 Msb Lsb の形式のしたがって、128msを1単位としたMSBとして扱う。 time = HectOne[i][5] * 128 # INT utime.sleep_ms(time) # 念のために MIDI ALL SOUND OFF midiSoundOff() else: print('Error : HectOne = None') # ---------------------------------------------------------------- # MicroPython Main Program # ---------------------------------------------------------------- channel = 0 octave = 4 key = 'A' velocity = 64 # 変数の初期設定 midi_frame_timer = 0 midi_ikg_timer = 10000 rfid_interval = 500 midi_rcvbuff = "" midi_rcvsize = 0 midi_buff_full = 0 # midi_buff > 240 midi_list = [] midi_listR = [] midi_listM1 = [] midi_listM2 = [] midi_channel = 0 tone = 0 # 楽器の番号 データは、0~127(楽器番号は、1-128) midi_tone_data = moji.byte2chr2(chr( 0xC0 | (midi_channel % 16))) midi_tone_data += moji.byte2chr2(chr(( tone % 16) & 0x7F )) midi_Noteoff = moji.byte2chr2(chr( 0xB0 | (midi_channel % 16))) midi_Noteoff += moji.byte2chr2(chr( 0x7B)) midi_Noteoff += moji.byte2chr2(chr( 0x00)) # ---------------------------------------------------------------- # 20240603 Add # テスト デバッグ用 if __name__ == '__main__': ##################################################################### print("tag_read()... Place your TAG within 4 seconds ...") tag_read_timer = NO_TAG_TIME # TAG 読み取り優先時間 4秒 midi_list = tag_read() # TAG を読み込み midi_list に書き込む ##################################################################### ##################################################################### print("play_midiList()... play memory") # 20240603 Change # play_midiList() # midi_list(リスト) を MIDI 演奏 play_midiList(midi_list) # midi_list(リスト) を MIDI 演奏 #####################################################################

mojipy.py

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桁 #----------------------------------------------------------------------------

ps2kb3.py

ps2kb3.py

############################################################################### # Pico に PS2 Keyboard を接続する # ps2kb.py # Auto Push ではなく、1文字受信毎に Push にしないと、うまくいかなかった。 # PS2Keyboard からの読み込みを文字列からリストに変更 # 2023/10/13 通常入力には耐えられる # # Pico <==> レベル変換 <==> PS2キーボードの接続 # 6-pin Mini-DIN 端子では、4Pin:+5V、3Pin:GND、1Pin:Data、5Pin:Clockである。 # マウスもキーボードと同じPin接続である。 # USB 端子では、1Pin:+5V、2Pin:D-:(Data)、3Pin:D+:(Clock)、4Pin:GND である。 # USB端子と レベル変換 バッファ Pico との接続は次のようにした。 # # ps2KeyBoard と Pico との接続 ps2KeyBoard # Pico レベル変換 USB-A USB-A # (メス) (オス) # 3V 5V GND (4) | | # gpio-13 (17)---clock -- 青------------- LV1 HV1 --- D+ --(3)--| | # gpio-12 (16)---data -- 緑------------- LV2 HV2 --- D- --(2)--| | # +5V (1) |___| # (TopView) # # 2024/05/22:ps2 Mouse 両用するため、 # gpio27(Clock) ==> gpio13(Clock) # gpio26(Data) ==> gpio12(Data) # sm4 ==> sm1 Mouse sm4 起動後に、KeyBoard sm1 を起動する # に 変更した。 # DEBUG用のLEDを3端子用意できないので、gpio-14:LED-R、gpio-15:LED-G のみとした。 # # PS2 キーボードインターフェース # PS2 Keyboard は、+5V、GND、KB_Data、KB_Clock のラインがある。 # KB_Data、KBClock は、オープンコレクタで接続されている。 # 双方向通信であるが、PS2 Keyboard から Pico(PC側)へのデータ送信では、 # KB_Clock の立下りで判断し、KB_Data が Lowなら0、Highなら、1であり # 10ビットで1つのキャラクタを構成する。 # 1ビットのスタートビット(1bit:0) # 8ビットのデータビット (8bit:data) # 1ビットのパリティビット(Parity:ODD) # 1ビットのストップビット(1bit:1) # # Ver:2023/10/14 Program by Hyodo # Ver:2023/10/16 SKB-KG3WN Shift + Arrow # Ver:2023/11/01 簡潔にした # Ver:2024/06/18 # 複数のモジュールから同時利用できるよう、クラス変数を導入した。 # # ############################################################################### # from rp2 import PIO, StateMachine, asm_pio # from micropython import const # # Debug Print True or False # DEBUG_PRINT = True DEBUG_PRINT = False # ############################################################################### # LSB First なので、右シフト:PIO RX-FIFO 上位に受信データがセットされる # 指定のビット数(BIT_CNT)を受信したら、自動的にPIO RX-FIFO にpush するよう # autopush を設定するとダメだった。 # MicroPython 側では、右シフトしてから取り出すこと ############################################################################### @asm_pio(in_shiftdir=PIO.SHIFT_RIGHT) def ps2kb_recive(): # BIT_CNT = 9 # 1文字の受信ビット数(data 8bit, parity 1bit) wrap_target() # 次の2つの命令は、PIO起動時1回のみ実行する。 pull() # osr = timeout value # label("start_frame") # <start_frame> mov(x, osr) # x = timeout value タイマー値をセット # label("start_1chr") # <start_1chr> set(y, BIT_CNT) # y = 9 bit (data 8bit, parity 1bit) jmp(y_dec, "wait_start_bit_L") # y != 0 なら y -= 1 して wait_start_bit_L へ # 回数(ビット数)処理調整のため減算、次へ label("wait_start_bit_L") # <wait_start_bit_L> jmp(pin, "chk_timeout") # ① jmp_pin = kb_clock が 1 なら chk_timeout へ # jmp_pin = kb_clock が 0 の場合は、次へ # label("wait_start_bit_H") # <wait_start_bit_H> wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ # start bit end, next recive 1chr label("recive_1chr") # <recive_1chr> wait(0, pin, 1) # in_base(kb_data) +1 = kb_clock が 0 を待つ mov(x, osr) # x = timeout value タイマー値を再度セット in_(pins, 1) # in_base = kb_data から 1bit 読み込み # ISR へ書き込む (LSB First) jmp(y_dec, "wait_start_bit_H") # y != 0 なら y -= 1 して wait_start_bit_H へ # y = 0 なら 次へ (8bit + parity recived) label("chk_stop_bit") # <chk_stop_bit> wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ wait(0, pin, 1) # in_base(kb_data) +1 = kb_clock が 0 を待つ wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ jmp("start_1chr") # 新たな文字受信待ち start_1chr へ label("chk_timeout") # <chk_timeout> timeout = 1 Frame Recived jmp(x_dec, "wait_start_bit_L") # ② x != 0 なら x -= 1 して wait_start_bit_L へ # x = 0 (=timeout) なら 次へ mov(x, isr) # isr(受信データ)を x レジスタに jmp(not_x, "start_frame") # isr = 0 でならば 受信なし start_frame へ # isr != 0 でならば 受信あり 次へ push() # autopush=True, push_thresh=11 を使用しない # 20240522 Change # irq(0) # 割り込み発生(受信データあり) irq(1) # 割り込み発生(受信データあり) jmp("start_frame") # 新たな受信待ち start_frame へ # sm4 StateMachine -------------------------------------------------------------- class PS2KeyRecive: # class 変数初期設定 「cls.」を付加して参照できる # 関数名(self) ではなく @classmethod 関数名(cls) とする必要あり # (self) で参照する場合は、cls.ではなく、クラス名(PS2KeyRecive.)とする。 key_code = "" # キーコードをクリア(文字列) key_code_ret = "" data_rx1_old = 0x00 data_rx2_old = 0x00 data_rx3_old = 0x00 shift = 0 # 0:直前に Shift キーなし 1:直前に Shift キーあり ctrl = 0 # 0:直前に Ctrl キーなし 1:直前に Ctrl キーあり # PS2KeyBoard Map Dictuionary PS2KeyCode:Value # 直前に Shift 押下なし テーブル(辞書)機能キーである(data_rx2 == 0xE0) PS2KeyMapE = {0x1F:'Win',0x14:'Ctrl',0x11:'Alt',0x27:'Win', 0x2F:'Appli', 0x75:'Arw_U',0x72:'Arw_D',0x6B:'Arw_L',0x74:'Arw_R', 0x7D:'PgUp',0x7A:'PgDn',0x6C:'Home',0x69:'End', 0x71:'Del',0x70:'Ins',0x7C:'PrtSc', 0x4A:'/',0x5A:'Enter',0x7E:'ScrLk', } # 直前に Shift 押下あり テーブル(辞書)機能キーである(data_rx2 == 0xE0) PS2KeyMapF = {0x1F:'Win',0x14:'Ctrl',0x11:'Alt',0x27:'Win', 0x2F:'Appli', 0x75:'PgUp',0x72:'PgDn',0x6B:'Home',0x74:'End', 0x7D:'PgUp',0x7A:'PgDn',0x6C:'Home',0x69:'End', 0x71:'Ins',0x70:'Ins',0x7C:'PrtSc', 0x4A:'/',0x5A:'Enter',0x7E:'ScrLk', } # 直前に Shift 押下 なし テーブル(辞書)機能キーでない(data_rx2 != 0xE0) PS2KeyMapD = {0x16:'1',0x1E:'2',0x26:'3',0x25:'4',0x2E:'5', 0x36:'6',0x3D:'7',0x3E:'8',0x46:'9',0x45:'0', 0x1C:'a',0x32:'b',0x21:'c',0x23:'d',0x24:'e', 0x2B:'f',0x34:'g',0x33:'h',0x43:'i',0x3B:'j', 0x42:'k',0x4B:'l',0x3A:'m',0x31:'n',0x44:'o', 0x4D:'p',0x15:'q',0x2D:'r',0x1B:'s',0x2C:'t', 0x3C:'u',0x2A:'v',0x1D:'w',0x22:'x',0x35:'y', 0x1A:'z',0x4E:'-',0x55:'^',0x6A:'Yen',0x54:'@', 0x5B:'[',0x4C:';',0x52:':',0x5D:']',0x41:',', 0x49:'.',0x4A:'/',0x51:'Yen', 0x70:'0',0x69:'1',0x72:'2',0x7A:'3',0x6B:'4', 0x73:'5',0x74:'6',0x6C:'7',0x75:'8',0x7D:'9', 0x71:'.',0x7C:'*',0x7B:'-',0x79:'+',0x77:'NumLk', 0x05:'F1',0x06:'F2',0x04:'F3',0x0C:'F4',0x03:'F5', 0x0B:'F6',0x83:'F7',0x0A:'F8',0x01:'F9',0x09:'F10', 0x78:'F11',0x07:'F12', 0x66:'BS',0x5A:'Enter',0x29:'Space',0x76:'Esc', 0x0E:'kanji',0x0D:'Tab',0x58:'Caps',0x12:'Shift', 0x14:'Ctrl',0x11:'Alt',0x59:'Shift',0x67:'NoChange', 0x64:'Change',0x13:'Rome',0x7E:'ScrLk', } # 直前に Shift 押下 あり テーブル(辞書)機能キーでない(data_rx2 != 0xE0) PS2KeyMapU = {0x16:'!',0x1E:'"',0x26:'Sharp',0x25:'$',0x2E:'%', 0x36:'&',0x3D:"'",0x3E:'(',0x46:')',0x45:'*', 0x1C:'A',0x32:'B',0x21:'C',0x23:'D',0x24:'E', 0x2B:'F',0x34:'G',0x33:'H',0x43:'I',0x3B:'J', 0x42:'K',0x4B:'L',0x3A:'M',0x31:'N',0x44:'O', 0x4D:'P',0x15:'Q',0x2D:'R',0x1B:'S',0x2C:'T', 0x3C:'U',0x2A:'V',0x1D:'W',0x22:'X',0x35:'Y', 0x1A:'Z',0x4E:'=',0x55:'~',0x6A:'|',0x54:'`', 0x5B:'{',0x4C:'+',0x52:'*',0x5D:'}',0x41:'<', 0x49:'>',0x4A:'?',0x51:'_', 0x70:'0',0x69:'1',0x72:'2',0x7A:'3',0x6B:'4', 0x73:'5',0x74:'6',0x6C:'7',0x75:'8',0x7D:'9', 0x71:'.',0x7C:'*',0x7B:'-',0x79:'+',0x77:'ScrLk', 0x05:'F1',0x06:'F2',0x04:'F3',0x0C:'F4',0x03:'F5', 0x0B:'F6',0x83:'F7',0x0A:'F8',0x01:'F9',0x09:'F10', 0x78:'F11',0x07:'F12', 0x66:'BS',0x5A:'Enter',0x29:'Space',0x76:'Esc', 0x0E:'kanji',0x0D:'Shift_Tab',0x58:'Caps',0x12:'Shift', 0x14:'Ctrl',0x11:'Alt',0x59:'Shift',0x67:'NoChange', 0x64:'Change',0x13:'Rome',0x7E:'ScrLk', } # 直前に Ctrl 押下 あり テーブル(辞書)機能キーでない(data_rx2 != 0xE0) PS2KeyMapC = {0x1C:'Ctrl_A',0x32:'Ctrl_B',0x21:'Ctrl_C',0x23:'Ctrl_D', 0x24:'Ctrl_E',0x2B:'Ctrl_F',0x34:'Ctrl_G',0x33:'Ctrl_H', 0x43:'Ctrl_I',0x3B:'Ctrl_J',0x42:'Ctrl_K',0x4B:'Ctrl_L', 0x3A:'Ctrl_M',0x31:'Ctrl_N',0x44:'Ctrl_O',0x4D:'Ctrl_P', 0x15:'Ctrl_Q',0x2D:'Ctrl_R',0x1B:'Ctrl_S',0x2C:'Ctrl_T', 0x3C:'Ctrl_U',0x2A:'Ctrl_V',0x1D:'Ctrl_W',0x22:'Ctrl_X', 0x35:'Ctrl_Y',0x1A:'Ctrl_Z', } def __init__(self, pio_freq, kb_data, kb_clock): print("PS2KeyRecive:init") self.sm = StateMachine(1, ps2kb_recive, freq=pio_freq, in_base=kb_data, jmp_pin=kb_clock) self.sm.irq(self._handler) # コールバック関数の登録 def set_active(self): # StateMachine 起動 self.sm.active(1) def set_inactive(self): # StateMachine 停止 self.sm.active(0) def put_timer(self, time_out): # time_out 値を PIO OSR にセット self.sm.put(time_out) # 受信サイズ取得 @classmethod def rcv_size(cls): return len(cls.key_code_ret) # 受信データサイズを返す # 受信末尾バッファ取得 @classmethod def get_code(cls): key_ret = cls.key_code_ret # 受信データ読み取りでクリア cls.key_code_ret = "" return key_ret # 取得キーコードを返す # StateMachine から割り込み発生でここにコールバック # 受信データの蓄積 def _handler(self, ev): # PIO からの割り込み 1 Char 受信 # Debug # print("PS2KeyRecive:Irq") # data_rx = self.sm.get() # PIO RX-FIFO からデータを取得 # Parity をチェックする場合、次の部分に工夫が必要 # Paritybit は、上位ビット 9ビット目にある。 data_rx1 = data_rx >> (5) & 0xFF data_rx2 = data_rx >> (14) & 0xFF data_rx3 = data_rx >> (24-1) & 0xFF # # Debug print if DEBUG_PRINT: print("IRQ data_rx = ", data_rx1, data_rx2, data_rx3) # # Shift キーの状態チェック if PS2KeyRecive.data_rx2_old == 0x00 and (PS2KeyRecive.data_rx3_old == 0x12 or PS2KeyRecive.data_rx3_old == 0x59): PS2KeyRecive.shift = 1 # 1:Shift キー押されている elif PS2KeyRecive.data_rx2_old == 0xF0 and (PS2KeyRecive.data_rx3_old == 0x12 or PS2KeyRecive.data_rx3_old == 0x59): PS2KeyRecive.shift = 0 # 0:Shift キー押されてない # Ctrl キーの状態チェック if (PS2KeyRecive.data_rx2_old == 0x00 and PS2KeyRecive.data_rx3_old == 0x14) or (PS2KeyRecive.data_rx2_old == 0xE0 and PS2KeyRecive.data_rx3_old == 0x14): PS2KeyRecive.ctrl = 1 # 1:Ctrl キー押されている elif (PS2KeyRecive.data_rx2_old == 0xF0 and PS2KeyRecive.data_rx3_old == 0x14) or (PS2KeyRecive.data_rx1_old == 0xE0 and PS2KeyRecive.data_rx2_old == 0xF0 and PS2KeyRecive.data_rx3_old == 0x14): PS2KeyRecive.ctrl = 0 # 0:Ctrl キー押されてない # Pause キー 対応 if data_rx1 == 0x14 and data_rx2 == 0xF0 and data_rx3 == 0x77: PS2KeyRecive.key_code = 'Pause' # テーブル(辞書)機能キーである(data_rx2 == 0xE0) elif data_rx2 == 0xE0: # Shift キーの状態チェック if PS2KeyRecive.shift == 1: # Shift 押下 あり テーブル(辞書)を利用 PS2KeyRecive.key_code = PS2KeyRecive.PS2KeyMapF.get(data_rx3) else: # Shift 押下 なし テーブル(辞書)を利用 PS2KeyRecive.key_code = PS2KeyRecive.PS2KeyMapE.get(data_rx3) # 本来は if data_rx2 == 0x00: (キーが押された時)で良いのだが # SANWA SKB-KG3WN OLD では 2,w,s,x ラインが 0x00 ではなく 0x22 が出るので対応 # 20231020:出ていない??? elif data_rx2 == 0x00: if PS2KeyRecive.shift == 1: # Shift 押下 あり テーブル(辞書)を利用 PS2KeyRecive.key_code = PS2KeyRecive.PS2KeyMapU.get(data_rx3) elif PS2KeyRecive.ctrl == 1: # Ctrl 押下 あり テーブル(辞書)を利用 PS2KeyRecive.key_code = PS2KeyRecive.PS2KeyMapC.get(data_rx3) # 多くのキーは、ここになる else: # Shift 押下 なし Ctrl 押下 なし テーブル(辞書)を利用 PS2KeyRecive.key_code = PS2KeyRecive.PS2KeyMapD.get(data_rx3) elif data_rx2 == 0xF0: PS2KeyRecive.key_code = "" # None または Shift キー または Ctrl キー なら出力しない if PS2KeyRecive.key_code == None or PS2KeyRecive.key_code == 'Shift' or PS2KeyRecive.key_code == 'Ctrl': PS2KeyRecive.key_code_ret = "" # Yen Sharp 対応 elif len(PS2KeyRecive.key_code) > 0: if PS2KeyRecive.key_code == 'Yen': # \ Pythonでは、辞書に表現できない PS2KeyRecive.key_code_ret = chr(0x5C) elif PS2KeyRecive.key_code == 'Sharp': # # Pythonでは、辞書に表現できない PS2KeyRecive.key_code_ret = chr(0x23) else: PS2KeyRecive.key_code_ret = PS2KeyRecive.key_code else: PS2KeyRecive.key_code_ret = "" # # Debug print if DEBUG_PRINT: if len(PS2KeyRecive.key_code_ret) > 0: print("Key data = ", PS2KeyRecive.key_code_ret) # PS2KeyRecive.data_rx1_old = data_rx1 PS2KeyRecive.data_rx2_old = data_rx2 PS2KeyRecive.data_rx3_old = data_rx3 #

ps2mus.py

ps2mus.py

############################################################################### # 目標:Pico に PS/2 Mouse を接続する # ps2mus_20240601.py Program by Hyodo # # PS2マウス と Picoの接続 # 6-pin Mini-DIN 端子では、4Pin:+5V、3Pin:GND、1Pin:Data、5Pin:Clockである。 # (2Pin:Data、6Pin:Clock は、間違いであり、キーボードと同じ接続である。) # USB 端子では、1Pin:+5V、2Pin:D-:(Data)、3Pin:D+:(Clock)、4Pin:GND である。 # Pico --- オープンドレインバッファ --- レベル変換 --- USBとの接続は次の通り # # Pico レベル変換 USBコネクタAメス ps/2 Mouse # GND GND GND 4pin # gpio26(Clock) +++++++++++++++++ <<+++++>> +++ D+ 3pin # gpio27(Data) --------- + --- <<----->> --- D- 2pin # 3V + - 3V 5V +5V 1pin # + - ( TopView ) # OpenDrainBuff + - # gpio20 ++ 11pin 10pin ++ - # gpio21 -- 13pin 12pin ----- # ( 74HC07 ) # # Data と Clock は、マウスのオープンコレクタトランジスタに接続されている。 # 双方向通信であるが、PS/2 Mouse から Pico(PC側)へのデータ送信では、Pico は、 # マウスからの Clock の立下りで判断し、Data が Lowなら0、Highなら、1であり # 11ビットで1つのキャラクタを構成する。 # 1ビットのスタートビット(1bit:0) # 8ビットのデータビット (8bit:data) # 1ビットのパリティビット(1bit:ODD Parity、Parityを含めて奇数にする) # 1ビットのストップビット(1bit:1) # # PS2 マウスを動作状態にするには、Pico(PC側)から、リセット・コマンド(0xFF)と # ストリーミング・モード開始コマンド(0xF4)を、マウスに送信しなければならない。 # その制御は やや複雑で、DATA 信号が high レベル状態で、Clockを 100us Low にし、 # 続いて、Dataを Low(=スタートビット送出)すると、マウスがクロックを発生する。 # マウスからの Clockの立下りに合わせて LSB から 順にコマンド・データを出力する。 # データ 8ビット送出し、パリティ・ビットを送出し、 # ストップビットを送出するという流れになる。 # # PS2 スクロール・ホイール対応 # Pico(CPU)側から、マウスに対して、リセット・コマンド(0xFF)を出した後、 # 先に、サンプリング・レイト設定(0xF3, xx)で、 # 10進数で、xx = 200, 100, 80 を続けて出した後に # ストリーミング・モード開始コマンド(0xF4)を出すと、 # スクロール・ホイール機能を有効化できる。 # # マウスの初期設定を PicoMain から、次の4つのコマンドで実行できるようにした。 # ps2mus_cmd.init_ps2cmd_1() # ps2mus_rcv.init_ps2rcv_1(MUS_PIO_FRQ) # ps2mus_cmd.init_ps2cmd_2() # ps2mus_rcv.init_ps2rcv_2(MUS_PIO_FRQ) # # ############################################################################### # from rp2 import PIO, StateMachine, asm_pio from machine import Timer from micropython import const import utime # Debug Print Use = 1 Debug Print NonUse = 0 # DEBUG_PRINT = const(1) DEBUG_PRINT = const(0) ############################################################################### # sm2 Pio -------------------------------------------------------------- # PS/2 Mouse との通信は、LSB First である。 # PIOは、Pythonがセットした TX-FIFOのデータの下位から取り出すので、右シフトにする # MicroPython側は、TX-FIFOの下位側にコマンドデータをセットすること。 # LSB側から start_bit,data8bit,oddparity_bit,stop_bitの順に11ビットに編集する # PIOからマウスへのデータは、out 命令を利用し、上記、11ビットを出力する。 # PIOから出力する clock は、set 命令で出力する。 ############################################################################### # Command Send from Pico to Mouse @asm_pio(set_init=PIO.OUT_HIGH, out_init=PIO.OUT_HIGH, \ out_shiftdir=PIO.SHIFT_RIGHT, in_shiftdir=PIO.SHIFT_RIGHT) def ps2mus_send(): SEND_BITS = 9 # start_bit, data_8bit, parity_bit, stop_bit RECIVE_BITS = 10 # start_bit, data_8bit, parity_bit, stop_bit WAIT_CNT = 30 # 待ち時間用 ERROR_BITS = 7 # エラー応答用 wrap_target() # Block with TX deasserted until data available 送信データがセットされるのを待つ pull() # Python 側からコマンドが到着したら # Pico から マウス側に コマンド送信要求を送出する(clock:0, Data:1 を 120us) set(y, WAIT_CNT) # 待ち時間をセット label("wait") # <wait> set(pins, 0) [2] # send_clock:0 を送出 send_data は初期状態:1 jmp(y_dec, "wait") # y != 0 なら wait へ PIO_freq=1MHzなら120us # y = 0 なら 次へ set(y, SEND_BITS) # ここまでは、Pico から マウスへの一方的な処理=コマンド送信要求である # start_bit 送出し、send_clock:1 を送出 label("tx_start") # <tx_start> out(pins, 1) # ⓪ (OSR で受信した)start_bit 「0」を送出 nop() [3] # 微妙なタイミングを想定して待ち時間挿入 set(pins, 1) # send_clock:1 を送出 # Mouse側が制御する rcv_clock 立下りを待って、data_8bit,parity_bit,stop_bit 送出 # 待ち時間タイマーを仕掛け、永遠ループを避ける set(x, WAIT_CNT) # 待ち時間をセット label("tx_loop") # <tx_loop> ① ~ ⑩ jmp(pin, "chk_timeout") # jmp_pin = rcv_clock が 1 なら chk_timeout へ # rcv_clock が 0 なら次へ set(x, WAIT_CNT) # 待ち時間を再度セット out(pins, 1) # data_8bit,parity_bit,stop_bit 送出 LSB First # Mouse 側からの rcv_clock 立上りを待つ wait(1, pin, 1) # in_base +1 = rcv_clock が 1 になるのを待つ # data_8bit, parity_bit, stop_bit 送出 途中なら tx_loop へ jmp(y_dec, "tx_loop") # y != 0 なら y -= 1 して tx_loop へ # data_8bit,parity_bit,stop_bit送出 終了なら 次へ # Mouse 側からの rcv_clock 立下りを待ち、アクノリッジを受信する wait(0, pin, 1) # in_base +1 = rcv_clock が 0 になるのを待つ in_(pins, 1) # ⑪ in_base = rcv_data から 1bit 読み込み # ISR へ書き込む (LSB First) # Mouse 側からの rcv_clock 立上りを待つ=終了 wait(1, pin, 1) # in_base +1 = rcv_clock が 1 になるのを待つ # 続けてマウスからの応答メッセージを受信する # スタートビットも ストップビットも in_ で isr に取り込む set(y, RECIVE_BITS) # start_bit, data_8bit, parity_bit, stop_bit の 11bit を受信する # この部分に、待ち時間タイマーを仕掛けたいが、プログラム容量なし label("rx_loop") # <rx_loop> ⓪ ~ ⑩ jmp(pin, "rx_loop") # jmp_pin = rcv_clock が 1 なら rx_loop へ # rcv_clock が 0 なら次へ in_(pins, 1) # in_base = rcv_data から 1bit 読み込み # ISR へ書き込む(LSB First) # Mouse 側からの rcv_clock 立上りを待つ wait(1, pin, 1) # in_base +1 = rcv_clock が 1 になるのを待つ # データ+パリティ受信 途中なら rx_loop へ jmp(y_dec, "rx_loop") # y != 0 なら y -= 1 して rx_loop へ # データ+パリティ受信 終了なら 次へ jmp("result_out") # result_out へ label("chk_timeout") # <chk_timeout> jmp(x_dec, "tx_loop") [3] # x != 0 なら y -= 1 して tx_loop へ 5us x 30 # x = 0(rcv_clock が 150us来ない)なら 次へ label("timeout") set(x, ERROR_BITS) # x = 0b111 mov(osr, x) # Data ラインに出力するため osr にコピー out(pins, 1) # Data ラインを Highにする mov(isr, osr) # osr に 残った 0b11 を isr に転送 # 次の命令で Python側に知らせる label("result_out") # <result_out> 結果をセットしPython側に知らせる push() # autopush=True, push_thresh を使用しない irq(2) # 割り込み発生 # アクノリッジデータと応答メッセージをセット # アクノリッジデータは、0:正常、1:異常 wrap() ############################################################################### # sm4 Pio -------------------------------------------------------------- # PS/2 Keyboard や Mouse との通信は、LSB First である。 # PIO RX-FIFOを右シフトで利用するので、上位に受信データがセットされる # MicroPython 側では、右シフトしてから取り出すこと ############################################################################### # Keyboard & Mouse Data Recive @asm_pio(in_shiftdir=PIO.SHIFT_RIGHT) def ps2mus_recive(): BIT_CNT = 7 # 受信ビット数(data 8bit) wrap_target() # 次の命令は、PIO起動時1回のみ実行する。 # Block with TX deasserted until data available 送信データがセットされるのを待つ pull() # osr = timeout value label("start_frame") # <start_frame> wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ label("start_1chr") # <start_1chr> mov(x, osr) # x = timeout value タイマー値をセット set(y, BIT_CNT) # y = 7(data 8bit) label("wait_start_bit") # <wait_start_bit> # wait(0, pin, 1) # in_base(kb_data) +1 = kb_clock が 0 を待つ jmp(pin, "chk_timeout1") # ① jmp_pin = kb_clock が 1 なら chk_timeout へ # jmp_pin = kb_clock が 0 の場合は、次へ mov(x, osr) # x = timeout value タイマー値をセット label("wait_clock_H1") # <wait_clock_H1> # wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ jmp(pin, "recive_1bit") # ① jmp_pin = kb_clock が 1 なら recive_1bit へ # jmp_pin = kb_clock が 0 の場合は、次へ jmp(x_dec, "wait_clock_H1") # ② x != 0 なら x -= 1 して wait_clock_H1 へ # x = 0 (=timeout) なら 次へ jmp("start_frame") # 中断して、新たな受信待ち start_frame へ # start bit end, recive 1chr label("recive_1bit") # <recive_1bit> # wait(0, pin, 1) # in_base(kb_data) +1 = kb_clock が 0 を待つ jmp(pin, "chk_timeout2") # ① jmp_pin = kb_clock が 1 なら chk_timeout2 へ # jmp_pin = kb_clock が 0 の場合は、次へ in_(pins, 1) # in_base = kb_data から 1bit 読み込み # ISR へ書き込む (LSB First) jmp(y_dec, "wait_clock_H1") # y != 0 なら y -= 1 して wait_clock_H1 へ # y = 0 なら 次へ (8bit recived) # wait parity and stop bit mov(x, osr) # x = timeout value タイマー値をセット set(y, 1) # 2回実行 label("wait_clock_H2") # <wait_clock_H2> # wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ jmp(pin, "wait_clock_L2") # ① jmp_pin = kb_clock が 1 なら wait_clock_L2 へ # jmp_pin = kb_clock が 0 の場合は、次へ jmp(x_dec, "wait_clock_H2") # ② x != 0 なら x -= 1 して wait_clock_H2 へ # x = 0 (=timeout) なら 次へ jmp("start_frame") # 中断して、受信待ち start_frame へ label("wait_clock_L2") # <wait_clock_L2> # wait(0, pin, 1) # in_base(kb_data) +1 = kb_clock が 0 を待つ jmp(pin, "chk_timeout3") # ① jmp_pin = kb_clock が 1 なら chk_timeout3 へ # jmp_pin = kb_clock が 0 の場合は、次へ jmp(y_dec, "wait_clock_H2") # y != 0 なら y -= 1 して wait_clock_H2 へ # y = 0 なら 次へ (parity and stop bit recived) label("wait_clock_H3") # <wait_clock_H3> # wait(1, pin, 1) # in_base(kb_data) +1 = kb_clock が 1 を待つ jmp(pin, "start_1chr") # ① jmp_pin = kb_clock が 1 なら start_1chr へ # jmp_pin = kb_clock が 0 の場合は、次へ jmp(x_dec, "wait_clock_H3") # ② x != 0 なら x -= 1 して wait_clock_H3 へ # x = 0 (=timeout) なら 次へ jmp("start_frame") # 中断して、受信待ち start_frame へ label("chk_timeout3") # <chk_timeout3> timeout = clock time over jmp(x_dec, "wait_clock_L2") # ② x != 0 なら x -= 1 して wait_clock_L2 へ # x = 0 (=timeout) なら 次へ jmp("start_frame") # 中断して、受信待ち start_frame へ label("chk_timeout2") # <chk_timeout2> timeout = clock time over jmp(x_dec, "recive_1bit") # ② x != 0 なら x -= 1 して recive_1bit へ # x = 0 (=timeout) なら 次へ jmp("start_frame") # 中断して、受信待ち start_frame へ label("chk_timeout1") # <chk_timeout1> timeout = 1 Frame Recived jmp(x_dec, "wait_start_bit") # ② x != 0 なら x -= 1 して wait_start_bit へ # x = 0 (=timeout) なら 次へ # ステップ数が不足するので以下のチェックは # Python側で処理することにした。 mov(x, isr) # isr(受信データ)を x レジスタに jmp(not_x, "start_frame") # isr = 0 でならば 受信なし start_frame へ # isr != 0 でならば 受信あり 次へ push() # autopush=True, push_thresh=11 を使用しない irq(0) # 割り込み発生(受信データあり) jmp("start_frame") # 1 Frame 受信完了。受信待ち start_frame へ ################################################################################ # sm0 StateMachine ------------------------------------------------------------- class PS2MouseCommand: def __init__(self, pio_freq, send_data, send_clock, rcv_data, rcv_clock): print("PS2MouseSend:init") self.sm = StateMachine(2, ps2mus_send, freq=pio_freq, \ out_base=send_data, set_base=send_clock, in_base=rcv_data, \ jmp_pin=rcv_clock) self.sm.irq(self._handler) # コールバック関数の登録 def set_active(self): # StateMachine 起動 self.sm.active(1) def set_inactive(self): # StateMachine 停止 self.sm.active(0) # マウスへのコマンド送信 # PS/2 Mouse への Command を PIO OSR にセット # start_bit, oddparity, stop_bit を加え、11bit に編集 def put_command(self, cmd): cmd_2 = cmd oddparity = 0 for i in range(8): if cmd_2 & 0x01 == 1: # LSB 1bit が「1」を数える oddparity += 1 cmd_2 >>= 1 # 1bit 右シフト if (oddparity % 2) == 0: # 奇数パリティ oddparity = 1 else: oddparity = 0 msb_data = 0x02 | oddparity # 0X02:stop_bit cmd_data = (msb_data << 8 | cmd) << 1 # 末尾の左シフトが start_bit:0 # Debug print if DEBUG_PRINT: print("PS2 Command = ", cmd_data) # self.sm.put(cmd_data) # 受信サイズ取得・・・必要ないか? def rcv_size(self): # self.key_ret = self.key_code_ret return len(data_resp) # 受信データサイズを返す # レスポンスを取得 def get_response(self): # 受信データ読み取りでクリア self.response = data_resp return self.response # 取得したレスポンスを返す # StateMachine から割り込み発生でここにコールバック # 受信データの蓄積 def _handler(self, ev): # PIO からの割り込み受信 data_rx = self.sm.get() # PIO RX-FIFO からデータを取得 # Parity をチェックする場合、次の部分に工夫が必要 # Paritybit は、データの上位ビット 9ビット目にある。(Parity,MSB...LSB) # if (data_rx & 0xFF) == 0x03: # PIO ERROR SET == 0x03 data_ack = 1 data_resp = 1 else: # stop, Parity, data8bit, start, ACK # Command 直後のアクノレッジ 0 が正常 data_ack = data_rx >> 20 & 0x01 # Command に対するレスポンス 0xFA が正常 data_resp = data_rx >> 22 & 0xFF # # Debug print if DEBUG_PRINT: print("PS2 Mouse IRQ CMD Response = ", data_ack, data_resp) # # 20240531 Add def init_ps2cmd_1(self): print("ps2mus_cmd.put_command(0xFF)") # PS2KeyRecive ドライバの起動 self.set_active() self.put_command(0xFF) utime.sleep_ms(10) # PS2KeyRecive ドライバの停止 self.set_inactive() # 念のために、PS/2 Data & Clock のラインを High にする----------------- # send_data.value(1) # PS2 Mouse Send Data # send_clock.value(1) # PS2 Mouse Send Clock # 20240531 Add def init_ps2cmd_2(self): # マウス・ホイール機能を有効にする 1 -> 3 # PS2KeyRecive ドライバの起動 self.set_active() # マウス ホイール機能を有効にする−1 print("ps2mus_cmd.put_command(0xF3)") self.put_command(0xF3) utime.sleep_ms(10) print("ps2mus_cmd.put_command(200)") self.put_command(200) utime.sleep_ms(10) # マウス・ホイール機能を有効にする−2 print("ps2mus_cmd.put_command(0xF3)") self.put_command(0xF3) utime.sleep_ms(10) print("ps2mus_cmd.put_command(100)") self.put_command(100) utime.sleep_ms(10) # マウス・ホイール機能を有効にする−3 print("ps2mus_cmd.put_command(0xF3)") self.put_command(0xF3) utime.sleep_ms(10) print("ps2mus_cmd.put_command(80)") self.put_command(80) utime.sleep_ms(10) # マウス・ホイール機能を有効にする 1 -> 3 終了 # マウス・ストリーミング・モード開始 print("ps2mus_cmd.put_command(0xF4)") # PS2KeyRecive ドライバの起動 self.set_active() self.put_command(0xF4) utime.sleep_ms(10) # PS2KeyRecive ドライバの停止 self.set_inactive() # 念のために、PS/2 Data & Clock のラインを High にする----------------- # send_data.value(1) # PS2 Mouse Send Data # send_clock.value(1) # PS2 Mouse Send Clock ################################################################################ # sm4 StateMachine ------------------------------------------------------------- class PS2MouseRecive: # class 変数初期設定 「cls.」を付加して参照できる # 関数名(self) ではなく @classmethod 関数名(cls) とする必要あり # (self) で参照する場合は、cls.ではなく、クラス名(PS2MouseRecive.)とする。 btn_l = 0 # 左クリック btn_r = 0 # 右クリック btn_c = 0 # スクロールボタンクリック cnt_x = 0 # マウス移動量:X方向:横方向 cnt_y = 0 # マウス移動量:Y方向:縦方向 cnt_s = 0 # マウス移動量:スクロールホイール data_cnt = 0 # マウスから受信したら カウントアップ # data_rx1_old = 0 # 第1バイト(ボタンクリック) data_rx2_old = 0 # 第2バイト(X方向:横方向) data_rx3_old = 0 # 第3バイト(Y方向:縦方向) data_rx4=old = 0 # 第4バイト(スクロールホイール) def __init__(self, pio_freq, rcv_data, rcv_clock): # print("PS2MouseRecive:init") self.sm = StateMachine(4, ps2mus_recive, freq=pio_freq, \ in_base=rcv_data, jmp_pin=rcv_clock) # self.sm.irq(self._handler) # コールバック関数の登録 def set_active(self): # StateMachine 起動 self.sm.active(1) def set_inactive(self): # StateMachine 停止 self.sm.active(0) def put_timer(self, time_out): # time_out 値を PIO OSR にセット self.sm.put(time_out) # @classmethod を指定することでクラス変数を利用する。 # 関数名(self) ではなく 関数名(cls) とし、変数の先頭に cls. を付ける。 # 受信データ取得とボタン情報のクリア @classmethod def get_data(cls): btn_l = cls.btn_l btn_r = cls.btn_r btn_c = cls.btn_c cls.btn_l = 0 cls.btn_r = 0 cls.btn_c = 0 return (cls.data_cnt, btn_l, btn_r, btn_c, cls.cnt_x, cls.cnt_y, cls.cnt_s) # 座標のセットと積算カウンタのリセット @classmethod def set_cnt(cls, x, y, s): cls.cnt_x = x # マウス移動量:X方向:横方向 cls.cnt_y = y # マウス移動量:Y方向:縦方向 cls.cnt_s = s # マウス移動量:スクロールホイール cls.data_cnt = 0 # StateMachine から割り込み発生でここにコールバック # クラス変数は、先頭に「PS2MouseRecive.」を付加する # 受信データの蓄積 def _handler(self, ev): # PIO からの割り込み受信 data_rx = self.sm.get() # PIO RX-FIFO からデータを取得 # if data_rx != 0: PS2MouseRecive.data_cnt += 1 data_rx1 = data_rx & 0xFF # 第1バイト(ボタンクリック) data_rx2 = data_rx >> 8 & 0xFF # 第2バイト(X方向:横方向) data_rx3 = data_rx >> 16 & 0xFF # 第3バイト(Y方向:縦方向) data_rx4 = data_rx >> 24 & 0xFF # 第4バイト(スクロールホイール) # スクロールの移動量を積算 # 積算値は、set_cnt で設定できる。通常は、0にする? if data_rx2 >= 128: # X方向:横方向の積算 PS2MouseRecive.cnt_x -= (256 - data_rx2) else: PS2MouseRecive.cnt_x += data_rx2 if data_rx3 >= 128: # Y方向:横方向の積算 PS2MouseRecive.cnt_y -= (256 - data_rx3) else: PS2MouseRecive.cnt_y += data_rx3 if data_rx4 >= 128: # スクロールホイールの積算 PS2MouseRecive.cnt_s -= (256 - data_rx4) else: PS2MouseRecive.cnt_s += data_rx4 # Button if data_rx1 & 0x01 != 0: # 左クリック押されているなら 1 PS2MouseRecive.btn_l = 1 #else: # PS2MouseRecive.btn_l = 0 # if data_rx1 & 0x02 != 0: # 右クリック押されているなら 1 PS2MouseRecive.btn_r = 1 #else: # PS2MouseRecive.btn_r = 0 # if data_rx1 & 0x04 != 0: # スクロールボタン押されているなら 1 PS2MouseRecive.btn_c = 1 #else: # PS2MouseRecive.btn_c = 0 # # Debug print if (PS2MouseRecive.data_rx1_old != data_rx1 or PS2MouseRecive.data_rx2_old != data_rx2 or PS2MouseRecive.data_rx3_old != data_rx3 or PS2MouseRecive.data_rx4_old != data_rx4) and DEBUG_PRINT: PS2MouseRecive.data_rx1_old = data_rx1 PS2MouseRecive.data_rx2_old = data_rx2 PS2MouseRecive.data_rx3_old = data_rx3 PS2MouseRecive.data_rx4_old = data_rx4 print("PS2 IRQ data_rx = ", PS2MouseRecive.data_cnt, PS2MouseRecive.btn_l, PS2MouseRecive.btn_r, PS2MouseRecive.btn_c, PS2MouseRecive.cnt_x, PS2MouseRecive.cnt_y, PS2MouseRecive.cnt_s) # 20240531 Add def init_ps2rcv_1(self, mus_pio_frq): # PS2MouseRecive ドライバの起動とタイマー設定 self.set_active() # 1Frame Time の設定 # マウスを連続して動かすと、12ms周期くらいでデータ送信してくる。 # 何もない時間が 4ms続けば区切りとして、インターラプトを発生させる。 # 4ms:(1MHz*1ms*1000us)/PIOクロック数 2 # time_out = int((MUS_PIO_FRQ * 4) / (1000 * 2)) time_out = int((mus_pio_frq * 4) / (1000 * 2)) self.put_timer(time_out) print("ps2mus_rcv.put_timer(time_out) = ", time_out) ########################################################################## # リセット・コマンドに対するマウスのセルフテスト完了の応答は、 # 400ms後くらいになるようだ。 utime.sleep_ms(1000) ########################################################################## # PS2MouseRecive ドライバの停止 self.set_inactive() # 20240531 Add def init_ps2rcv_2(self, mus_pio_frq): # PS2MouseRecive ドライバの起動 self.set_active() # 1Frame Time の設定 # マウスを連続して動かすと、12ms周期くらいでデータ送信してくる。 # 何もない時間が 4ms続けば区切りとして、インターラプトを発生させる。 # 4ms:(1MHz*1ms*1000us)/PIOクロック数 2 # time_out = int((MUS_PIO_FRQ * 4) / (1000 * 2)) time_out = int((mus_pio_frq * 4) / (1000 * 2)) self.put_timer(time_out) print("ps2mus_rcv.put_timer(time_out) = ", time_out) utime.sleep_ms(100)

st7789py.py

st7789py.py

""" st7789 tft driver in MicroPython based on devbis' st7789py_mpy module from https://github.com/devbis/st7789py_mpy. I added support for display rotation, scrolling and drawing text using 8 and 16 bit wide bitmap fonts with heights that are multiples of 8. Included are 12 bitmap fonts derived from classic pc text mode fonts. """ import time from micropython import const import ustruct as struct # commands ST7789_NOP = const(0x00) ST7789_SWRESET = const(0x01) ST7789_RDDID = const(0x04) ST7789_RDDST = const(0x09) ST7789_SLPIN = const(0x10) ST7789_SLPOUT = const(0x11) ST7789_PTLON = const(0x12) ST7789_NORON = const(0x13) ST7789_INVOFF = const(0x20) ST7789_INVON = const(0x21) ST7789_DISPOFF = const(0x28) ST7789_DISPON = const(0x29) ST7789_CASET = const(0x2A) ST7789_RASET = const(0x2B) ST7789_RAMWR = const(0x2C) ST7789_RAMRD = const(0x2E) ST7789_PTLAR = const(0x30) ST7789_VSCRDEF = const(0x33) ST7789_COLMOD = const(0x3A) ST7789_MADCTL = const(0x36) ST7789_VSCSAD = const(0x37) ST7789_MADCTL_MY = const(0x80) ST7789_MADCTL_MX = const(0x40) ST7789_MADCTL_MV = const(0x20) ST7789_MADCTL_ML = const(0x10) ST7789_MADCTL_BGR = const(0x08) ST7789_MADCTL_MH = const(0x04) ST7789_MADCTL_RGB = const(0x00) ST7789_RDID1 = const(0xDA) ST7789_RDID2 = const(0xDB) ST7789_RDID3 = const(0xDC) ST7789_RDID4 = const(0xDD) COLOR_MODE_65K = const(0x50) COLOR_MODE_262K = const(0x60) COLOR_MODE_12BIT = const(0x03) COLOR_MODE_16BIT = const(0x05) COLOR_MODE_18BIT = const(0x06) COLOR_MODE_16M = const(0x07) # Color definitions BLACK = const(0x0000) BLUE = const(0x001F) RED = const(0xF800) GREEN = const(0x07E0) CYAN = const(0x07FF) MAGENTA = const(0xF81F) YELLOW = const(0xFFE0) WHITE = const(0xFFFF) _ENCODE_PIXEL = ">H" _ENCODE_POS = ">HH" _DECODE_PIXEL = ">BBB" _BUFFER_SIZE = const(256) _BIT7 = const(0x80) _BIT6 = const(0x40) _BIT5 = const(0x20) _BIT4 = const(0x10) _BIT3 = const(0x08) _BIT2 = const(0x04) _BIT1 = const(0x02) _BIT0 = const(0x01) def color565(red, green=0, blue=0): """ Convert red, green and blue values (0-255) into a 16-bit 565 encoding. """ try: red, green, blue = red # see if the first var is a tuple/list except TypeError: pass return (red & 0xf8) << 8 | (green & 0xfc) << 3 | blue >> 3 def _encode_pos(x, y): """Encode a postion into bytes.""" return struct.pack(_ENCODE_POS, x, y) def _encode_pixel(color): """Encode a pixel color into bytes.""" return struct.pack(_ENCODE_PIXEL, color) class ST7789(): """ ST7789 driver class Args: spi (spi): spi object width (int): display width height (int): display height reset (pin): reset pin dc (pin): dc pin cs (pin): cs pin backlight(pin): backlight pin xstart (int): display xstart offset ystart (int): display ystart offset rotation (int): display rotation """ def __init__(self, spi, width, height, reset, dc, cs=None, backlight=None, xstart=-1, ystart=-1, rotation=0): """ Initialize display. """ if (width, height) != (240, 240) and (width, height) != (135, 240): raise ValueError( "Unsupported display. Only 240x240 and 135x240 are supported." ) self._display_width = self.width = width self._display_height = self.height = height self.spi = spi self.reset = reset self.dc = dc self.cs = cs self.backlight = backlight self._rotation = rotation % 4 self.xstart = xstart self.ystart = ystart self.hard_reset() self.soft_reset() self.sleep_mode(False) self._set_color_mode(COLOR_MODE_65K|COLOR_MODE_16BIT) time.sleep_ms(50) self.rotation(self._rotation) self.inversion_mode(True) time.sleep_ms(10) self.write(ST7789_NORON) time.sleep_ms(10) if backlight is not None: backlight.value(1) self.fill(0) self.write(ST7789_DISPON) time.sleep_ms(500) def write(self, command=None, data=None): """SPI write to the device: commands and data.""" if self.cs: self.cs.off() if command is not None: self.dc.off() self.spi.write(bytes([command])) if data is not None: self.dc.on() self.spi.write(data) if self.cs: self.cs.on() def hard_reset(self): """ Hard reset display. """ if self.cs: self.cs.off() if self.reset: self.reset.on() time.sleep_ms(50) # 20240320 Before 50 if self.reset: self.reset.off() time.sleep_ms(50) # 20240320 Before 50 if self.reset: self.reset.on() time.sleep_ms(150) # 20240320 Before 150 if self.cs: self.cs.on() def soft_reset(self): """ Soft reset display. """ self.write(ST7789_SWRESET) time.sleep_ms(150) def sleep_mode(self, value): """ Enable or disable display sleep mode. Args: value (bool): if True enable sleep mode. if False disable sleep mode """ if value: self.write(ST7789_SLPIN) else: self.write(ST7789_SLPOUT) def inversion_mode(self, value): """ Enable or disable display inversion mode. Args: value (bool): if True enable inversion mode. if False disable inversion mode """ if value: self.write(ST7789_INVON) else: self.write(ST7789_INVOFF) def _set_color_mode(self, mode): """ Set display color mode. Args: mode (int): color mode COLOR_MODE_65K, COLOR_MODE_262K, COLOR_MODE_12BIT, COLOR_MODE_16BIT, COLOR_MODE_18BIT, COLOR_MODE_16M """ self.write(ST7789_COLMOD, bytes([mode & 0x77])) def rotation(self, rotation): """ Set display rotation. Args: rotation (int): 0-Portrait, 1-Landscape, 2-Inverted Portrait, 3-Inverted Landscape """ self._rotation = rotation % 4 if self._rotation == 0: # Portrait madctl = ST7789_MADCTL_RGB self.width = self._display_width self.height = self._display_height if self._display_width == 135: self.xstart = 52 self.ystart = 40 elif self._rotation == 1: # Landscape madctl = ST7789_MADCTL_MX | ST7789_MADCTL_MV | ST7789_MADCTL_RGB self.width = self._display_height self.height = self._display_width if self._display_width == 135: self.xstart = 40 self.ystart = 53 elif self._rotation == 2: # Inverted Portrait madctl = ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB self.width = self._display_width self.height = self._display_height if self._display_width == 135: self.xstart = 53 self.ystart = 40 else: # Inverted Landscape madctl = ST7789_MADCTL_MV | ST7789_MADCTL_MY | ST7789_MADCTL_RGB self.width = self._display_height self.height = self._display_width if self._display_width == 135: self.xstart = 40 self.ystart = 52 self.write(ST7789_MADCTL, bytes([madctl])) def _set_columns(self, start, end): """ Send CASET (column address set) command to display. Args: start (int): column start address end (int): column end address """ if start <= end <= self.width: self.write(ST7789_CASET, _encode_pos( start+self.xstart, end + self.xstart)) def _set_rows(self, start, end): """ Send RASET (row address set) command to display. Args: start (int): row start address end (int): row end address """ if start <= end <= self.height: self.write(ST7789_RASET, _encode_pos( start+self.ystart, end+self.ystart)) def set_window(self, x0, y0, x1, y1): """ Set window to column and row address. Args: x0 (int): column start address y0 (int): row start address x1 (int): column end address y1 (int): row end address """ self._set_columns(x0, x1) self._set_rows(y0, y1) self.write(ST7789_RAMWR) def vline(self, x, y, length, color): """ Draw vertical line at the given location and color. Args: x (int): x coordinate Y (int): y coordinate length (int): length of line color (int): 565 encoded color """ self.fill_rect(x, y, 1, length, color) def hline(self, x, y, length, color): """ Draw horizontal line at the given location and color. Args: x (int): x coordinate Y (int): y coordinate length (int): length of line color (int): 565 encoded color """ self.fill_rect(x, y, length, 1, color) def pixel(self, x, y, color): """ Draw a pixel at the given location and color. Args: x (int): x coordinate Y (int): y coordinate color (int): 565 encoded color """ self.set_window(x, y, x, y) self.write(None, _encode_pixel(color)) def blit_buffer(self, buffer, x, y, width, height): """ Copy buffer to display at the given location. Args: buffer (bytes): Data to copy to display x (int): Top left corner x coordinate Y (int): Top left corner y coordinate width (int): Width height (int): Height """ self.set_window(x, y, x + width - 1, y + height - 1) self.write(None, buffer) def rect(self, x, y, w, h, color): """ Draw a rectangle at the given location, size and color. Args: x (int): Top left corner x coordinate y (int): Top left corner y coordinate width (int): Width in pixels height (int): Height in pixels color (int): 565 encoded color """ self.hline(x, y, w, color) self.vline(x, y, h, color) self.vline(x + w - 1, y, h, color) self.hline(x, y + h - 1, w, color) def fill_rect(self, x, y, width, height, color): """ Draw a rectangle at the given location, size and filled with color. Args: x (int): Top left corner x coordinate y (int): Top left corner y coordinate width (int): Width in pixels height (int): Height in pixels color (int): 565 encoded color """ self.set_window(x, y, x + width - 1, y + height - 1) chunks, rest = divmod(width * height, _BUFFER_SIZE) pixel = _encode_pixel(color) self.dc.on() if chunks: data = pixel * _BUFFER_SIZE for _ in range(chunks): self.write(None, data) if rest: self.write(None, pixel * rest) def fill(self, color): """ Fill the entire FrameBuffer with the specified color. Args: color (int): 565 encoded color """ self.fill_rect(0, 0, self.width, self.height, color) def line(self, x0, y0, x1, y1, color): """ Draw a single pixel wide line starting at x0, y0 and ending at x1, y1. Args: x0 (int): Start point x coordinate y0 (int): Start point y coordinate x1 (int): End point x coordinate y1 (int): End point y coordinate color (int): 565 encoded color """ steep = abs(y1 - y0) > abs(x1 - x0) if steep: x0, y0 = y0, x0 x1, y1 = y1, x1 if x0 > x1: x0, x1 = x1, x0 y0, y1 = y1, y0 dx = x1 - x0 dy = abs(y1 - y0) err = dx // 2 if y0 < y1: ystep = 1 else: ystep = -1 while x0 <= x1: if steep: self.pixel(y0, x0, color) else: self.pixel(x0, y0, color) err -= dy if err < 0: y0 += ystep err += dx x0 += 1 def vscrdef(self, tfa, vsa, bfa): """ Set Vertical Scrolling Definition. To scroll a 135x240 display these values should be 40, 240, 40. There are 40 lines above the display that are not shown followed by 240 lines that are shown followed by 40 more lines that are not shown. You could write to these areas off display and scroll them into view by changing the TFA, VSA and BFA values. Args: tfa (int): Top Fixed Area vsa (int): Vertical Scrolling Area bfa (int): Bottom Fixed Area """ struct.pack(">HHH", tfa, vsa, bfa) self.write(ST7789_VSCRDEF, struct.pack(">HHH", tfa, vsa, bfa)) def vscsad(self, vssa): """ Set Vertical Scroll Start Address of RAM. Defines which line in the Frame Memory will be written as the first line after the last line of the Top Fixed Area on the display Example: for line in range(40, 280, 1): tft.vscsad(line) utime.sleep(0.01) Args: vssa (int): Vertical Scrolling Start Address """ self.write(ST7789_VSCSAD, struct.pack(">H", vssa)) def _text8(self, font, text, x0, y0, color=WHITE, background=BLACK): """ Internal method to write characters with width of 8 and heights of 8 or 16. Args: font (module): font module to use text (str): text to write x0 (int): column to start drawing at y0 (int): row to start drawing at color (int): 565 encoded color to use for characters background (int): 565 encoded color to use for background """ for char in text: ch = ord(char) if (font.FIRST <= ch < font.LAST and x0+font.WIDTH <= self.width and y0+font.HEIGHT <= self.height): if font.HEIGHT == 8: passes = 1 size = 8 each = 0 else: passes = 2 size = 16 each = 8 for line in range(passes): idx = (ch-font.FIRST)*size+(each*line) buffer = struct.pack('>64H', color if font.FONT[idx] & _BIT7 else background, color if font.FONT[idx] & _BIT6 else background, color if font.FONT[idx] & _BIT5 else background, color if font.FONT[idx] & _BIT4 else background, color if font.FONT[idx] & _BIT3 else background, color if font.FONT[idx] & _BIT2 else background, color if font.FONT[idx] & _BIT1 else background, color if font.FONT[idx] & _BIT0 else background, color if font.FONT[idx+1] & _BIT7 else background, color if font.FONT[idx+1] & _BIT6 else background, color if font.FONT[idx+1] & _BIT5 else background, color if font.FONT[idx+1] & _BIT4 else background, color if font.FONT[idx+1] & _BIT3 else background, color if font.FONT[idx+1] & _BIT2 else background, color if font.FONT[idx+1] & _BIT1 else background, color if font.FONT[idx+1] & _BIT0 else background, color if font.FONT[idx+2] & _BIT7 else background, color if font.FONT[idx+2] & _BIT6 else background, color if font.FONT[idx+2] & _BIT5 else background, color if font.FONT[idx+2] & _BIT4 else background, color if font.FONT[idx+2] & _BIT3 else background, color if font.FONT[idx+2] & _BIT2 else background, color if font.FONT[idx+2] & _BIT1 else background, color if font.FONT[idx+2] & _BIT0 else background, color if font.FONT[idx+3] & _BIT7 else background, color if font.FONT[idx+3] & _BIT6 else background, color if font.FONT[idx+3] & _BIT5 else background, color if font.FONT[idx+3] & _BIT4 else background, color if font.FONT[idx+3] & _BIT3 else background, color if font.FONT[idx+3] & _BIT2 else background, color if font.FONT[idx+3] & _BIT1 else background, color if font.FONT[idx+3] & _BIT0 else background, color if font.FONT[idx+4] & _BIT7 else background, color if font.FONT[idx+4] & _BIT6 else background, color if font.FONT[idx+4] & _BIT5 else background, color if font.FONT[idx+4] & _BIT4 else background, color if font.FONT[idx+4] & _BIT3 else background, color if font.FONT[idx+4] & _BIT2 else background, color if font.FONT[idx+4] & _BIT1 else background, color if font.FONT[idx+4] & _BIT0 else background, color if font.FONT[idx+5] & _BIT7 else background, color if font.FONT[idx+5] & _BIT6 else background, color if font.FONT[idx+5] & _BIT5 else background, color if font.FONT[idx+5] & _BIT4 else background, color if font.FONT[idx+5] & _BIT3 else background, color if font.FONT[idx+5] & _BIT2 else background, color if font.FONT[idx+5] & _BIT1 else background, color if font.FONT[idx+5] & _BIT0 else background, color if font.FONT[idx+6] & _BIT7 else background, color if font.FONT[idx+6] & _BIT6 else background, color if font.FONT[idx+6] & _BIT5 else background, color if font.FONT[idx+6] & _BIT4 else background, color if font.FONT[idx+6] & _BIT3 else background, color if font.FONT[idx+6] & _BIT2 else background, color if font.FONT[idx+6] & _BIT1 else background, color if font.FONT[idx+6] & _BIT0 else background, color if font.FONT[idx+7] & _BIT7 else background, color if font.FONT[idx+7] & _BIT6 else background, color if font.FONT[idx+7] & _BIT5 else background, color if font.FONT[idx+7] & _BIT4 else background, color if font.FONT[idx+7] & _BIT3 else background, color if font.FONT[idx+7] & _BIT2 else background, color if font.FONT[idx+7] & _BIT1 else background, color if font.FONT[idx+7] & _BIT0 else background ) self.blit_buffer(buffer, x0, y0+8*line, 8, 8) x0 += 8 def _text16(self, font, text, x0, y0, color=WHITE, background=BLACK): """ Internal method to draw characters with width of 16 and heights of 16 or 32. Args: font (module): font module to use text (str): text to write x0 (int): column to start drawing at y0 (int): row to start drawing at color (int): 565 encoded color to use for characters background (int): 565 encoded color to use for background """ for char in text: ch = ord(char) if (font.FIRST <= ch < font.LAST and x0+font.WIDTH <= self.width and y0+font.HEIGHT <= self.height): if font.HEIGHT == 16: passes = 2 size = 32 each = 16 else: passes = 4 size = 64 each = 16 for line in range(passes): idx = (ch-font.FIRST)*size+(each*line) buffer = struct.pack('>128H', color if font.FONT[idx] & _BIT7 else background, color if font.FONT[idx] & _BIT6 else background, color if font.FONT[idx] & _BIT5 else background, color if font.FONT[idx] & _BIT4 else background, color if font.FONT[idx] & _BIT3 else background, color if font.FONT[idx] & _BIT2 else background, color if font.FONT[idx] & _BIT1 else background, color if font.FONT[idx] & _BIT0 else background, color if font.FONT[idx+1] & _BIT7 else background, color if font.FONT[idx+1] & _BIT6 else background, color if font.FONT[idx+1] & _BIT5 else background, color if font.FONT[idx+1] & _BIT4 else background, color if font.FONT[idx+1] & _BIT3 else background, color if font.FONT[idx+1] & _BIT2 else background, color if font.FONT[idx+1] & _BIT1 else background, color if font.FONT[idx+1] & _BIT0 else background, color if font.FONT[idx+2] & _BIT7 else background, color if font.FONT[idx+2] & _BIT6 else background, color if font.FONT[idx+2] & _BIT5 else background, color if font.FONT[idx+2] & _BIT4 else background, color if font.FONT[idx+2] & _BIT3 else background, color if font.FONT[idx+2] & _BIT2 else background, color if font.FONT[idx+2] & _BIT1 else background, color if font.FONT[idx+2] & _BIT0 else background, color if font.FONT[idx+3] & _BIT7 else background, color if font.FONT[idx+3] & _BIT6 else background, color if font.FONT[idx+3] & _BIT5 else background, color if font.FONT[idx+3] & _BIT4 else background, color if font.FONT[idx+3] & _BIT3 else background, color if font.FONT[idx+3] & _BIT2 else background, color if font.FONT[idx+3] & _BIT1 else background, color if font.FONT[idx+3] & _BIT0 else background, color if font.FONT[idx+4] & _BIT7 else background, color if font.FONT[idx+4] & _BIT6 else background, color if font.FONT[idx+4] & _BIT5 else background, color if font.FONT[idx+4] & _BIT4 else background, color if font.FONT[idx+4] & _BIT3 else background, color if font.FONT[idx+4] & _BIT2 else background, color if font.FONT[idx+4] & _BIT1 else background, color if font.FONT[idx+4] & _BIT0 else background, color if font.FONT[idx+5] & _BIT7 else background, color if font.FONT[idx+5] & _BIT6 else background, color if font.FONT[idx+5] & _BIT5 else background, color if font.FONT[idx+5] & _BIT4 else background, color if font.FONT[idx+5] & _BIT3 else background, color if font.FONT[idx+5] & _BIT2 else background, color if font.FONT[idx+5] & _BIT1 else background, color if font.FONT[idx+5] & _BIT0 else background, color if font.FONT[idx+6] & _BIT7 else background, color if font.FONT[idx+6] & _BIT6 else background, color if font.FONT[idx+6] & _BIT5 else background, color if font.FONT[idx+6] & _BIT4 else background, color if font.FONT[idx+6] & _BIT3 else background, color if font.FONT[idx+6] & _BIT2 else background, color if font.FONT[idx+6] & _BIT1 else background, color if font.FONT[idx+6] & _BIT0 else background, color if font.FONT[idx+7] & _BIT7 else background, color if font.FONT[idx+7] & _BIT6 else background, color if font.FONT[idx+7] & _BIT5 else background, color if font.FONT[idx+7] & _BIT4 else background, color if font.FONT[idx+7] & _BIT3 else background, color if font.FONT[idx+7] & _BIT2 else background, color if font.FONT[idx+7] & _BIT1 else background, color if font.FONT[idx+7] & _BIT0 else background, color if font.FONT[idx+8] & _BIT7 else background, color if font.FONT[idx+8] & _BIT6 else background, color if font.FONT[idx+8] & _BIT5 else background, color if font.FONT[idx+8] & _BIT4 else background, color if font.FONT[idx+8] & _BIT3 else background, color if font.FONT[idx+8] & _BIT2 else background, color if font.FONT[idx+8] & _BIT1 else background, color if font.FONT[idx+8] & _BIT0 else background, color if font.FONT[idx+9] & _BIT7 else background, color if font.FONT[idx+9] & _BIT6 else background, color if font.FONT[idx+9] & _BIT5 else background, color if font.FONT[idx+9] & _BIT4 else background, color if font.FONT[idx+9] & _BIT3 else background, color if font.FONT[idx+9] & _BIT2 else background, color if font.FONT[idx+9] & _BIT1 else background, color if font.FONT[idx+9] & _BIT0 else background, color if font.FONT[idx+10] & _BIT7 else background, color if font.FONT[idx+10] & _BIT6 else background, color if font.FONT[idx+10] & _BIT5 else background, color if font.FONT[idx+10] & _BIT4 else background, color if font.FONT[idx+10] & _BIT3 else background, color if font.FONT[idx+10] & _BIT2 else background, color if font.FONT[idx+10] & _BIT1 else background, color if font.FONT[idx+10] & _BIT0 else background, color if font.FONT[idx+11] & _BIT7 else background, color if font.FONT[idx+11] & _BIT6 else background, color if font.FONT[idx+11] & _BIT5 else background, color if font.FONT[idx+11] & _BIT4 else background, color if font.FONT[idx+11] & _BIT3 else background, color if font.FONT[idx+11] & _BIT2 else background, color if font.FONT[idx+11] & _BIT1 else background, color if font.FONT[idx+11] & _BIT0 else background, color if font.FONT[idx+12] & _BIT7 else background, color if font.FONT[idx+12] & _BIT6 else background, color if font.FONT[idx+12] & _BIT5 else background, color if font.FONT[idx+12] & _BIT4 else background, color if font.FONT[idx+12] & _BIT3 else background, color if font.FONT[idx+12] & _BIT2 else background, color if font.FONT[idx+12] & _BIT1 else background, color if font.FONT[idx+12] & _BIT0 else background, color if font.FONT[idx+13] & _BIT7 else background, color if font.FONT[idx+13] & _BIT6 else background, color if font.FONT[idx+13] & _BIT5 else background, color if font.FONT[idx+13] & _BIT4 else background, color if font.FONT[idx+13] & _BIT3 else background, color if font.FONT[idx+13] & _BIT2 else background, color if font.FONT[idx+13] & _BIT1 else background, color if font.FONT[idx+13] & _BIT0 else background, color if font.FONT[idx+14] & _BIT7 else background, color if font.FONT[idx+14] & _BIT6 else background, color if font.FONT[idx+14] & _BIT5 else background, color if font.FONT[idx+14] & _BIT4 else background, color if font.FONT[idx+14] & _BIT3 else background, color if font.FONT[idx+14] & _BIT2 else background, color if font.FONT[idx+14] & _BIT1 else background, color if font.FONT[idx+14] & _BIT0 else background, color if font.FONT[idx+15] & _BIT7 else background, color if font.FONT[idx+15] & _BIT6 else background, color if font.FONT[idx+15] & _BIT5 else background, color if font.FONT[idx+15] & _BIT4 else background, color if font.FONT[idx+15] & _BIT3 else background, color if font.FONT[idx+15] & _BIT2 else background, color if font.FONT[idx+15] & _BIT1 else background, color if font.FONT[idx+15] & _BIT0 else background ) self.blit_buffer(buffer, x0, y0+8*line, 16, 8) x0 += font.WIDTH def text(self, font, text, x0, y0, color=WHITE, background=BLACK): """ Draw text on display in specified font and colors. 8 and 16 bit wide fonts are supported. Args: font (module): font module to use. text (str): text to write x0 (int): column to start drawing at y0 (int): row to start drawing at color (int): 565 encoded color to use for characters background (int): 565 encoded color to use for background """ if font.WIDTH == 8: self._text8(font, text, x0, y0, color, background) else: self._text16(font, text, x0, y0, color, background)

ymf825py.py

ymf825py.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 # テーブル(辞書) exGmYmf825 = {00:00, # ピアノ系 01:06, # 02:Bright Acostic Piano:06:Bright Piano 02:01, # 03:Electric Grand Piano:01:E.Piano 03:01, # 04:Honky-Tonk Piano:01:E.Piano 04:01, # 05:Electric Piano 1:01:E.Piano 05:01, # 06:Electric Piano 2:01:E.Piano 06:00, 07:00, # クロマチック・パーカッション系:04:TiklBell 08:04, 09:04, 10:04, 11:07, # 12:Vibraphone:ヴィヴラフォン:大型鉄琴:07:Vibes 12:04, 13:04, 14:04, 15:04, 16:04, 17:04, # オルガン系 18:10, 19:08, # 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:03, # 33:Acosic Bass 通常のアコースティック:03:PickBass 33:03, # 34:Electric Bass (finger):03:PickBass 34:03, # 35:Electric Bass (pick):03:PickBass 35:03, 36:03, 37:03, 38:03, 39:03, # ストリングス系 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:05, # 51:Synth Strings 1:05:NewAgePd 51:05, # 52:Synth Strings 2:05:NewAgePd 52:05, 53:05, 54:05, 55:05, # ブラス系 56:00, 57:00, 58:00, 59:00, 60:00, 61:00, 62:00, 63:00, # リード系 64:02, 65:02, 66:02, 67:02, 68:02, 69:02, 70:02, 71:02, # 72:Clarinet:クラリネット:02:TenorSax # パイプ系 72:09, 73:09, # 74:Flute:フルート:09:Flute 74:13, # 75:Recorder:リコーダー:13:SawLead 75:13, 76:13, 77:13, 78:13, 79:13, # シンセ・リード系 80:00, 81:00, 82:00, 83:00, 84:00, 85:00, 86:00, 87:00, # シンセ・パッド系 88:00, 89:00, 90:00, 91:00, 92:00, 93:00, 94:00, 95:00, 96:00, # シンセ・エフェクト系 97:00, 98:00, 99:00,100:00,101:00,102:00,103:00, # エスニック系 104:00,105:00,106:00,107:00,108:00,109:00,110:00,111:00, # パーカッシヴ系 112:00,113:00,114:00,115:00,116:00,117:00,118:00,119:00, # 効果音 120:00,121:00,122:00,123:00,124:00,125:00,126:00,127:00,} 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) ################################################################# # 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)

「fonts」フォルダを作りその下に次のファイルをコピーしてください

vga1_16x32.py

vga1_16x32.py

WIDTH = 16 HEIGHT = 32 FIRST = 0x20 LAST = 0x7f _FONT = \ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x7f\xfe\x7f\xfe\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x7f\xfe\x7f\xfe\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x01\x80\x01\x80\x0f\xf0\x0f\xf0\x39\x9c\x39\x9c\x71\x8e\x71\x8e\x71\x80\x71\x80\x39\x80\x39\x80\x0f\xf0\x0f\xf0\x01\x9c\x01\x9c\x01\x8e\x01\x8e\x71\x8e\x71\x8e\x39\x9c\x39\x9c\x0f\xf0\x0f\xf0\x01\x80\x01\x80\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x1c\x1e\x1c\x1e\x38\x1e\x38\x00\x70\x00\x70\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x0e\x3c\x0e\x3c\x1c\x3c\x1c\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xc0\x07\xc0\x1c\x70\x1c\x70\x38\x38\x38\x38\x1c\x70\x1c\x70\x07\xc0\x07\xc0\x0f\xce\x0f\xce\x38\xfc\x38\xfc\x70\x78\x70\x78\x70\x78\x70\x78\x38\xfc\x38\xfc\x0f\xce\x0f\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x07\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x38\x0e\x38\x03\xe0\x03\xe0\x3f\xfe\x3f\xfe\x03\xe0\x03\xe0\x0e\x38\x0e\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x3f\xfe\x3f\xfe\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfe\x3f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00\x38\x00\x38\x00\x70\x00\x70\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x0e\x00\x0e\x00\x1c\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xe0\x07\xe0\x1c\x38\x1c\x38\x38\x3c\x38\x3c\x38\x7c\x38\x7c\x38\xdc\x38\xdc\x39\x9c\x39\x9c\x3b\x1c\x3b\x1c\x3e\x1c\x3e\x1c\x3c\x1c\x3c\x1c\x1c\x38\x1c\x38\x07\xe0\x07\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x03\xc0\x03\xc0\x0f\xc0\x0f\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf0\x0f\xf0\x38\x1c\x38\x1c\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x1c\x00\x1c\x00\x70\x00\x70\x01\xc0\x01\xc0\x07\x00\x07\x00\x1c\x00\x1c\x00\x38\x00\x38\x00\x3f\xfe\x3f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf0\x0f\xf0\x38\x1c\x38\x1c\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x1c\x00\x1c\x01\xf0\x01\xf0\x00\x1c\x00\x1c\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x38\x1c\x38\x1c\x0f\xf0\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x03\xf0\x03\xf0\x07\x70\x07\x70\x0e\x70\x0e\x70\x1c\x70\x1c\x70\x38\x70\x38\x70\x3f\xfc\x3f\xfc\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfe\x3f\xfe\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xf0\x3f\xf0\x00\x1c\x00\x1c\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x38\x1c\x38\x1c\x0f\xf0\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x00\x1c\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf8\x3f\xf8\x00\x38\x00\x38\x00\x38\x00\x38\x00\x70\x00\x70\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x0e\x1c\x0e\x07\xfe\x07\xfe\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x1c\x00\x1c\x0f\xf0\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x80\x03\x80\x03\x80\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x80\x03\x80\x03\x80\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x80\x03\x80\x03\x80\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x80\x03\x80\x03\x80\x03\x80\x07\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x0e\x00\x0e\x00\x1c\x00\x1c\x00\x0e\x00\x0e\x00\x07\x00\x07\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfc\x3f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfc\x3f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x07\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xe0\x00\xe0\x00\x70\x00\x70\x00\x38\x00\x38\x00\x70\x00\x70\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xe0\x07\xe0\x1c\x38\x1c\x38\x38\x1c\x38\x1c\x00\x38\x00\x38\x00\x70\x00\x70\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf0\x0f\xf0\x38\x1c\x38\x1c\x70\x0e\x70\x0e\x71\xfe\x71\xfe\x73\x8e\x73\x8e\x73\x8e\x73\x8e\x73\x8e\x73\x8e\x71\xfc\x71\xfc\x70\x00\x70\x00\x38\x00\x38\x00\x0f\xfc\x0f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x03\xc0\x03\xc0\x07\xe0\x07\xe0\x0e\x70\x0e\x70\x1c\x38\x1c\x38\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x3f\xfc\x3f\xfc\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x1c\x38\x1c\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x1c\x38\x1c\x3f\xf0\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x1c\x38\x1c\x3f\xf0\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfc\x3f\xfc\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xe0\x3f\xe0\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xfc\x3f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfc\x3f\xfc\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xe0\x3f\xe0\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x3e\x38\x3e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x3f\xfe\x3f\xfe\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x1c\x1c\x1c\x1c\x0e\x38\x0e\x38\x03\xe0\x03\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x38\x1c\x38\x1c\x70\x1c\x70\x1c\xe0\x1c\xe0\x1d\xc0\x1d\xc0\x1f\x80\x1f\x80\x1f\x80\x1f\x80\x1d\xc0\x1d\xc0\x1c\xe0\x1c\xe0\x1c\x70\x1c\x70\x1c\x38\x1c\x38\x1c\x1c\x1c\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xfc\x3f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x78\x1e\x78\x1e\x7c\x3e\x7c\x3e\x7e\x7e\x7e\x7e\x77\xee\x77\xee\x73\xce\x73\xce\x71\x8e\x71\x8e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0e\x38\x0e\x3c\x0e\x3c\x0e\x3e\x0e\x3e\x0e\x3f\x0e\x3f\x0e\x3b\x8e\x3b\x8e\x39\xce\x39\xce\x38\xee\x38\xee\x38\x7e\x38\x7e\x38\x3e\x38\x3e\x38\x1e\x38\x1e\x38\x0e\x38\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x1c\x38\x1c\x3f\xf0\x3f\xf0\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\xee\x38\xee\x1c\x7c\x1c\x7c\x07\xf8\x07\xf8\x00\x1c\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x1c\x38\x1c\x3f\xf0\x3f\xf0\x38\xe0\x38\xe0\x38\x70\x38\x70\x38\x38\x38\x38\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf0\x0f\xf0\x38\x1c\x38\x1c\x70\x0e\x70\x0e\x70\x00\x70\x00\x38\x00\x38\x00\x0f\xf0\x0f\xf0\x00\x1c\x00\x1c\x00\x0e\x00\x0e\x70\x0e\x70\x0e\x38\x1c\x38\x1c\x0f\xf0\x0f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfe\x3f\xfe\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x1c\x38\x1c\x38\x0e\x70\x0e\x70\x07\xe0\x07\xe0\x03\xc0\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x70\x0e\x71\x8e\x71\x8e\x73\xce\x73\xce\x77\xee\x77\xee\x3e\x7c\x3e\x7c\x1c\x38\x1c\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x1c\x38\x1c\x38\x0e\x70\x0e\x70\x07\xe0\x07\xe0\x03\xc0\x03\xc0\x07\xe0\x07\xe0\x0e\x70\x0e\x70\x1c\x38\x1c\x38\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x0e\x38\x0e\x38\x07\x70\x07\x70\x03\xe0\x03\xe0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfe\x3f\xfe\x00\x1c\x00\x1c\x00\x38\x00\x38\x00\x70\x00\x70\x00\xe0\x00\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x0e\x00\x0e\x00\x1c\x00\x1c\x00\x3f\xfe\x3f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00\x0e\x00\x0e\x00\x07\x00\x07\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xe0\x00\xe0\x00\x70\x00\x70\x00\x38\x00\x38\x00\x1c\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x03\xc0\x03\xc0\x07\xe0\x07\xe0\x0e\x70\x0e\x70\x1c\x38\x1c\x38\x38\x1c\x38\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x07\x00\x07\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf8\x0f\xf8\x00\x0e\x00\x0e\x0f\xfe\x0f\xfe\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x0f\xfe\x0f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x3f\xf8\x3f\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf8\x0f\xf8\x38\x0e\x38\x0e\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x0e\x38\x0e\x0f\xf8\x0f\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x07\xfe\x07\xfe\x1c\x0e\x1c\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x0f\xfe\x0f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf8\x0f\xf8\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x3f\xfe\x3f\xfe\x38\x00\x38\x00\x38\x00\x38\x00\x0f\xfc\x0f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00\xf8\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x0f\xf0\x0f\xf0\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xf8\x0f\xf8\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x0f\xfe\x0f\xfe\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x1f\xf8\x1f\xf8\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x3b\xf8\x3b\xf8\x3c\x0e\x3c\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x70\x00\x70\x00\x70\x00\x00\x00\x00\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\x70\x00\xe0\x00\xe0\x0f\x80\x0f\x80\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x38\x0e\x38\x0e\x70\x0e\x70\x0e\xe0\x0e\xe0\x0f\xc0\x0f\xc0\x0e\xe0\x0e\xe0\x0e\x70\x0e\x70\x0e\x38\x0e\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3e\x78\x3e\x78\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x39\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xe0\x3f\xe0\x38\x38\x38\x38\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x07\xf0\x1c\x1c\x1c\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x07\xf0\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x1c\x38\x1c\x3f\xf0\x3f\xf0\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xfe\x07\xfe\x1c\x0e\x1c\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x1c\x0e\x1c\x0e\x07\xfe\x07\xfe\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xf0\x3f\xf0\x38\x1c\x38\x1c\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xfc\x0f\xfc\x38\x00\x38\x00\x38\x00\x38\x00\x0f\xf8\x0f\xf8\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x1f\xf8\x1f\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x1f\xfc\x1f\xfc\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x38\x1c\x0f\xfc\x0f\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x0e\x70\x0e\x38\x1c\x38\x1c\x1c\x38\x1c\x38\x0e\x70\x0e\x70\x07\xe0\x07\xe0\x03\xc0\x03\xc0\x01\x80\x01\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x38\x0e\x39\xce\x39\xce\x3b\xee\x3b\xee\x1f\x7c\x1f\x7c\x0e\x38\x0e\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x38\x1c\x38\x0e\x70\x0e\x70\x07\xe0\x07\xe0\x03\xc0\x03\xc0\x07\xe0\x07\xe0\x0e\x70\x0e\x70\x1c\x38\x1c\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0e\x38\x0e\x1c\x1c\x1c\x1c\x0e\x38\x0e\x38\x07\x70\x07\x70\x03\xe0\x03\xe0\x01\xc0\x01\xc0\x03\x80\x03\x80\x07\x00\x07\x00\x0e\x00\x0e\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xfe\x3f\xfe\x00\x1c\x00\x1c\x00\x70\x00\x70\x01\xc0\x01\xc0\x07\x00\x07\x00\x1c\x00\x1c\x00\x3f\xfe\x3f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00\xf8\x01\xc0\x01\xc0\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x1e\x00\x1e\x00\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x03\x80\x01\xc0\x01\xc0\x00\xf8\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x1f\x00\x03\x80\x03\x80\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x00\x78\x00\x78\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x03\x80\x03\x80\x1f\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\x9e\x07\x9e\x3c\xf0\x3c\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x01\xc0\x07\x70\x07\x70\x1c\x1c\x1c\x1c\x70\x07\x70\x07\x70\x07\x70\x07\x7f\xff\x7f\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ FONT = memoryview(_FONT)

vga2_8x8.py

vga2_8x8.py

"""converted from vga_8x8.bin """ WIDTH = 8 HEIGHT = 8 FIRST = 0x00 LAST = 0xff _FONT =\ b'\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x7e\x81\xa5\x81\xbd\x99\x81\x7e'\ b'\x7e\xff\xdb\xff\xc3\xe7\xff\x7e'\ b'\x6c\xfe\xfe\xfe\x7c\x38\x10\x00'\ b'\x10\x38\x7c\xfe\x7c\x38\x10\x00'\ b'\x38\x7c\x38\xfe\xfe\xd6\x10\x38'\ b'\x10\x38\x7c\xfe\xfe\x7c\x10\x38'\ b'\x00\x00\x18\x3c\x3c\x18\x00\x00'\ b'\xff\xff\xe7\xc3\xc3\xe7\xff\xff'\ b'\x00\x3c\x66\x42\x42\x66\x3c\x00'\ b'\xff\xc3\x99\xbd\xbd\x99\xc3\xff'\ b'\x0f\x07\x0f\x7d\xcc\xcc\xcc\x78'\ b'\x3c\x66\x66\x66\x3c\x18\x7e\x18'\ b'\x3f\x33\x3f\x30\x30\x70\xf0\xe0'\ b'\x7f\x63\x7f\x63\x63\x67\xe6\xc0'\ b'\x18\xdb\x3c\xe7\xe7\x3c\xdb\x18'\ b'\x80\xe0\xf8\xfe\xf8\xe0\x80\x00'\ b'\x02\x0e\x3e\xfe\x3e\x0e\x02\x00'\ b'\x18\x3c\x7e\x18\x18\x7e\x3c\x18'\ b'\x66\x66\x66\x66\x66\x00\x66\x00'\ b'\x7f\xdb\xdb\x7b\x1b\x1b\x1b\x00'\ b'\x3e\x61\x3c\x66\x66\x3c\x86\x7c'\ b'\x00\x00\x00\x00\x7e\x7e\x7e\x00'\ b'\x18\x3c\x7e\x18\x7e\x3c\x18\xff'\ b'\x18\x3c\x7e\x18\x18\x18\x18\x00'\ b'\x18\x18\x18\x18\x7e\x3c\x18\x00'\ b'\x00\x18\x0c\xfe\x0c\x18\x00\x00'\ b'\x00\x30\x60\xfe\x60\x30\x00\x00'\ b'\x00\x00\xc0\xc0\xc0\xfe\x00\x00'\ b'\x00\x24\x66\xff\x66\x24\x00\x00'\ b'\x00\x18\x3c\x7e\xff\xff\x00\x00'\ b'\x00\xff\xff\x7e\x3c\x18\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x18\x3c\x3c\x18\x18\x00\x18\x00'\ b'\x66\x66\x24\x00\x00\x00\x00\x00'\ b'\x6c\x6c\xfe\x6c\xfe\x6c\x6c\x00'\ b'\x18\x3e\x60\x3c\x06\x7c\x18\x00'\ b'\x00\xc6\xcc\x18\x30\x66\xc6\x00'\ b'\x38\x6c\x38\x76\xdc\xcc\x76\x00'\ b'\x18\x18\x30\x00\x00\x00\x00\x00'\ b'\x0c\x18\x30\x30\x30\x18\x0c\x00'\ b'\x30\x18\x0c\x0c\x0c\x18\x30\x00'\ b'\x00\x66\x3c\xff\x3c\x66\x00\x00'\ b'\x00\x18\x18\x7e\x18\x18\x00\x00'\ b'\x00\x00\x00\x00\x00\x18\x18\x30'\ b'\x00\x00\x00\x7e\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x18\x18\x00'\ b'\x06\x0c\x18\x30\x60\xc0\x80\x00'\ b'\x38\x6c\xc6\xd6\xc6\x6c\x38\x00'\ b'\x18\x38\x18\x18\x18\x18\x7e\x00'\ b'\x7c\xc6\x06\x1c\x30\x66\xfe\x00'\ b'\x7c\xc6\x06\x3c\x06\xc6\x7c\x00'\ b'\x1c\x3c\x6c\xcc\xfe\x0c\x1e\x00'\ b'\xfe\xc0\xc0\xfc\x06\xc6\x7c\x00'\ b'\x38\x60\xc0\xfc\xc6\xc6\x7c\x00'\ b'\xfe\xc6\x0c\x18\x30\x30\x30\x00'\ b'\x7c\xc6\xc6\x7c\xc6\xc6\x7c\x00'\ b'\x7c\xc6\xc6\x7e\x06\x0c\x78\x00'\ b'\x00\x18\x18\x00\x00\x18\x18\x00'\ b'\x00\x18\x18\x00\x00\x18\x18\x30'\ b'\x06\x0c\x18\x30\x18\x0c\x06\x00'\ b'\x00\x00\x7e\x00\x00\x7e\x00\x00'\ b'\x60\x30\x18\x0c\x18\x30\x60\x00'\ b'\x7c\xc6\x0c\x18\x18\x00\x18\x00'\ b'\x7c\xc6\xde\xde\xde\xc0\x78\x00'\ b'\x38\x6c\xc6\xfe\xc6\xc6\xc6\x00'\ b'\xfc\x66\x66\x7c\x66\x66\xfc\x00'\ b'\x3c\x66\xc0\xc0\xc0\x66\x3c\x00'\ b'\xf8\x6c\x66\x66\x66\x6c\xf8\x00'\ b'\xfe\x62\x68\x78\x68\x62\xfe\x00'\ b'\xfe\x62\x68\x78\x68\x60\xf0\x00'\ b'\x3c\x66\xc0\xc0\xce\x66\x3a\x00'\ b'\xc6\xc6\xc6\xfe\xc6\xc6\xc6\x00'\ b'\x3c\x18\x18\x18\x18\x18\x3c\x00'\ b'\x1e\x0c\x0c\x0c\xcc\xcc\x78\x00'\ b'\xe6\x66\x6c\x78\x6c\x66\xe6\x00'\ b'\xf0\x60\x60\x60\x62\x66\xfe\x00'\ b'\xc6\xee\xfe\xfe\xd6\xc6\xc6\x00'\ b'\xc6\xe6\xf6\xde\xce\xc6\xc6\x00'\ b'\x7c\xc6\xc6\xc6\xc6\xc6\x7c\x00'\ b'\xfc\x66\x66\x7c\x60\x60\xf0\x00'\ b'\x7c\xc6\xc6\xc6\xc6\xce\x7c\x0e'\ b'\xfc\x66\x66\x7c\x6c\x66\xe6\x00'\ b'\x3c\x66\x30\x18\x0c\x66\x3c\x00'\ b'\x7e\x7e\x5a\x18\x18\x18\x3c\x00'\ b'\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00'\ b'\xc6\xc6\xc6\xc6\xc6\x6c\x38\x00'\ b'\xc6\xc6\xc6\xd6\xd6\xfe\x6c\x00'\ b'\xc6\xc6\x6c\x38\x6c\xc6\xc6\x00'\ b'\x66\x66\x66\x3c\x18\x18\x3c\x00'\ b'\xfe\xc6\x8c\x18\x32\x66\xfe\x00'\ b'\x3c\x30\x30\x30\x30\x30\x3c\x00'\ b'\xc0\x60\x30\x18\x0c\x06\x02\x00'\ b'\x3c\x0c\x0c\x0c\x0c\x0c\x3c\x00'\ b'\x10\x38\x6c\xc6\x00\x00\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\xff'\ b'\x30\x18\x0c\x00\x00\x00\x00\x00'\ b'\x00\x00\x78\x0c\x7c\xcc\x76\x00'\ b'\xe0\x60\x7c\x66\x66\x66\xdc\x00'\ b'\x00\x00\x7c\xc6\xc0\xc6\x7c\x00'\ b'\x1c\x0c\x7c\xcc\xcc\xcc\x76\x00'\ b'\x00\x00\x7c\xc6\xfe\xc0\x7c\x00'\ b'\x3c\x66\x60\xf8\x60\x60\xf0\x00'\ b'\x00\x00\x76\xcc\xcc\x7c\x0c\xf8'\ b'\xe0\x60\x6c\x76\x66\x66\xe6\x00'\ b'\x18\x00\x38\x18\x18\x18\x3c\x00'\ b'\x06\x00\x06\x06\x06\x66\x66\x3c'\ b'\xe0\x60\x66\x6c\x78\x6c\xe6\x00'\ b'\x38\x18\x18\x18\x18\x18\x3c\x00'\ b'\x00\x00\xec\xfe\xd6\xd6\xd6\x00'\ b'\x00\x00\xdc\x66\x66\x66\x66\x00'\ b'\x00\x00\x7c\xc6\xc6\xc6\x7c\x00'\ b'\x00\x00\xdc\x66\x66\x7c\x60\xf0'\ b'\x00\x00\x76\xcc\xcc\x7c\x0c\x1e'\ b'\x00\x00\xdc\x76\x60\x60\xf0\x00'\ b'\x00\x00\x7e\xc0\x7c\x06\xfc\x00'\ b'\x30\x30\xfc\x30\x30\x36\x1c\x00'\ b'\x00\x00\xcc\xcc\xcc\xcc\x76\x00'\ b'\x00\x00\xc6\xc6\xc6\x6c\x38\x00'\ b'\x00\x00\xc6\xd6\xd6\xfe\x6c\x00'\ b'\x00\x00\xc6\x6c\x38\x6c\xc6\x00'\ b'\x00\x00\xc6\xc6\xc6\x7e\x06\xfc'\ b'\x00\x00\x7e\x4c\x18\x32\x7e\x00'\ b'\x0e\x18\x18\x70\x18\x18\x0e\x00'\ b'\x18\x18\x18\x18\x18\x18\x18\x00'\ b'\x70\x18\x18\x0e\x18\x18\x70\x00'\ b'\x76\xdc\x00\x00\x00\x00\x00\x00'\ b'\x00\x10\x38\x6c\xc6\xc6\xfe\x00'\ b'\x7c\xc6\xc0\xc0\xc6\x7c\x0c\x78'\ b'\xcc\x00\xcc\xcc\xcc\xcc\x76\x00'\ b'\x0c\x18\x7c\xc6\xfe\xc0\x7c\x00'\ b'\x7c\x82\x78\x0c\x7c\xcc\x76\x00'\ b'\xc6\x00\x78\x0c\x7c\xcc\x76\x00'\ b'\x30\x18\x78\x0c\x7c\xcc\x76\x00'\ b'\x30\x30\x78\x0c\x7c\xcc\x76\x00'\ b'\x00\x00\x7e\xc0\xc0\x7e\x0c\x38'\ b'\x7c\x82\x7c\xc6\xfe\xc0\x7c\x00'\ b'\xc6\x00\x7c\xc6\xfe\xc0\x7c\x00'\ b'\x30\x18\x7c\xc6\xfe\xc0\x7c\x00'\ b'\x66\x00\x38\x18\x18\x18\x3c\x00'\ b'\x7c\x82\x38\x18\x18\x18\x3c\x00'\ b'\x30\x18\x00\x38\x18\x18\x3c\x00'\ b'\xc6\x38\x6c\xc6\xfe\xc6\xc6\x00'\ b'\x38\x6c\x7c\xc6\xfe\xc6\xc6\x00'\ b'\x18\x30\xfe\xc0\xf8\xc0\xfe\x00'\ b'\x00\x00\x7e\x18\x7e\xd8\x7e\x00'\ b'\x3e\x6c\xcc\xfe\xcc\xcc\xce\x00'\ b'\x7c\x82\x7c\xc6\xc6\xc6\x7c\x00'\ b'\xc6\x00\x7c\xc6\xc6\xc6\x7c\x00'\ b'\x30\x18\x7c\xc6\xc6\xc6\x7c\x00'\ b'\x78\x84\x00\xcc\xcc\xcc\x76\x00'\ b'\x60\x30\xcc\xcc\xcc\xcc\x76\x00'\ b'\xc6\x00\xc6\xc6\xc6\x7e\x06\xfc'\ b'\xc6\x38\x6c\xc6\xc6\x6c\x38\x00'\ b'\xc6\x00\xc6\xc6\xc6\xc6\x7c\x00'\ b'\x18\x18\x7e\xc0\xc0\x7e\x18\x18'\ b'\x38\x6c\x64\xf0\x60\x66\xfc\x00'\ b'\x66\x66\x3c\x7e\x18\x7e\x18\x18'\ b'\xf8\xcc\xcc\xfa\xc6\xcf\xc6\xc7'\ b'\x0e\x1b\x18\x3c\x18\xd8\x70\x00'\ b'\x18\x30\x78\x0c\x7c\xcc\x76\x00'\ b'\x0c\x18\x00\x38\x18\x18\x3c\x00'\ b'\x0c\x18\x7c\xc6\xc6\xc6\x7c\x00'\ b'\x18\x30\xcc\xcc\xcc\xcc\x76\x00'\ b'\x76\xdc\x00\xdc\x66\x66\x66\x00'\ b'\x76\xdc\x00\xe6\xf6\xde\xce\x00'\ b'\x3c\x6c\x6c\x3e\x00\x7e\x00\x00'\ b'\x38\x6c\x6c\x38\x00\x7c\x00\x00'\ b'\x18\x00\x18\x18\x30\x63\x3e\x00'\ b'\x00\x00\x00\xfe\xc0\xc0\x00\x00'\ b'\x00\x00\x00\xfe\x06\x06\x00\x00'\ b'\x63\xe6\x6c\x7e\x33\x66\xcc\x0f'\ b'\x63\xe6\x6c\x7a\x36\x6a\xdf\x06'\ b'\x18\x00\x18\x18\x3c\x3c\x18\x00'\ b'\x00\x33\x66\xcc\x66\x33\x00\x00'\ b'\x00\xcc\x66\x33\x66\xcc\x00\x00'\ b'\x22\x88\x22\x88\x22\x88\x22\x88'\ b'\x55\xaa\x55\xaa\x55\xaa\x55\xaa'\ b'\x77\xdd\x77\xdd\x77\xdd\x77\xdd'\ b'\x18\x18\x18\x18\x18\x18\x18\x18'\ b'\x18\x18\x18\x18\xf8\x18\x18\x18'\ b'\x18\x18\xf8\x18\xf8\x18\x18\x18'\ b'\x36\x36\x36\x36\xf6\x36\x36\x36'\ b'\x00\x00\x00\x00\xfe\x36\x36\x36'\ b'\x00\x00\xf8\x18\xf8\x18\x18\x18'\ b'\x36\x36\xf6\x06\xf6\x36\x36\x36'\ b'\x36\x36\x36\x36\x36\x36\x36\x36'\ b'\x00\x00\xfe\x06\xf6\x36\x36\x36'\ b'\x36\x36\xf6\x06\xfe\x00\x00\x00'\ b'\x36\x36\x36\x36\xfe\x00\x00\x00'\ b'\x18\x18\xf8\x18\xf8\x00\x00\x00'\ b'\x00\x00\x00\x00\xf8\x18\x18\x18'\ b'\x18\x18\x18\x18\x1f\x00\x00\x00'\ b'\x18\x18\x18\x18\xff\x00\x00\x00'\ b'\x00\x00\x00\x00\xff\x18\x18\x18'\ b'\x18\x18\x18\x18\x1f\x18\x18\x18'\ b'\x00\x00\x00\x00\xff\x00\x00\x00'\ b'\x18\x18\x18\x18\xff\x18\x18\x18'\ b'\x18\x18\x1f\x18\x1f\x18\x18\x18'\ b'\x36\x36\x36\x36\x37\x36\x36\x36'\ b'\x36\x36\x37\x30\x3f\x00\x00\x00'\ b'\x00\x00\x3f\x30\x37\x36\x36\x36'\ b'\x36\x36\xf7\x00\xff\x00\x00\x00'\ b'\x00\x00\xff\x00\xf7\x36\x36\x36'\ b'\x36\x36\x37\x30\x37\x36\x36\x36'\ b'\x00\x00\xff\x00\xff\x00\x00\x00'\ b'\x36\x36\xf7\x00\xf7\x36\x36\x36'\ b'\x18\x18\xff\x00\xff\x00\x00\x00'\ b'\x36\x36\x36\x36\xff\x00\x00\x00'\ b'\x00\x00\xff\x00\xff\x18\x18\x18'\ b'\x00\x00\x00\x00\xff\x36\x36\x36'\ b'\x36\x36\x36\x36\x3f\x00\x00\x00'\ b'\x18\x18\x1f\x18\x1f\x00\x00\x00'\ b'\x00\x00\x1f\x18\x1f\x18\x18\x18'\ b'\x00\x00\x00\x00\x3f\x36\x36\x36'\ b'\x36\x36\x36\x36\xff\x36\x36\x36'\ b'\x18\x18\xff\x18\xff\x18\x18\x18'\ b'\x18\x18\x18\x18\xf8\x00\x00\x00'\ b'\x00\x00\x00\x00\x1f\x18\x18\x18'\ b'\xff\xff\xff\xff\xff\xff\xff\xff'\ b'\x00\x00\x00\x00\xff\xff\xff\xff'\ b'\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0'\ b'\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f'\ b'\xff\xff\xff\xff\x00\x00\x00\x00'\ b'\x00\x00\x76\xdc\xc8\xdc\x76\x00'\ b'\x78\xcc\xcc\xd8\xcc\xc6\xcc\x00'\ b'\xfe\xc6\xc0\xc0\xc0\xc0\xc0\x00'\ b'\x00\x00\xfe\x6c\x6c\x6c\x6c\x00'\ b'\xfe\xc6\x60\x30\x60\xc6\xfe\x00'\ b'\x00\x00\x7e\xd8\xd8\xd8\x70\x00'\ b'\x00\x00\x66\x66\x66\x66\x7c\xc0'\ b'\x00\x76\xdc\x18\x18\x18\x18\x00'\ b'\x7e\x18\x3c\x66\x66\x3c\x18\x7e'\ b'\x38\x6c\xc6\xfe\xc6\x6c\x38\x00'\ b'\x38\x6c\xc6\xc6\x6c\x6c\xee\x00'\ b'\x0e\x18\x0c\x3e\x66\x66\x3c\x00'\ b'\x00\x00\x7e\xdb\xdb\x7e\x00\x00'\ b'\x06\x0c\x7e\xdb\xdb\x7e\x60\xc0'\ b'\x1e\x30\x60\x7e\x60\x30\x1e\x00'\ b'\x00\x7c\xc6\xc6\xc6\xc6\xc6\x00'\ b'\x00\xfe\x00\xfe\x00\xfe\x00\x00'\ b'\x18\x18\x7e\x18\x18\x00\x7e\x00'\ b'\x30\x18\x0c\x18\x30\x00\x7e\x00'\ b'\x0c\x18\x30\x18\x0c\x00\x7e\x00'\ b'\x0e\x1b\x1b\x18\x18\x18\x18\x18'\ b'\x18\x18\x18\x18\x18\xd8\xd8\x70'\ b'\x00\x18\x00\x7e\x00\x18\x00\x00'\ b'\x00\x76\xdc\x00\x76\xdc\x00\x00'\ b'\x38\x6c\x6c\x38\x00\x00\x00\x00'\ b'\x00\x00\x00\x18\x18\x00\x00\x00'\ b'\x00\x00\x00\x18\x00\x00\x00\x00'\ b'\x0f\x0c\x0c\x0c\xec\x6c\x3c\x1c'\ b'\x6c\x36\x36\x36\x36\x00\x00\x00'\ b'\x78\x0c\x18\x30\x7c\x00\x00\x00'\ b'\x00\x00\x3c\x3c\x3c\x3c\x00\x00'\ b'\x00\x00\x00\x00\x00\x00\x00\x00'\ FONT = memoryview(_FONT)

PicoS_Lib

(以下のプログラムは予めPicoSubに書き込んでおいてください)
プログラムは、PicoM_libにあるものと同じです。
mojipy.py
ymf825py.py

Hyodotのアイコン画像
真空管アンプ、トランジスタ回路、IC(SN74xx)、Z80。 その後、24時間戦えますかモード?に突入、電子工作から途絶。 定年で戦いを終え、電子工作を再開、浦島太郎。 PIC、IchigoJam、Arduino、RaspberryPi、micro:bit、 今は、Pico Pythonで遊んでいます。 アセンブラーもやるアラ・セブン。 ・・・アラセブン 脳トレ成果を 置き土産・・・
  • Hyodot さんが 前の日曜日の20:29 に 編集 をしました。 (メッセージ: 初版)
ログインしてコメントを投稿する