Skip to content

Commit

Permalink
Fixing Yamaha FS1R after testing with the MID files downloaded
Browse files Browse the repository at this point in the history
  • Loading branch information
christofmuc committed Feb 6, 2025
1 parent 522dc54 commit 30951d5
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 87 deletions.
143 changes: 56 additions & 87 deletions adaptations/Yamaha_FS1R_2.py → adaptations/Yamaha_FS1R.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
#
# Dual licensed: Distributed under Affero GPL license by default, an MIT license is available for purchase
#
import itertools
from copy import copy
from typing import List

import knobkraft
import testing
from knobkraft import load_midi

YAMAHA_ID=0x43
YAMAHA_FS1R=0x5e
Expand All @@ -24,33 +22,33 @@

DEVICE_ID_DETECTED=0x00

class DataBlock:
def __init__(self, address, size, name):
pass

fs1r_performance_data = [DataBlock((0x10, 0x00, 0x00), 80, "Performance Common"), # The first 12 bytes are the name
DataBlock((0x10, 0x00, 0x50), 112, "Effect"),
DataBlock((0x30, 0x00, 0x00), 52, "Part 1"),
DataBlock((0x31, 0x00, 0x00), 52, "Part 2"),
DataBlock((0x32, 0x00, 0x00), 52, "Part 3"),
DataBlock((0x33, 0x00, 0x00), 52, "Part 4")]

fs1_all_performance_data = [DataBlock((0x11, 0x00, 0x00), 400, "Performance")]


fs1r_voice_data = [DataBlock((0x40, 0x00, 0x00), 112, "Voice Common")] + \
[DataBlock((0x60, op, 0x00), 35, "Operator 1 Voiced") for op in range(8)] + \
[DataBlock((0x60, op, 0x23), 27, "Operator 1 Non-Voiced") for op in range(8)] + \
[DataBlock((0x61, op, 0x00), 35, "Operator 2 Voiced") for op in range(8)] + \
[DataBlock((0x61, op, 0x23), 27, "Operator 2 Non-Voiced") for op in range(8)] + \
[DataBlock((0x62, op, 0x00), 35, "Operator 3 Voiced") for op in range(8)] + \
[DataBlock((0x62, op, 0x23), 27, "Operator 3 Non-Voiced") for op in range(8)] + \
[DataBlock((0x63, op, 0x00), 35, "Operator 4 Voiced") for op in range(8)] + \
[DataBlock((0x64, op, 0x23), 27, "Operator 4 Non-Voiced") for op in range(8)]

fs1r_fseq_data = [DataBlock((0x70, 0x00, 0x00), 0x00, "Fseq parameter")] # 8 bytes of name at the start, byte count not used in here

fs1r_system_data = [DataBlock((0x00, 0x00, 0x00), 0x4c, "System Parameter")]
# class DataBlock:
# def __init__(self, address, size, name):
# pass
#
# fs1r_performance_data = [DataBlock((0x10, 0x00, 0x00), 80, "Performance Common"), # The first 12 bytes are the name
# DataBlock((0x10, 0x00, 0x50), 112, "Effect"),
# DataBlock((0x30, 0x00, 0x00), 52, "Part 1"),
# DataBlock((0x31, 0x00, 0x00), 52, "Part 2"),
# DataBlock((0x32, 0x00, 0x00), 52, "Part 3"),
# DataBlock((0x33, 0x00, 0x00), 52, "Part 4")]
#
# fs1_all_performance_data = [DataBlock((0x11, 0x00, 0x00), 400, "Performance")]
#
#
# fs1r_voice_data = [DataBlock((0x40, 0x00, 0x00), 112, "Voice Common")] + \
# [DataBlock((0x60, op, 0x00), 35, "Operator 1 Voiced") for op in range(8)] + \
# [DataBlock((0x60, op, 0x23), 27, "Operator 1 Non-Voiced") for op in range(8)] + \
# [DataBlock((0x61, op, 0x00), 35, "Operator 2 Voiced") for op in range(8)] + \
# [DataBlock((0x61, op, 0x23), 27, "Operator 2 Non-Voiced") for op in range(8)] + \
# [DataBlock((0x62, op, 0x00), 35, "Operator 3 Voiced") for op in range(8)] + \
# [DataBlock((0x62, op, 0x23), 27, "Operator 3 Non-Voiced") for op in range(8)] + \
# [DataBlock((0x63, op, 0x00), 35, "Operator 4 Voiced") for op in range(8)] + \
# [DataBlock((0x64, op, 0x23), 27, "Operator 4 Non-Voiced") for op in range(8)]
#
# fs1r_fseq_data = [DataBlock((0x70, 0x00, 0x00), 0x00, "Fseq parameter")] # 8 bytes of name at the start, byte count not used in here
#
# fs1r_system_data = [DataBlock((0x00, 0x00, 0x00), 0x4c, "System Parameter")]


