Skip to content

Commit

Permalink
Merge tag '0.3.3' into develop
Browse files Browse the repository at this point in the history
0.3.3
  • Loading branch information
roszcz committed Sep 22, 2024
2 parents f76f112 + c5fe1ea commit 9ad9e7d
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [0.3.2] - 2024-09-22
### Added
- separate dataframe build method for MidiFile

## [0.3.2] - 2024-08-28
### Added
- possible to write midi to a buffer
Expand Down
2 changes: 1 addition & 1 deletion fortepyan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from fortepyan.midi.structures import MidiFile, MidiPiece

__all__ = ["view", "MidiFile", "MidiPiece"]
__version__ = "0.3.2"
__version__ = "0.3.3"

# Pretty MIDI will throw an unwanted error for large files with high PPQ
# This is a workaround
Expand Down
9 changes: 5 additions & 4 deletions fortepyan/midi/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,12 @@ def key_number_to_key_name(key_number):
Convert a key number to a key string.
Parameters:
key_number (int): Uses pitch classes to represent major and minor keys. For minor keys, adds a 12 offset. For example, C major is 0 and C minor is 12.
key_number (int): Uses pitch classes to represent major and minor keys.
For minor keys, adds a 12 offset. For example, C major is 0 and C minor is 12.
Returns:
key_name (str): Key name in the format ``'(root) (mode)'``, e.g. ``'Gb minor'``. Gives preference for keys with flats, with the exception of F#, G# and C# minor.
key_name (str): Key name in the format ``'(root) (mode)'``, e.g. ``'Gb minor'``.
Gives preference for keys with flats, with the exception of F#, G# and C# minor.
"""

if not isinstance(key_number, int):
Expand Down Expand Up @@ -234,9 +236,8 @@ def key_name_to_key_number(key_string):
" ?"
# Next, look for any of the mode strings
"(?P<mode>(?:(?:"
+
# Next, look for any of the major or minor mode strings
")|(?:".join(major_strs + minor_strs)
+ ")|(?:".join(major_strs + minor_strs)
+ "))?)$"
)
# Match provided key string
Expand Down
40 changes: 33 additions & 7 deletions fortepyan/midi/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,12 @@ def __add__(self, other: "MidiPiece") -> "MidiPiece":
out = MidiPiece(df=df)

# Show warning as the piece might not be musically valid.
showwarning("The resulting piece may not be musically valid.", UserWarning, "fortepyan", lineno=1)
showwarning(
message="The resulting piece may not be musically valid.",
category=UserWarning,
filename="fortepyan/midi/structures.py",
lineno=280,
)

return out

Expand Down Expand Up @@ -493,13 +498,16 @@ def _process_midi_file(self):
# Check that there are tempo, key and time change events
# only on track 0
if any(e.type in ("set_tempo", "key_signature", "time_signature") for track in midi_data.tracks[1:] for e in track):
showwarning(
message = (
"Tempo, Key or Time signature change events found on "
"non-zero tracks. This is not a valid type 0 or type 1 "
"MIDI file. Tempo, Key or Time Signature may be wrong.",
RuntimeWarning,
"fortepyan",
lineno=1,
"MIDI file. Tempo, Key or Time Signature may be wrong."
)
showwarning(
message=message,
category=RuntimeWarning,
filename="fortepyan/midi/structures.py",
lineno=469,
)

# Populate the list of instruments
Expand All @@ -517,6 +525,9 @@ def _process_midi_file(self):
ids = self.control_frame.number == 64
self.sustain = self.control_frame[ids].reset_index(drop=True)

self._build_dataframes()

def _build_dataframes(self):
# Extract notes
raw_df = pd.DataFrame(
{
Expand Down Expand Up @@ -967,13 +978,16 @@ def event_compare(event1, event2):
# to determine their ordering.
if event1.time == event2.time and event1.type in secondary_sort and event2.type in secondary_sort:
return secondary_sort[event1.type](event1) - secondary_sort[event2.type](event2)

# Otherwise, just return the difference of their ticks.
return event1.time - event2.time

# Initialize output MIDI object
mid = mido.MidiFile(ticks_per_beat=self.resolution)

# Create track 0 with timing information
timing_track = mido.MidiTrack()

# Add a default time signature only if there is not one at time 0.
add_ts = True
if self.time_signature_changes:
Expand All @@ -992,11 +1006,15 @@ def event_compare(event1, event2):
tempo=int(6e7 / (60.0 / (tick_scale * self.resolution))),
)
)

# Add in each time signature
for ts in self.time_signature_changes:
timing_track.append(
mido.MetaMessage(
"time_signature", time=self.time_to_tick(ts.time), numerator=ts.numerator, denominator=ts.denominator
"time_signature",
time=self.time_to_tick(ts.time),
numerator=ts.numerator,
denominator=ts.denominator,
)
)
# Add in each key signature
Expand Down Expand Up @@ -1035,17 +1053,22 @@ def event_compare(event1, event2):
# Add in all lyrics events
for lyr in self.lyrics:
timing_track.append(mido.MetaMessage("lyrics", time=self.time_to_tick(lyr.time), text=lyr.text))

# Add text events
for tex in self.text_events:
timing_track.append(mido.MetaMessage("text", time=self.time_to_tick(tex.time), text=tex.text))

# Sort the (absolute-tick-timed) events.
timing_track.sort(key=functools.cmp_to_key(event_compare))

# Add in an end of track event
timing_track.append(mido.MetaMessage("end_of_track", time=timing_track[-1].time + 1))
mid.tracks.append(timing_track)

# Create a list of possible channels to assign - this seems to matter
# for some synths.
channels = list(range(16))

# Don't assign the drum channel by mistake!
channels.remove(9)
for n, instrument in enumerate(self.instruments):
Expand Down Expand Up @@ -1104,10 +1127,13 @@ def event_compare(event1, event2):
):
track[n] = event2
track[n + 1] = event1

# Finally, add in an end of track event
track.append(mido.MetaMessage("end_of_track", time=track[-1].time + 1))

# Add to the list of output tracks
mid.tracks.append(track)

# Turn ticks to relative time from absolute
for track in mid.tracks:
tick = 0
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "fortepyan"
version = "0.3.2"
version = "0.3.3"
description = "Process MIDI piano with (almost) no pain"
readme = "README.md"
authors = [{ name = "Piano For AI", email = "[email protected]" }]
Expand Down Expand Up @@ -45,7 +45,7 @@ packages = [
]

[tool.bumpver]
current_version = "0.3.2"
current_version = "0.3.3"
version_pattern = "MAJOR.MINOR.PATCH"
commit_message = "bump version {old_version} -> {new_version}"
commit = false
Expand Down

0 comments on commit 9ad9e7d

Please sign in to comment.