About the optimized Renoise XSD Model

Why an optimized model?

As of NRenoiseTools 2.5, this part is no longer use as Renoise is releasing a builtin optimized xsd that performs correct xsd complextype model. Although, generic "Track" inheritance is generated in NRenoiseTools as well as a bug fix in the Renoise xsd in order to be able to save correctly Renoise xrns

If you have already used the original XSD files from Renoise, you may have noticed that all types are inlined : there is no reusable complextype in the Schema, resulting in duplication of lots of complextype that have the same structure. Check for example MidiMapping and you will see that this structure is duplicated 573 times (!) in the RenoiseSong.xsd file. With such xsd, it's almost impossible to generate a coherent mapping for a programming language (C#, Java...etc.), because types are duplicated.
Moreover, inheritance is not used and the number of generated class is huge (10 times the number of classes used in NRenoiseTools), making this more difficult to developp a robust application.

Using complextype name

The key concept of an optimized version of XSD Renoise file is to use complextype name and reference them in xs:element instead of using an inline declaration.

For example, instead of having several MidiMapping defined in the RenoiseSong.xsd :
<xs:element ...>
     <!-- First declaration -->
    <xs:element name="MidiMapping" minOccurs="0" maxOccurs="unbounded">
    <xs:complexType>
    <xs:all>
    <xs:element name="Channel" type="xs:int" default="-1" minOccurs="0"/>
    <xs:element name="CCNumber" type="xs:int" default="-1" minOccurs="0"/>
    <xs:element name="Mode" type="xs:int" default="0" minOccurs="0"/>
    <xs:element name="Min" type="xs:float" default="0.0" minOccurs="0"/>
    <xs:element name="Max" type="xs:float" default="1.0" minOccurs="0"/>
    <xs:element name="Inverse" type="xs:boolean" default="false" minOccurs="0"/>
    </xs:all>
    </xs:complexType>
    </xs:element>
</xs:element>
...
<xs:element ...>
     <!-- 2nd declaration (There are 571 declarations like this in the RenoiseModel.xsd ) -->
    <xs:element name="MidiMapping" minOccurs="0" maxOccurs="unbounded">
    <xs:complexType>
    <xs:all>
    <xs:element name="Channel" type="xs:int" default="-1" minOccurs="0"/>
    <xs:element name="CCNumber" type="xs:int" default="-1" minOccurs="0"/>
    <xs:element name="Mode" type="xs:int" default="0" minOccurs="0"/>
    <xs:element name="Min" type="xs:float" default="0.0" minOccurs="0"/>
    <xs:element name="Max" type="xs:float" default="1.0" minOccurs="0"/>
    <xs:element name="Inverse" type="xs:boolean" default="false" minOccurs="0"/>
    </xs:all>
    </xs:complexType>
    </xs:element>
</xs:element>

We create a new complextype called "MidiMapping", and every xs:element that are using a MidiMapping will be mapped to this complextype (with the type attribute of xs:element) :
  <!-- Only one declaration -->
  <xs:complexType name="MidiMapping">
    <xs:all>
      <xs:element minOccurs="0" default="-1" name="Channel" type="xs:int" />
      <xs:element minOccurs="0" default="-1" name="CCNumber" type="xs:int" />
      <xs:element minOccurs="0" default="0" name="Mode" type="xs:int" />
      <xs:element minOccurs="0" default="0.0" name="Min" type="xs:float" />
      <xs:element minOccurs="0" default="1.0" name="Max" type="xs:float" />
      <xs:element minOccurs="0" default="false" name="Inverse" type="xs:boolean" />
    </xs:all>
  </xs:complexType>
....
  <!-- Reference of the declaration using typed xs:element with type attribute -->
 <xs:element minOccurs="0" maxOccurs="unbounded" name="MidiMapping" type="MidiMapping" />
....
  <!-- Reference of the declaration using typed xs:element with type attribute -->
 <xs:element minOccurs="0" maxOccurs="unbounded" name="MidiMapping" type="MidiMapping" />
....
  <!-- Reference of the declaration using typed xs:element with type attribute -->
 <xs:element minOccurs="0" maxOccurs="unbounded" name="MidiMapping" type="MidiMapping" />

Using this technique in NRenoiseTools reduces the size of the final XSD to 300Ko instead of 3Mo!
Therefore, when using this optimized xsd to map to a language (C#, Java), the number of generated class is much more reasonnable.

XsdRenoiseParser and inheritance

NRenoiseTools uses an optimized version of the following 1.9.1 xsd files : RenoiseSong10.xsd, RenoiseInstrument6.xsd and RenoiseDeviceChain6.xsd.

You can check the resulting XSD file used by NRenoiseTools in the NRenoiseTools-Schemas.zip. This schema was generated automatically from XsdRenoiseParser, an application specially developped to parse, merge and apply some transformations to the original XSD from Renoise, while keeping full compatibility.

The resulting XSD (RenoiseModel191.xsd) is much more usable when converting the schema to classes in a language. Thus, this schema can be reused in other projects like Java.

XSDRenoiseParser manage severals transformations to produce an optimized xsd:
  • Merge the xsd files (RenoiseSong, RenoiseInstrument, RenoiseDeviceChain) in order to share the same ComplexTypes. It means that the RenoiseInstrument will use the elements already declared in the RenoiseSong, same for the RenoiseDeviceChain.
  • Reuse all complextype that are similar (same complextype with same default values, elements composition) and extract them in order to reuse them in the XSD.
  • Change some names that will not map correctly.
  • Add some inheritances :
    • PatternTrack, PatternMasterTrack and PatternSendTrack inherits from a new type Track, in order to manipulate them the same way.
    • Make RenoiseSong inherits from a new type Song (to make it similar to RenoiseInstrument and Instrument)
    • Make RenoiseInstrument inherits from Instrument already declared in the RenoiseSong structure

Last edited Sep 12, 2010 at 9:51 PM by alexandre_mutel, version 3

Comments

No comments yet.