def name():
Expand Down Expand Up @@ -111,21 +109,13 @@ def renamePatch(message, new_name):
raise Exception("can only rename single program dumps!")


# def createEditBufferRequest(channel):
# # How do we request the Voices? Just send all requests at once?
# return buildRequest(channel, PERFORMANCE_EDIT_BUFFER_ADDRESS) + \
# buildRequest(channel, VOICE_EDIT_BUFFFER_PART1) + \
# buildRequest(channel, VOICE_EDIT_BUFFFER_PART2) + \
# buildRequest(channel, VOICE_EDIT_BUFFFER_PART3) + \
# buildRequest(channel, VOICE_EDIT_BUFFFER_PART4)
#
#
# def isPartOfEditBufferDump(message):
# # Accept a certain set of addresses
# if isOwnSysex(message):
# address = addressFromMessage(message)
# return address in [PERFORMANCE_EDIT_BUFFER_ADDRESS, VOICE_EDIT_BUFFFER_PART1, VOICE_EDIT_BUFFFER_PART2, VOICE_EDIT_BUFFFER_PART3, VOICE_EDIT_BUFFFER_PART4]
# return False
def createEditBufferRequest(channel):
# How do we request the Voices? Just send all requests at once?
return buildRequest(channel, PERFORMANCE_EDIT_BUFFER_ADDRESS) + \
buildRequest(channel, VOICE_EDIT_BUFFFER_PART1) + \
buildRequest(channel, VOICE_EDIT_BUFFFER_PART2) + \
buildRequest(channel, VOICE_EDIT_BUFFFER_PART3) + \
buildRequest(channel, VOICE_EDIT_BUFFFER_PART4)


def isEditBufferDump(data):
Expand Down Expand Up @@ -173,26 +163,6 @@ def createProgramDumpRequest(channel, patch_no):
return buildRequest(DEVICE_ID_DETECTED, VOICE_ADDRESS + [patch_no])
raise Exception("Can only request 128 performances or 128 voices")


#def bankDownloadMethodOverride():
# return "EDITBUFFERS"


# def buildBulkDumpMessage(deviceID, address, data):
# message = [0xf0, 0x43, 0x00 | deviceID, 0x7f, 0x1c, 0, 0, 0x05, address[0], address[1], address[2]] + data
# data_len = len(data) + 4 # Include address and checksum in data size
# size_high = (data_len >> 7) & 0x7f
# size_low = data_len & 0x7f
# message[5] = size_high
# message[6] = size_low
# check_sum = 0
# for m in message[7:]:
# check_sum -= m
# message.append(check_sum & 0x7f)
# message.append(0xf7)
# return message


