Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python 3 and jazz updates #63

Closed
wants to merge 3 commits into from
Closed

Python 3 and jazz updates #63

wants to merge 3 commits into from

Conversation

samg7b5
Copy link
Contributor

@samg7b5 samg7b5 commented May 8, 2020

Added various Python 3 support, small midi fixes, jazz features (chords, scales etc.). Please refer to commit notes for more details on each category.

Please note: some edits were made to move away from mingus' diatonic/classical numeral parsing and towards jazz notation (e.g. I7 was Imaj7, should now give Idom7). Would suggest reviewing and removing this code if not desirable for the package. See core/progressions.py and progressions.to_chords().

Apologies that this is not a well-structured pull request as I was originally editing the package for my own local usage.

samg7b5 added 2 commits June 16, 2019 13:37
Update import and raise syntax for Python 3.x (now supports mingus.core.*)
Changed conventions to Python 3 e.g. imports, line breaks, printing, xrange
Fixed some type issues
Added some jazz chord support (chord types, lower case as minor convention (moving away from mingus' existing diatonic/classical approach))
Added jazz scales: minor modes, altered scales, and some extras
Updated midi support to work with binary strings (Python 3) and fixed some event handling (note-off)
@samg7b5 samg7b5 marked this pull request as ready for review May 8, 2020 10:01
@samg7b5
Copy link
Contributor Author

samg7b5 commented May 8, 2020

Happy to discuss edits/conflicts, let me know.

@edudobay
Copy link
Collaborator

edudobay commented May 9, 2020

Hi @samg7b5! Thanks a lot for the contribution. An older proposal for Python 3 support has already been merged. Of course if you have any specific feedback do feel free to bring it.

About the jazz updates, I'll be happy to review them, BUT that's nearly impossible in this PR in its current form. There's a lot of conflicts, and an overwhelmingly large set of changes due to this Python 3 rework.

So I'd suggest that you isolate the functional changes that you wanted to introduce, removing the Python 3 updates that are already present in the master branch of this repo. Then I hope you should be able to cherry-pick or rebase against master without conflicts, and then update this PR (or open a new one) with only those changes. That has to be done anyway in order to merge this.

Please ping me back if you need some help or advice at doing this.

@samg7b5
Copy link
Contributor Author

samg7b5 commented May 9, 2020

Hey @edudobay , I took a look at these conflicts and removed most of my edits to respect the existing Py3 edits that had already been implemented. There are just a few notable edits remaining from my side (plus the obvious additional jazz functionality in chords/scales):

To midi_file_in, added (to get the floor function)
import numpy as np
and then around line 120, a commented snippet:
n = Note(notes.int_to_note(event['param1'] % 12), np.floor(event['param1'] / 12)) # this was event['param1']/12 - 1 but that gives skewed, incorrect octaves

This was because my MIDI files were being read in and having their octave multiplied by a non-integer factor, which effectively vertically stretched the pitches.

I also added (around line 360)
# "It is common for a note on with 0 velocity to be interpreted as NOTE OFF." https://stackoverflow.com/questions/48687756/midi-note-on-event-without-off-event # this should resolve Lilypad midi files which don't seem to use ec 8 to signify NOTE OFF

if param2 == 0: event_type = 8

This was to fix reading in MIDI created by Lilypond (Lilypad is a typo in the above) which in mingus was interpreted with notes that didn't end (i.e. kept playing) after their duration was passed.

PS. I removed my jazz numeral functionality, so 'I7' should be interpreted as 'IMaj7' as before, and lowercase won't imply a minor chord.

@edudobay
Copy link
Collaborator

edudobay commented May 9, 2020

That's quite an impressive amount of work! In fact you have uncovered some bugs in MIDI-related code, and unfortunately that part is lacking automated tests. I'll shortly try to give specific feedback on your changes but I have to warn you that making a lot of unrelated changes in one single commit makes a PR much harder to review — and also can make maintenance harder in the future.

The way I see this as a community-faced project, we should aim to make changes as transparent as possible and be responsible about those changes. The best way to handle this PR as I see it is to split it into smaller, semantic commits, with one type of change for each.

My top priority is reviewing your fixes to broken behavior, so I'll start by the MIDI-related stuff and other changes to Note.

Copy link
Collaborator

@edudobay edudobay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said, this first review is about fixing current behavior. After we address and merge those issues, we can proceed to new functionality.

self.bar = []
self.current_beat = 0.0
return self.bar

def set_chord_notes(self, chords):
self.chords = chords
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unclear to me why you added chords and temporal_notes to this class. It seems they are not used elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure that I added this, maybe from a historic version of mingus? Guess it's fine to ignore

@@ -272,7 +274,7 @@ def __int__(self):
res += 1
elif n == "b":
res -= 1
return res
return int(res)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear why this int should be needed. Did you ever get a non-int here? If so, maybe there's another bug to uncover.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry also not sure why I added this - I'm guessing it was from a type bug but I'm afraid I can't recall


# added as was getting erros from play_Bar.set_key
if type(other) == str:
other = Note(other)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to me we should not compare Notes and strings by implicit conversion, but instead raise a TypeError to uncover bugs.

'7b5': ' dominant flat five',
'hendrix': ' hendrix chord',
'7b12': ' hendrix chord',
'5': ' perfect fifth',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should run make format prior to your commits to avoid accidentally committing undesired coding style changes.

@@ -684,7 +726,7 @@ def I7(key):


def ii(key):
return supertonic(key)
return supertonic(key) # note that progressions.to_chords['ii'] will come and pick this up (major 2nd chord due to mingus' classical approach). Instead, that fn has been re-written to try to except lower-casing and add a minor suffix
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment up-to-date? Seems this is about the changes you didn't keep.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, I think we should disregard this now as I removed the notion of jazz chord notation (originally I was using lowercase to imply minor but removed that functionality)

n.channel = event["channel"]
n.velocity = event["param2"]
n = Note(notes.int_to_note(event['param1'] % 12),
np.floor(event['param1'] / 12)) # this was event['param1']/12 - 1 but that gives skewed, incorrect octaves
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of floor we can simply use integer division: event["param1"] // 12.

Even if floor was needed, the one from NumPy returns a float instead of an int, and pulls in an unnecessary dependency (numpy is only required for the FFT module). The floor from the built-in math module would fit in perfectly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already fixed on master (due to #64)

fp.read(chunk_size / 2)
self.bytes_read += chunk_size / 2
# fp.read(chunk_size // 2)
# self.bytes_read += chunk_size // 2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this seems like a debug thing. Indeed the divisions here should be integer divisions, but it seems to me there's no reason to remove this code and it should be uncommented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might have been coming from LilyPond midi files - maybe worth keeping an eye on this in future

@@ -332,6 +355,12 @@ def parse_midi_event(self, fp):
raise IOError("Couldn't read MIDI event parameters from file.")
param1 = self.bytes_to_int(param1)
param2 = self.bytes_to_int(param2)

# "It is common for a note on with 0 velocity to be interpreted as NOTE OFF." https://stackoverflow.com/questions/48687756/midi-note-on-event-without-off-event
# this should resolve Lilypad midi files which don't seem to use ec 8 to signify NOTE OFF
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one. Did you mean LilyPond instead of Lilypad?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I did :)

#
# SG:
# Have needed to change strings to bstrings to get concat to work
#
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type of comment would be more suited to the commit message. But I think this one is outdated and just unneeded.

@@ -256,7 +257,7 @@ def set_key(self, key="C"):

def key_signature_event(self, key="C"):
"""Return the bytes for a key signature event."""
if key.islower():
if str(key).islower():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. I think this solves it for now. In the future we should use stricter types.

@samg7b5
Copy link
Contributor Author

samg7b5 commented May 9, 2020

Thanks @edudobay - just for context, it's not the best structured PR because when I was working on it I didn't really consider adding back into the project, but then afterwards figured I probably should share my updates back to the community. Hence the random comments and things, apologies for that.

A couple of the edits that you've picked up on look like things that I never actually made myself - potentially diff against edits that have already been incorporated into the base in the meantime? These are the things like temporal_note, I can't recall adding (or needing to add) that in myself, as you rightly noted in your response.

For simplicity, I'd suggest we only keep my MIDI fixes and the new jazz scales since these are quite clear. What do you think? I can take a look at the requested changes you've flagged above, but could you please advise on how I should go about splitting into different commits and re-submitting?

Cheers!

@edudobay
Copy link
Collaborator

edudobay commented May 9, 2020

Hey @samg7b5, sorry I missed your comment for a few minutes. I was investigating the MIDI issues that were discussed in #64 and saw that further changes were needed. So I expedited a fix, including your changes and some other ones, that is already present in the master branch – mentioning your name in the commit message for credit :)

About the other issues, I'd propose we add the jazz scales first, and then we can handle what's left (if needed). What do you think?

@samg7b5
Copy link
Contributor Author

samg7b5 commented May 9, 2020

@edudobay no problem at all! Thanks for the mention.

Agree, let's add the jazz scales as it seems pretty much everything else is covered. And I'll try to do cleaner commits in future (I'm working on a higher-level jazz composition and analysis API that I'm calling Sidewinder, so may end up dipping into mingus again)! Please let me know if you need anything from me with regards to incorporating the jazz scales (they should all be quite clearly laid out in the scales.py file) and/or finalising or closing this PR? This is my first GitHub contribution so this is all pretty new to me :)


def generate(self, i):
print('Please use ascending() and descending() methods instead of generate() for SUHMM scales')
return False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that returning False would totally break the expectations of the caller. I think that you should either raise an exception or accept to run the default generate normally. (In the latter case you could issue a warning, using warnings.warn())

@edudobay
Copy link
Collaborator

edudobay commented May 9, 2020

@samg7b5 Sorry if I've been a bit harsh on some comments. Welcome and congrats on your first GitHub contribution :)

Well, for the PR to be ready to merge we'll have to isolate the changes in scales.py and revert the others. Are you comfortable with this? I'd suggest that you start a new branch and open a new PR with only the changes to scales.py (so you don't need to discard everything that is contained in this PR).

@samg7b5
Copy link
Contributor Author

samg7b5 commented May 18, 2020

Will open a new PR #66 with scales (and the couple of approved midi changes) isolated.

@samg7b5 samg7b5 closed this May 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants