# pysspm-rhythia
The official python library dedicated to reading, writing, and modifying the SSPM file format from the video game "Rhythia".
> ***Note: Any version before 0.1.5 does not work in python.***
## SSPM libray information
The main library includes these features:
> 1. Reading .SSPM files
> 2. Modifying SSPM data
> 3. Writing .SSPM files
Extras:
> 1. Difficulty Calculation (W.I.P)
> 2. Note Classification (semi-stable)
## How to install/use
To install the library, run:
```bash
pip install pysspm-rythia
```
to start using the library, create a python script and load up pysspm.
```python
from pysspm_rhythia import SSPMParser
parser = SSPMParser()
# Example of loading a SSPMfile
parser.ReadSSPM("*.sspm")
# Example of turning it into a roblox sound space file
with open("output.txt", "w") as f:
f.write(parser.NOTES2TEXT())
```
> *Functionality does not end there. When reading files, you have full access to all the metadata, and other information stored in the variables.*
**Some common variables you will find are:**
1. `coverBytes` the byteform of the image if cover was found
2. `audioBytes` the byteform of the audio in `.mp3` form if audio was found
3. `Header`: {"Signature": ..., "Version": ...}
4. `Hash`: a SHA-1 hash of the markers (notes) in the map
5. `mapID`: A unique combination using the mappers and map name*
6. `mappers`: a list containing each mapper.
7. `mapName`: The name given to the map.
8. `songName`: The original name of the audio before imported. Usually left as artist name - song name
9. `customValues`: NOT IMPLEMENTED | will return a dictionary of found custom blocks.
10. `isQuantum`: Determins if the level contains ANY float value notes.
11. `Notes`: A list of tuples containing all notes. | Example of what it Notes is: `[(x, y, ms), (x, y, ms), (x, y, ms) . . .]`
```python
from pysspm_rhythia import SSPMParser
parser = SSPMParser()
# Example of loading a SSPMfile
parser.ReadSSPM("*.sspm")
# changing the decal to be a different image
if parser.hasCover[0] == 0: # hasCover is originally in byteform | Can be 0x00 or 0x01
with open("cover.png", 'rb') as f:
parser.coverBytes = f.read() # reading the BYTES of the image
# Finally save the sspm file with the newly configured settings
sspmFileBytes = parser.WriteSSPM()
with open('sspmfile.sspm', "wb") as f:
f.write(sspmFileBytes)
```
Alternativly, you can pass in arguments into WriteSSPM function directly
```py
from pysspm_rhythia import SSPMParser
parser = SSPMParser()
parser.ReadSSPM("*.sspm")
mappers = parser.Mappers.extend('DigitalDemon') # adding another mapper to the mapper list
parser.WriteSSPM('./SSPMFile.sspm', mappers=mappers)
```
## Advanced guide
This shows the more advanced things you can do by giving examples of custom written code.
```python
from pysspm_rhythia import SSPMParser
from random import randint
parser = SSPMParser()
parser.ReadSSPM("*.sspm") # reading the sspm file
sigHeader = parser.Header.get("Signature") # 4 byte header | should always be: b"\x53\x53\x2b\x6d"
ver = parser.Header.get("Version") # stored as 2 or 1
sspmHash = parser.Hash # Storing the hash
if randint(0, 5) == 5:
parser.Notes = parser.Notes.extend((1, 1, (parser.Notes[-1][2]+200))) # adding a center note (1,1), with ms of last note + 200
newSSPM = parser.WriteSSPM(mappers=["DigitalDemon", "Someone else"], mapName="Possibly modified map haha")
# comparing the note hashes
newSSPMHash = parser.Hash
if newSSPMHash == sspmhash:
with open("UnmodifiedMap.sspm", 'wb') as f:
f.write(newSSPM)
else:
raise Warning("Map does not match original hash. Map notes were modified from the original!!!")
```
> Code shows off how hashes are calculated to prevent changes between levels. Could be used for security and integrity of the notes.
*More advanced documentation will be added in the near future...*
## Function Documentation
A in-depth list of things you can do with this library
```py
SSPMParser()
```
> Initializes the sspm library parser
```py
def WriteSSPM(self, filename: str = None, debug: bool = False, **kwargs) -> bytearray | None:
```
> Creates a SSPM v2 file based on variables passed in, or already set.
*If no filepath is passed in, it will return file as bytes* <br>
*Note: current version of pysspm-rhythia requires audio as a parameter for v2 filetype*
**Variables that need to be covered:**
1. `coverImage`: Cover image in bytes form, or None
2. `audioBytes`: Audio in bytes form, or None
3. `Difficulty`: one of Difficulties dictionary options, or 0x00 - 05 OR "N/A", "Easy", "Medium", "Hard", "Logic", "Tasukete"
4. `mapName`: The name of the map. Rhythia guidelines suggests `artist name - song name`
5. `mappers`: a list of strings containing the mapper(s)
6. `notes`: a list of tuples as shown below
<br>
```python
# (x, y, ms)
self.notes = [
(1, 2, 1685), # X, Y, MS
(1.22521, 0.156781, 2000)
]#...
```
***Notes can sometimes be unordered***
<br>
`**kwargs`: pass in any of the variables shown above.
Example usage:
```python
from pysspm_rhythia import SSPMParser
sspm = SSPMParser()
sspm.ReadSSPM("*.sspm") # reads
sspm.Difficulty = 5 # changes difficulty to Tasukete
with open(output_path+".sspm", "wb") as f:
f.write(sspm.WriteSSPM())
```
**ReadSSPM**
```py
def ReadSSPM(self, file: str | BinaryIO, debug: bool = False):
```
> Reads and processes any SSPM file. <br>
`File:` Takes in directory of sspm, or BinaryIO object stored in memory.
`debug:` Useful for getting readable outputs of steps taken.
#### Warning
***SSPM (Sound space plus map file) version 1 is not supported at this time. loading this file may raise errors***
#### Returns
1. `coverBytes` if cover was found
2. `audioBytes` if audio was found
3. `Header`: {"Signature": ..., "Version": ...}
4. `Hash`: a SHA-1 hash of the markers in the map
5. `mapID`: A unique combination using the mappers and map name*
6. `mappers`: a list containing each mapper.
7. `mapName`: The name given to the map.
8. `songName`: The original name of the audio before imported. Usually left as artist name - song name
9. `customValues`: NOT IMPLEMENTED | will return a dictionary of found custom blocks.
10. `isQuantum`: Determins if the level contains ANY float value notes.
11. `Notes`: A list of tuples containing all notes.
Example of what it Notes is: `[(x, y, ms), (x, y, ms), (x, y, ms) . . .]`
> ***Returns itself***
## Roadmap (May get completed)
TODO: (In order of priority)
- Add typing support for library ✔️
- add proper documentation on github
- add proper documentation in code ✔️
- add loading of sspmV2 ✔️
- add support for creating sspmV2 ✔️
- clean up unused variables from @self ✔️
- add support for sspmv1 loading ✔️ (Thank you fogsaturate)
- support multiple versions of sspm
- add custom block support in loading
- Drop numpy dependency
- Implement Extras difficulty calc
- Implement simple note ordering function
- Support for Pheonix Filetype (When I get my hands on the data structure)
Made with 💖 by DigitalDemon (David Jed)
> Documentation last updated: `2024-12-12` | `V0.2.2`
Raw data
{
"_id": null,
"home_page": "https://github.com/David-Jed/pysspm",
"name": "pysspm-rhythia",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "Rhythia, Sound space, SSPM, Rhythm game, pysspm-rhythia, pysspm",
"author": "David Jedlovsky",
"author_email": "Dev.DavidJed@gmail.com",
"download_url": null,
"platform": null,
"description": "# pysspm-rhythia\r\n\r\nThe official python library dedicated to reading, writing, and modifying the SSPM file format from the video game \"Rhythia\".\r\n\r\n> ***Note: Any version before 0.1.5 does not work in python.***\r\n\r\n## SSPM libray information\r\n\r\nThe main library includes these features:\r\n\r\n> 1. Reading .SSPM files\r\n> 2. Modifying SSPM data\r\n> 3. Writing .SSPM files\r\n\r\nExtras:\r\n\r\n> 1. Difficulty Calculation (W.I.P)\r\n> 2. Note Classification (semi-stable)\r\n\r\n## How to install/use\r\n\r\nTo install the library, run:\r\n\r\n```bash\r\npip install pysspm-rythia\r\n```\r\n\r\nto start using the library, create a python script and load up pysspm.\r\n\r\n```python\r\nfrom pysspm_rhythia import SSPMParser\r\n\r\n\r\nparser = SSPMParser()\r\n\r\n# Example of loading a SSPMfile\r\nparser.ReadSSPM(\"*.sspm\")\r\n\r\n# Example of turning it into a roblox sound space file\r\n\r\nwith open(\"output.txt\", \"w\") as f:\r\n f.write(parser.NOTES2TEXT())\r\n\r\n```\r\n\r\n> *Functionality does not end there. When reading files, you have full access to all the metadata, and other information stored in the variables.*\r\n\r\n**Some common variables you will find are:**\r\n\r\n1. `coverBytes` the byteform of the image if cover was found\r\n2. `audioBytes` the byteform of the audio in `.mp3` form if audio was found\r\n3. `Header`: {\"Signature\": ..., \"Version\": ...}\r\n4. `Hash`: a SHA-1 hash of the markers (notes) in the map\r\n5. `mapID`: A unique combination using the mappers and map name*\r\n6. `mappers`: a list containing each mapper.\r\n7. `mapName`: The name given to the map.\r\n8. `songName`: The original name of the audio before imported. Usually left as artist name - song name\r\n9. `customValues`: NOT IMPLEMENTED | will return a dictionary of found custom blocks.\r\n10. `isQuantum`: Determins if the level contains ANY float value notes.\r\n11. `Notes`: A list of tuples containing all notes. | Example of what it Notes is: `[(x, y, ms), (x, y, ms), (x, y, ms) . . .]`\r\n\r\n```python\r\nfrom pysspm_rhythia import SSPMParser\r\n\r\n\r\nparser = SSPMParser()\r\n\r\n# Example of loading a SSPMfile\r\nparser.ReadSSPM(\"*.sspm\")\r\n\r\n# changing the decal to be a different image\r\nif parser.hasCover[0] == 0: # hasCover is originally in byteform | Can be 0x00 or 0x01\r\n with open(\"cover.png\", 'rb') as f:\r\n parser.coverBytes = f.read() # reading the BYTES of the image\r\n\r\n# Finally save the sspm file with the newly configured settings\r\nsspmFileBytes = parser.WriteSSPM()\r\n\r\nwith open('sspmfile.sspm', \"wb\") as f:\r\n f.write(sspmFileBytes)\r\n\r\n```\r\n\r\nAlternativly, you can pass in arguments into WriteSSPM function directly\r\n\r\n```py\r\nfrom pysspm_rhythia import SSPMParser\r\n\r\nparser = SSPMParser()\r\nparser.ReadSSPM(\"*.sspm\")\r\n\r\nmappers = parser.Mappers.extend('DigitalDemon') # adding another mapper to the mapper list\r\nparser.WriteSSPM('./SSPMFile.sspm', mappers=mappers)\r\n```\r\n\r\n## Advanced guide\r\n\r\nThis shows the more advanced things you can do by giving examples of custom written code.\r\n\r\n```python\r\nfrom pysspm_rhythia import SSPMParser\r\nfrom random import randint\r\n\r\nparser = SSPMParser()\r\n\r\nparser.ReadSSPM(\"*.sspm\") # reading the sspm file\r\n\r\nsigHeader = parser.Header.get(\"Signature\") # 4 byte header | should always be: b\"\\x53\\x53\\x2b\\x6d\"\r\nver = parser.Header.get(\"Version\") # stored as 2 or 1\r\nsspmHash = parser.Hash # Storing the hash\r\n\r\nif randint(0, 5) == 5:\r\n parser.Notes = parser.Notes.extend((1, 1, (parser.Notes[-1][2]+200))) # adding a center note (1,1), with ms of last note + 200\r\n\r\nnewSSPM = parser.WriteSSPM(mappers=[\"DigitalDemon\", \"Someone else\"], mapName=\"Possibly modified map haha\")\r\n\r\n# comparing the note hashes\r\nnewSSPMHash = parser.Hash\r\nif newSSPMHash == sspmhash:\r\n with open(\"UnmodifiedMap.sspm\", 'wb') as f:\r\n f.write(newSSPM)\r\nelse:\r\n raise Warning(\"Map does not match original hash. Map notes were modified from the original!!!\")\r\n\r\n\r\n```\r\n\r\n> Code shows off how hashes are calculated to prevent changes between levels. Could be used for security and integrity of the notes.\r\n\r\n*More advanced documentation will be added in the near future...*\r\n\r\n## Function Documentation\r\n\r\nA in-depth list of things you can do with this library\r\n\r\n```py\r\nSSPMParser()\r\n```\r\n\r\n> Initializes the sspm library parser\r\n\r\n```py\r\ndef WriteSSPM(self, filename: str = None, debug: bool = False, **kwargs) -> bytearray | None:\r\n```\r\n\r\n> Creates a SSPM v2 file based on variables passed in, or already set.\r\n\r\n*If no filepath is passed in, it will return file as bytes* <br>\r\n*Note: current version of pysspm-rhythia requires audio as a parameter for v2 filetype*\r\n\r\n**Variables that need to be covered:**\r\n\r\n1. `coverImage`: Cover image in bytes form, or None\r\n2. `audioBytes`: Audio in bytes form, or None\r\n3. `Difficulty`: one of Difficulties dictionary options, or 0x00 - 05 OR \"N/A\", \"Easy\", \"Medium\", \"Hard\", \"Logic\", \"Tasukete\"\r\n4. `mapName`: The name of the map. Rhythia guidelines suggests `artist name - song name`\r\n5. `mappers`: a list of strings containing the mapper(s)\r\n6. `notes`: a list of tuples as shown below\r\n\r\n<br>\r\n\r\n```python\r\n# (x, y, ms)\r\nself.notes = [\r\n (1, 2, 1685), # X, Y, MS\r\n (1.22521, 0.156781, 2000)\r\n]#...\r\n```\r\n\r\n***Notes can sometimes be unordered***\r\n\r\n<br>\r\n\r\n`**kwargs`: pass in any of the variables shown above.\r\n\r\nExample usage:\r\n\r\n```python\r\n from pysspm_rhythia import SSPMParser\r\n \r\n sspm = SSPMParser()\r\n sspm.ReadSSPM(\"*.sspm\") # reads\r\n sspm.Difficulty = 5 # changes difficulty to Tasukete\r\n \r\n with open(output_path+\".sspm\", \"wb\") as f:\r\n f.write(sspm.WriteSSPM())\r\n```\r\n\r\n**ReadSSPM**\r\n\r\n```py\r\ndef ReadSSPM(self, file: str | BinaryIO, debug: bool = False):\r\n```\r\n\r\n> Reads and processes any SSPM file. <br>\r\n\r\n`File:` Takes in directory of sspm, or BinaryIO object stored in memory.\r\n`debug:` Useful for getting readable outputs of steps taken.\r\n\r\n#### Warning\r\n\r\n***SSPM (Sound space plus map file) version 1 is not supported at this time. loading this file may raise errors***\r\n\r\n#### Returns\r\n\r\n1. `coverBytes` if cover was found\r\n2. `audioBytes` if audio was found\r\n3. `Header`: {\"Signature\": ..., \"Version\": ...}\r\n4. `Hash`: a SHA-1 hash of the markers in the map\r\n5. `mapID`: A unique combination using the mappers and map name*\r\n6. `mappers`: a list containing each mapper.\r\n7. `mapName`: The name given to the map.\r\n8. `songName`: The original name of the audio before imported. Usually left as artist name - song name\r\n9. `customValues`: NOT IMPLEMENTED | will return a dictionary of found custom blocks.\r\n10. `isQuantum`: Determins if the level contains ANY float value notes.\r\n11. `Notes`: A list of tuples containing all notes.\r\n\r\nExample of what it Notes is: `[(x, y, ms), (x, y, ms), (x, y, ms) . . .]`\r\n\r\n> ***Returns itself***\r\n\r\n## Roadmap (May get completed)\r\n\r\nTODO: (In order of priority)\r\n\r\n- Add typing support for library \u2714\ufe0f\r\n- add proper documentation on github\r\n- add proper documentation in code \u2714\ufe0f\r\n- add loading of sspmV2 \u2714\ufe0f\r\n- add support for creating sspmV2 \u2714\ufe0f\r\n- clean up unused variables from @self \u2714\ufe0f\r\n- add support for sspmv1 loading \u2714\ufe0f (Thank you fogsaturate)\r\n- support multiple versions of sspm\r\n- add custom block support in loading\r\n- Drop numpy dependency\r\n- Implement Extras difficulty calc\r\n- Implement simple note ordering function\r\n- Support for Pheonix Filetype (When I get my hands on the data structure)\r\n\r\nMade with \ud83d\udc96 by DigitalDemon (David Jed)\r\n\r\n> Documentation last updated: `2024-12-12` | `V0.2.2`\r\n",
"bugtrack_url": null,
"license": null,
"summary": "A Python library dedicated to reading, writing, and modifying the Rhythia SSPM file format",
"version": "0.2.2",
"project_urls": {
"Homepage": "https://github.com/David-Jed/pysspm"
},
"split_keywords": [
"rhythia",
" sound space",
" sspm",
" rhythm game",
" pysspm-rhythia",
" pysspm"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "336ed867d0f914009d0d84510e3041042e1edeeb41f7ec7af0f5adfa0a0a3858",
"md5": "b5335eb0b28b2cb8495474604991b13b",
"sha256": "551d510450378a7f6a1fe05cb44ee9e76c267370ec231cca6b7f131d3e373855"
},
"downloads": -1,
"filename": "pysspm_rhythia-0.2.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b5335eb0b28b2cb8495474604991b13b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 17681,
"upload_time": "2024-12-12T07:22:36",
"upload_time_iso_8601": "2024-12-12T07:22:36.538937Z",
"url": "https://files.pythonhosted.org/packages/33/6e/d867d0f914009d0d84510e3041042e1edeeb41f7ec7af0f5adfa0a0a3858/pysspm_rhythia-0.2.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-12 07:22:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "David-Jed",
"github_project": "pysspm",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "pysspm-rhythia"
}