QEM, or Quantum Editor Map, is an internal format developed for SSQE. While currently unfinished, it will be used to save maps more efficiently and in a standardized location compared to the current TXT/INI system, which is restrictive, unstandardized, and not reasonably scalable.
This format is partly based on SSPMv2, but has been greatly simplified to make reading and writing easier. However, this format does not contain audio data - that will be delegated to an upcoming QEMZ format which relies on QEM files for object data. QEMZ will be a lossless export option for sharing maps in one file, regardless of what game or format you intend to map for, and could be a reasonable option for any future derivatives of Sound Space who don’t want to develop an entirely new format.
All integer values below should be assumed to be SIGNED unless otherwise stated. (This just makes parsing slightly easier and no map would reasonably need an unsigned integer for those values)
Similar to SSPM, QEM uses a lookup table for data types to determine how to read a following set of bytes. Every entry in the format marked with (*) is an example of one of these types, which will always come before a value of that type. These data types are different from what SSPM offers, and are listed below:
Note: a “buffer” is a raw block of bytes, with no inherent information on how it is encoded. It will not be written by SSQE, but should be accounted for in case you want to use and/or modify this format for your own purposes. This can be used to store another file within QEM, although this is not recommended (see QEMZ).
Now we get to the actual byte layout of the format, starting with the header. Note that a block marked with (static) must be present in every QEM file and will only occur once in that file.
After the header is a path block with zero or more string keys mapped to file paths (also strings). These are files the map will need to load correctly, and may be absolute or relative paths. If relative, this path will be relative to the directory the QEM file is in. Always check if a file referenced by this block exists before trying to use it, especially if it’s an absolute path! The path block has the following layout:
Below are all the paths SSQE may write into a QEM file. None of these fields are required, and there may be additional fields you must be able to account for if you intend to process QEM files for your own purposes.
Following the path block will be a metadata block with zero or more metadata fields. Each field is represented by a UTF-8 string identifier and a value, with this layout:
Below are all the fields written by SSQE into metadata, along with their default values if not present. A QEM file cannot be expected to contain all of these fields, and it may contain more fields than are listed here, so all present fields must be handled appropriately. Additionally, a field could have a different type than what is listed here, which is not recommended but must be accounted for.
Next up in the format are object blocks, or sets of what SSPMv2 considers to be “markers” - notes, timing points, etc.
Below are the possible object IDs and type lists recognized by SSQE. These must be accounted for even if you don’t use all of them. If you intend to create a new object type for your own purposes, it’s recommended to use IDs descending from 255 instead of ascending from where these IDs stop.
Keep in mind that an object block may identify more or less types than are listed here. An object will always have as many types as the block defines, but these types aren’t guaranteed to be identical to what your parser can understand. If an object has less types than you expect, you should use the defaults listed next to each type here as a placeholder. If an object has more types than you expect, you can safely discard them after reading them.
A type listed for any object will never be deleted or altered for another purpose, or have its type changed. While you cannot assume the types in an object block are identical to these types in a valid parser implementation, such a case where a type of an SSQE-compatible object conflicts with a type listed here or is not in this list would mean the object block is invalid and can safely be discarded after being read.
Miscellaneous lookup tables: