import TOE

template = '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE MIDINameDocument PUBLIC "-//MIDI Manufacturers Association//DTD MIDINameDocument 1.0//EN" "http://www.midi.org/dtds/MIDINameDocument10.dtd">
<MIDINameDocument>
  <Author>TOE Morpheus.py</Author>
  <MasterDeviceNames>
    <Manufacturer>E-mu</Manufacturer>
    <Model>Morpheus</Model>
    <CustomDeviceMode Name="Mode 1">
      <ChannelNameSetAssignments>
        <ChannelNameSetAssign Channel="1" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="2" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="3" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="4" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="5" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="6" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="7" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="8" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="9" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="10" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="11" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="12" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="13" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="14" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="15" NameSet="Name Set 1"/>
        <ChannelNameSetAssign Channel="16" NameSet="Name Set 1"/>
      </ChannelNameSetAssignments>
    </CustomDeviceMode>
    <ChannelNameSet Name="Name Set 1">
      <AvailableForChannels>
        <AvailableChannel Channel="1" Available="true"/>
        <AvailableChannel Channel="2" Available="true"/>
        <AvailableChannel Channel="3" Available="true"/>
        <AvailableChannel Channel="4" Available="true"/>
        <AvailableChannel Channel="5" Available="true"/>
        <AvailableChannel Channel="6" Available="true"/>
        <AvailableChannel Channel="7" Available="true"/>
        <AvailableChannel Channel="8" Available="true"/>
        <AvailableChannel Channel="9" Available="true"/>
        <AvailableChannel Channel="10" Available="true"/>
        <AvailableChannel Channel="11" Available="true"/>
        <AvailableChannel Channel="12" Available="true"/>
        <AvailableChannel Channel="13" Available="true"/>
        <AvailableChannel Channel="14" Available="true"/>
        <AvailableChannel Channel="15" Available="true"/>
        <AvailableChannel Channel="16" Available="true"/>
      </AvailableForChannels>
      <PatchBank Name="RAM Presets" ROM="false">
        <MIDICommands>
          <ControlChange Control="0" Value="0"/>
          <ControlChange Control="32" Value="0"/>
        </MIDICommands>
        <UsesPatchNameList Name="RAM Presets"/>
      </PatchBank>
      <PatchBank Name="ROM Presets" ROM="true">
        <MIDICommands>
          <ControlChange Control="0" Value="0"/>
          <ControlChange Control="32" Value="1"/>
        </MIDICommands>
        <UsesPatchNameList Name="ROM Presets"/>
      </PatchBank>
      <PatchBank Name="HyperPresets" ROM="false">
        <MIDICommands>
          <ControlChange Control="0" Value="0"/>
          <ControlChange Control="32" Value="2"/>
        </MIDICommands>
        <UsesPatchNameList Name="HyperPresets"/>
      </PatchBank>
    </ChannelNameSet>
%s  </MasterDeviceNames>
</MIDINameDocument>
'''

# Send Sysex data requestSysex to device and receive and return
# lengthExpected bytes of bulk dump data.
def GetSysexBulkDump(device, requestSysex, lengthExpected):
    device.Send(requestSysex)
    while (device.NumOfBytesReceived() < lengthExpected):
        pass
    return device.Receive()

# From the bulk dump data sysexData, extract and return a list of
# patch names.  Each name is of length nameLen.  The first name starts
# at byte offest startOffset.  The next names starts at 'startOffset +
# interval', 'startOffset + 2 * interval' and so on.
def ExtractNameList(sysexData, numNames, startOffset, interval, nameLen):
    nameList = []
    for i in range(numNames):
        nameList.append(sysexData[startOffset + i * interval : startOffset + i * interval + nameLen])
    return nameList

# Convert a list of patch names into the <PatchNameList> XML element
# to be inserted into the MIDI name document representation.
def PatchNameList(nameListName, nameList):
    patchNameList = '    <PatchNameList Name="%s">\n' % nameListName
    i = 0
    for name in nameList:
        patchNameList += '      <Patch Number="P-%u" Name="%s" ProgramChange="%u" />\n' % (i, name, i)
        i += 1
    patchNameList += '    </PatchNameList>\n'
    return patchNameList

TOE.Initialize()

d = TOE.Sysex('Morpheus')

ramRomSysex = GetSysexBulkDump(d, '\xf0\x18\x0c\x00\x12\xf7', 3336)
ramPresets = ExtractNameList(ramRomSysex, 128, 7, 13, 12)
romPresets = ExtractNameList(ramRomSysex, 128, 7 + 13 * 128, 13, 12)

hyperSysex = GetSysexBulkDump(d, '\xf0\x18\x0c\x00\x50\xf7', 1672)
hyperPresets = ExtractNameList(hyperSysex, 128, 7, 13, 12)

print template % (PatchNameList("RAM Presets", ramPresets) + \
                  PatchNameList("ROM Presets", romPresets) + \
                  PatchNameList("HyperPresets", hyperPresets))

TOE.Terminate()