外観
動画
編集画面や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接続
PicoSubとYMF825とのSPI-0接続図
PicoMainとPicoSubとのgpio接続図
MIDIインターフェースとPicoMain、PicoSubとのUART-0接続図
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キーで項目をクリア)
- 設定したパラメータは、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
###############################################################################
# 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
# 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
###############################################################################
# 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
###############################################################################
# 目標: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
"""
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
#############################################################################
# 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
さんが
2024/10/27
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する