#def calculateFingerprint(message):
# for i in range(10):
# message[i] = 0
Expand Down Expand Up @@ -235,13 +205,13 @@ def isVoice(message):
def dataBlockFromMessage(message):
if isOwnSysex(message):
data_len = message[4] << 7 | message[5]
if len(message) == data_len + 12:
if len(message) == data_len + 11:
# The Check-sum is the value that results in a value of 0 for the
# lower 7 bits when the Model ID, Start Address, Data and Check sum itself are added.
checksum_block = message[0x04:-2]
checksum_block = message[0x04:-1]
if (sum(checksum_block) & 0x7f) == 0:
# return "Data" block
data_block = message[0x09:-3]
data_block = message[0x09:-2]
assert len(data_block) == data_len
return data_block
raise Exception("Got corrupt data block")
Expand All @@ -250,11 +220,11 @@ def dataBlockFromMessage(message):
def recalculateChecksum(message):
if isOwnSysex(message):
data_len = message[4] << 7 | message[5]
if len(message) == data_len + 12:
if len(message) == data_len + 11:
changed = copy(message)
checksum_block = message[0x04:-3]
checksum_block = message[0x04:-2]
checksum = sum([-x for x in checksum_block]) & 0x7f
changed[-3] = checksum
changed[-2] = checksum
return changed
raise Exception("Got corrupt data block")

Expand All @@ -263,28 +233,27 @@ def buildRequest(device_id, address):
return [0xf0, YAMAHA_ID, 0x20 | (device_id & 0x0f), YAMAHA_FS1R, address[0], address[1], address[2], 0xf7]


#def changeChannelInMessage(new_channel, message):
# return message[0:2] + [(message[2] & 0xf0) | (new_channel & 0x0f)] + message[3:]


def make_test_data():
messages = load_midi("testData/Yamaha_FS1R/Vdfs1r01.mid")
program_data = []
for d in messages:
if isSingleProgramDump(d):
program_data.append(d)
#messages = load_midi("testData/Yamaha_FS1R/Vdfs1r01.mid")
message = knobkraft.stringToSyx("f0 43 00 5e 03 10 11 00 01 43 50 2d 37 30 20 50 47 20 20 20 20 00 00 01 00 75 40 18 00 00 00 01 00 07 68 00 00 00 00 00 00 00 02 00 00 00 00 00 40 01 01 01 01 01 01 00 00 00 01 00 02 00 04 00 08 20 00 20 00 00 00 00 00 19 1a 13 14 13 14 27 28 38 38 50 50 3c 50 40 40 00 0f 00 0a 00 09 00 18 00 2a 00 00 00 00 00 00 00 00 22 04 45 0a 40 00 00 05 00 2e 00 5c 00 0a 00 4a 00 14 00 40 00 32 00 40 00 00 00 00 00 00 00 1a 00 40 00 01 00 40 00 40 00 22 00 40 00 32 00 40 00 13 00 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 40 40 01 40 40 40 15 40 00 00 7f 46 0c 07 00 42 22 07 46 36 07 00 00 04 01 01 00 10 01 00 00 18 40 40 7f 40 40 40 00 7f 7f 0d 08 00 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 02 00 42 3e 32 00 01 7f 00 01 40 40 00 00 00 00 04 01 00 11 7f 01 00 00 18 40 40 7f 40 40 40 00 7f 7f 00 28 00 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 02 32 42 3e 32 00 01 7f 00 01 40 40 00 00 00 00 04 01 00 11 7f 01 00 00 18 40 40 7f 40 40 40 00 7f 7f 00 28 00 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 02 32 42 3e 32 00 01 7f 00 01 40 40 00 00 00 00 04 01 00 11 7f 01 00 00 18 40 40 7f 40 40 40 00 7f 7f 00 28 00 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 02 32 42 3e 32 00 01 7f 00 01 40 40 00 00 00 00 03 f7")
#program_data = []
#for d in messages:
# if isSingleProgramDump(d):
# program_data.append(d)

