nephitejnf / muse2pokecrystal Goto Github PK
View Code? Open in Web Editor NEWLicense: GNU Affero General Public License v3.0
License: GNU Affero General Public License v3.0
The with the output of even some of the most simple and repetitive songs being so long, it would be really nice if we implemented some kind of algorithm to reduce bloat.
First of all, output of sequential rests are 1:1 with input. Musescore does not automatically compress rests when they are deleted. This means that we get a lot of output like this for example:
note __, 2
note __, 2
note __, 2
note __, 2
note __, 1
note __, 8
This can be optimized to:
note __, 16
note __, 1
This optimization alone would save several bytes. The length just can't exceed 16.
There is also a much more daunting optimization using callchannel
that could potentially save even more space. My proposed algorithm would happen post-conversion, be toggled by a flag, and likely be in a separate file:
callchannel Music_<SongName>_Branch<index>
. The search array is formatted and appended to the array as well.This one is gonna be while before its properly implemented.
Traceback:
muse2pokecrystal/src/text.py", line 88, in converting_channel
instrument = instrument_list[channel - 1][1]
IndexError: list index out of range
Traceback:
muse2pokecrystal/src/score.py", line 66, in process_to_file_store
bpm = int(channel_part.find(
AttributeError: 'NoneType' object has no attribute 'get'
Parsing non-note commands by outputting the text on a specific note right before it would greatly reduce the amount of work required to find notes that need command changes (ie duty cycles and stereopanning). This also has potential to enable converting xml at pokecrystal build time for even faster deployment.
Currently, Muse2pokecrystal will simply throw an error if any chords exist in the same channel.
There are a couple alternative ways to handle this:
<chord/>
element<chord/>
element
Note: I really dislike the idea of having to parse something spoopy like this. What will likely happen instead is there will still be a placeholder command and a separate chord list (at this point, likely a three dimensional one which is...not ideal) and an index that points to the placeholder.
Pre-process the notes and commands adding placeholders for notes formatted like so:
[[[list_index], [note, octave, length, tie_start_or_end], [note, octave, length, tie_start_or_end], ...], ...]
For example:
[[[4], ['A_', 4, 4, None], ['F#', 5, 8, 'start'], ...], ...]
Apply algorithm 2 for channel 2 only.
Apply algorithm 3 with weights based on what other notes exist in other channels. Prioritize unique notes.
Apply algorithm 1 to channel 4. Don't use too many different seeds.
Simple version of algorithm 4 without the wacky list.
I will try and see if I can implement an algorithm similar to algorithm 5. Ideally, the functionality of 4 should still be the target but it's a lot of work for very little gain.
Before I get around to documenting my new changes, it's worth mentioning that he code is currently pretty messy and a little redundant in some places. Hopefully this will make the code smaller, more readable, and less prone to errors.
process_score
into a classnote_print
says hi)This sometimes can be worked around with the -x
parameter.
However, I have made an edge case. Lucky me.
Flags:
python muse2pokecrystal.py /tmp/He_Approaches.musicxml ../polishedcrystal/audio/music/lookyoungster.asm -c defaultsong.ini -n "Look Youngster" -flCx --noiseless
Configuration (close to default):
[Channel 1]
volume = $77
notetype = $c
intensity = $97
dutycycle = $1
tone =
stereopanning = $0f
vibrato = false
vibrato_delay = $00
vibrato_extent = $00
;custom_commands =
[Channel 2]
notetype = $c
intensity = $a7
dutycycle = $2
tone =
stereopanning = $f0
vibrato = false
vibrato_delay = $00
vibrato_extent = $00
;custom_commands =
[Channel 3]
notetype = $c
intensity = $19
tone =
stereopanning = $ff
vibrato = false
vibrato_delay = $00
vibrato_extent = $00
;custom_commands =
[Channel 4]
notetype = $c
togglenoise = 1
stereopanning = $ff
;custom_commands =
The script output here exhibits issues #22 and #23 as well.
Music_LookYoungster:
musicheader 3, 1, Music_LookYoungster_Ch1
musicheader 1, 2, Music_LookYoungster_Ch2
musicheader 1, 3, Music_LookYoungster_Ch3
Music_LookYoungster_Ch1:
tempo 320
volume $77
notetype $c, $97
dutycycle $1
stereopanning $0f
note __, 8
note __, 8
note __, 8
note __, 8
Music_LookYoungster_Ch1_Loop:
octave -1
note __, 8
note __, 8
note __, 8
note __, 8
octave 3
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
octave 4
note C_, 2
octave 3
note B_, 2
note A#, 2
note B_, 2
jumpchannel Music_LookYoungster_Ch1_Loop
Music_LookYoungster_Ch2:
notetype $c, $a7
dutycycle $2
stereopanning $f0
note __, 8
note __, 8
note __, 8
note __, 8
Music_LookYoungster_Ch2_Loop:
octave -1
octave 3
note B_, 1
octave 3
note A#, 1
octave 3
note B_, 1
octave 3
note A#, 1
octave 4
note D_, 1
note E_, 1
note D_, 1
note E_, 1
octave 3
note B_, 1
octave 3
note A#, 1
octave 3
note B_, 1
octave 3
note A#, 1
octave 4
note D_, 1
note E_, 1
note D_, 1
note E_, 1
octave 3
note B_, 1
octave 3
note A#, 1
octave 3
note B_, 1
octave 3
note A#, 1
octave 4
note D_, 1
note E_, 1
note D_, 1
note E_, 1
octave 3
note G_, 2
note E_, 2
note F#, 2
note E_, 2
octave 4
note B_, 1
octave 4
note A#, 1
octave 4
note B_, 1
octave 4
note A#, 1
octave 5
note D_, 1
note E_, 1
note D_, 1
note E_, 1
octave 4
note B_, 1
octave 4
note A#, 1
octave 4
note B_, 1
octave 4
note A#, 1
octave 5
note D_, 1
note E_, 1
note D_, 1
note E_, 1
octave 4
note B_, 1
octave 4
note A#, 1
octave 4
note B_, 1
octave 4
note A#, 1
octave 5
note D_, 1
note E_, 1
note D_, 1
note E_, 1
octave 4
note G_, 2
note E_, 2
note F#, 2
note E_, 2
jumpchannel Music_LookYoungster_Ch2_Loop
Music_LookYoungster_Ch3:
notetype $c, $19
octave 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
octave 3
note C_, 2
octave 2
note B_, 2
note A#, 2
note B_, 2
Music_LookYoungster_Ch3_Loop:
octave 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
octave 3
note C_, 2
octave 2
note B_, 2
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
note E_, 1
note E_, 1
note G_, 1
note E_, 1
note A#, 2
note B_, 2
octave 3
note C_, 2
octave 2
note B_, 2
note A#, 2
note B_, 2
jumpchannel Music_LookYoungster_Ch3_Loop
Music_LookYoungster_Ch4:
notetype $c
togglenoise 1
note __, 8
note __, 8
note __, 8
note __, 8
Music_LookYoungster_Ch4_Loop:
octave -1
note __, 8
note __, 8
note __, 8
note __, 8
note __, 8
note __, 8
note __, 8
note __, 8
jumpchannel Music_LookYoungster_Ch4_Loop
MusicXML: https://cdn.discordapp.com/attachments/706331639650844672/714368456442511410/He_Approaches.musicxml
If the first note in a channel is a rest, octave -1
is placed above it.
The tempo formula (19200 / bpm
) assumes that a note size of 1
in the note macro is equivalent to a 1/16
note. However, this is note always the case. Let's take a look at a part of the Template.musicxml
in the repo:
<measure number="7" width="57.54">
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
</note>
</measure>
The most important thing to notice here is the <duration>
tag. We can see that the rest spans the entire measure; this is proven both by the fact of it being the only child <note>
and when opening the file in Musescore.
Currently, Muse2pokecrystal just takes the listed bpm, applies it to the set tempo formula and assumes that <duration>4</duration>
is not a whole note.
There is an xml tag called <divisions>
, a child of the <attributes>
tag. By default, this tag holds a value of 1. As I understand it, we can find the smallest note in a score by doing (1/4) / divisions
. A value of 1 indicates that a quarter note is the smallest note in the entire score. A value of 4 means the smallest note is a sixteenth note.
A modified formula that takes this into account though you may want to check my algebra:
(19200 / bpm) * (4 / divisions)
While this slightly increases complexity of the tempo formula (it's getting it's own function in the refactor anyway), properly implementing this and pairing it with #12 will allow more complex songs with a much wider note length range.
Input should at least better approximate to the output. I honestly know very little about the drumkits so this is gonna be a difficult thing to do. Main thing I've noticed is that having a bass drum + snare doesn't sound anything like it should.
After #14, a lot of the docs have become obsolete, using old syntax and suggesting old workarounds. This needs to be updated at some point (probably once development switches from core Muse2pokecrystal to the proposed Musescore plugin).
Also, it's becoming resilient enough to where a tutorial would be beneficial for a lot of people.
This would prevent accidental overwrites.
Lower priority, but we probably want to throw a license on this bad boy at some point (because we can).
My recommendation would be GPLv3 for code (maybe even AGPL...even though muse2pokecrystal isn't designed to run on a server at this point) and CC0 for the MusicXML template.
There's a couple different macros formats that support could be added for.
New Pokecrystal changes a lot of macros. While some improve readability significantly, others greatly depart from the methods currently used to parse (looking at you drum_note
). This will help a lot with future proofing songs.
Most of the macros are identical to new Pokecrystal at first glance. Honestly support for Pokered will likely happen by freak accident.
Prism just changes the music headers:
Music_Song:
channelcount 3
channel 1, Music_Song_Ch1
channel 2, Music_Song_Ch2
channel 3, Music_Song_Ch3
Easy to implement, the only difference between Prism headers and new Pokecrystal is channelcount
macro is referred to as channel_count
in new Pokecrystal.
By automatically setting the low intensity nibble to f
muse2pokecrystal may be able to create an effect where when a note with a length longer than 16 will be split into multiple notes but still hold it's effect of sounding like a single note.
I have not extensively tested this behavior, but I may work it into the refactor.
Musescore allows for plugins that are written in QML. Utilizing the plugin functionality, we could make exports more user friendly and have more precise error checking (especially errors due to chords or tuplets). Additionally (if I am not mistaken this could be impossible or out of scope), custom elements could be added in Musescore for sound engine commands via the plugin interface as well.
Other tools (TriteHexagon's Midi2ASM) now do triplet handling.
This handling is done using the notetype
macro. I was previously under the impression that all channels have to have the same notetype
length when being played, but I'm starting to realize that may not necessarily be the case if the lengths are divisible. This needs a bit more digging, I haven't tested a whole lot yet.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.