def edit_buffers(test_data: testing.TestData) -> List[testing.ProgramTestData]:
edit1 = convertToEditBuffer(0x01, program_data[0])
yield testing.ProgramTestData(message=edit1, name="HARDPNO PF ", rename_name="Piano 2 ")
edit2 = convertToEditBuffer(0x01, program_data[255])
yield testing.ProgramTestData(message=edit2, name="Sitar ", target_no=244, rename_name="Piano 2 ")
edit1 = convertToEditBuffer(0x01, message)
#edit1 = convertToEditBuffer(0x01, program_data[0])
yield testing.ProgramTestData(message=edit1, name="CP-70 PG ", rename_name="Piano 2 ")
#edit2 = convertToEditBuffer(0x01, program_data[255])
#yield testing.ProgramTestData(message=edit2, name="Sitar ", target_no=244, rename_name="Piano 2 ")

def program_buffers(test_data: testing.TestData) -> List[testing.ProgramTestData]:
yield testing.ProgramTestData(message=program_data[0], name="HARDPNO PF ", rename_name="Piano 2 ", number=0, friendly_number="Bank3-2")
yield testing.ProgramTestData(message=program_data[127], name="Sitar ", rename_name="Piano 2 ", number=127, friendly_number="Bank3-2")
yield testing.ProgramTestData(message=program_data[128], name="HARDPNO PF", rename_name="Piano 2 ", number=128, target_no=140, friendly_number="Bank3-2")
yield testing.ProgramTestData(message=program_data[255], name="Sitar ", rename_name="Piano 2 ", number=255, target_no=244, friendly_number="Bank3-2")
yield testing.ProgramTestData(message=message, name="CP-70 PG ", rename_name="Piano 2 ", number=1, friendly_number="Bank3-2")
#yield testing.ProgramTestData(message=program_data[0], name="HARDPNO PF ", rename_name="Piano 2 ", number=0, friendly_number="Bank3-2")
#yield testing.ProgramTestData(message=program_data[127], name="Sitar ", rename_name="Piano 2 ", number=127, friendly_number="Bank3-2")
#yield testing.ProgramTestData(message=program_data[128], name="HARDPNO PF", rename_name="Piano 2 ", number=128, target_no=140, friendly_number="Bank3-2")
#yield testing.ProgramTestData(message=program_data[255], name="Sitar ", rename_name="Piano 2 ", number=255, target_no=244, friendly_number="Bank3-2")

return testing.TestData(program_generator=program_buffers, edit_buffer_generator=edit_buffers)

Expand Down
Binary file added adaptations/testData/Yamaha_FS1R/CYBER.MID
Binary file not shown.
16 changes: 16 additions & 0 deletions adaptations/testData/Yamaha_FS1R/README.TXT
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"Cyber" 128 voice & 128 performance for FS1R

Cyber�n�̉��F128performance�̃f�[�^�W�ł��B
128performance�p��128voice����������Ă��܂��B
���}�n�i���j�͂��̃{�C�X�f�[�^�̂��g�p�Ɋ�Â����ڊԐڂ̑��Q�ɑ΂���
�ӔC�𕉂��܂���B�]���܂��āA�g�p���̉��F�f�[�^�̃o�b�N�A�b�v���́A
���q�l�����g�̐ӔC�ł��肢�������܂��B

CYBER.MID
128voice&128performance�̃o���N�_���v�f�[�^�ł��B
�K�؂ȃV�[�P���T�[����FS1R�ɑ��M���܂��ƁA�ŏ���128voice��FS1R��
voice��InitBunk��1����128�Ƀ��[�h����A���̌�128performance��
FS1R��Performance��InitBunk��1����128�Ƀ��[�h����܂��B
���̍ہAFS1R�{�̂�voice�����performance��InitBunk�̃f�[�^�͏㏑��
����܂��̂ŁA���炩���߃o���N�_���v�ɂ���ăo�b�N�A�b�v�����Ȃǂ��A
�����ӂ��������B

0 comments on commit 30951d5

Please sign in to comment.