Push 2 Scales
-
- Posts: 7
- Joined: Wed May 08, 2013 10:51 am
- Contact:
Re: Push 2 Scales
Just confirming that this also works with Live 11 beta.
Note however that, although that the newly added scales will still show up in Push, they won't be present in the new 'Scales' list shown in the new MIDI clip editor.
Note however that, although that the newly added scales will still show up in Push, they won't be present in the new 'Scales' list shown in the new MIDI clip editor.
-
- Posts: 35
- Joined: Thu Feb 08, 2018 9:29 am
Re: Push 2 Scales
You spoke too soon I think, I repeatedly get this error and/or just a blank screen on the push and nothing but the dot on the pitch bend lighting up in the latest beta 11.0b22MauriceNorris wrote: ↑Wed Nov 11, 2020 9:30 amJust confirming that this also works with Live 11 beta.
Note however that, although that the newly added scales will still show up in Push, they won't be present in the new 'Scales' list shown in the new MIDI clip editor.
Any anyone please look into why this is happening all of a sudden? Almost looks like a deliberate thing done by Ableton to stop us from upgrading the push like that or what? This looks like deliberate tampering to make it not work all of a sudden, but please prove me wrong or find a way to circumvent this nonsense. Thanks
Re: Push 2 Scales
L11 now uses v3 of Python, and 3rd party scripts need to be updated to work with it.
Ableton Forum Moderator
-
- Posts: 7
- Joined: Wed May 08, 2013 10:51 am
- Contact:
Re: Push 2 Scales
Hmm, that's strange. I'm on b23 and am not getting this error at all. The modified melodic_pattern.py is still working fine.torbenscharling wrote: ↑Mon Dec 21, 2020 5:36 am
You spoke too soon I think, I repeatedly get this error and/or just a blank screen on the push and nothing but the dot on the pitch bend lighting up in the latest beta 11.0b22
-
- Posts: 35
- Joined: Thu Feb 08, 2018 9:29 am
Re: Push 2 Scales
I'm on 23 now and still does it..Push 2 logo on the push and ableton says Script could not be loadedMauriceNorris wrote: ↑Sun Jan 17, 2021 8:55 pmHmm, that's strange. I'm on b23 and am not getting this error at all. The modified melodic_pattern.py is still working fine.torbenscharling wrote: ↑Mon Dec 21, 2020 5:36 am
You spoke too soon I think, I repeatedly get this error and/or just a blank screen on the push and nothing but the dot on the pitch bend lighting up in the latest beta 11.0b22
Did you compile it fresh with the 11 install or just copy paste it over from the one in the 10 pushbase?
If it works on yours why does it keep saying remote script doesnt work on mine?
Works fine on ableton 10 beta still...same push, same machine..doesn't work on 11 beta 22 and 11 beta 23..
I don't know much about compiling pyc files and stuff like that I just want additional scales to work like they do on 10, since I payed for the upgrade to 11, so far I'm stuck with the info that it needs to be updated to python 3 but if that's not the case, the original "dev" doesn't have to be bothered making a new .pyc or if I can just change something manually in it, but I need to know where to go from here to fix this issue.
-
- Posts: 7
- Joined: Wed May 08, 2013 10:51 am
- Contact:
Re: Push 2 Scales
@torbenscharling
I didn't compile it, no. You don't need to. Ableton does the compiling for you (from the .py file)
I just copied the melodic_pattern.py from the Live 10 to Live 11.
Are you copying the .py or the .pyc file to Ableton 11? If it's the .pyc then this will almost certainly produce an error as this is the file that Ableton 10 has already compiled. Ableton needs to 'see' the .py file and then compile it itself.
You're welcome to use my melodic_pattern.py though if you like? You can download it here:
https://drive.google.com/file/d/1Sm-0Ze ... sp=sharing
Just make sure you backup your original melodic_pattern.pyc (which I'm guessing you already have) and delete the melodic_pattern.pyc script that isn't working for you. If it's working for you (and I can't see any reason it shouldn't) you should just be able to copy the part where you define the scales from your old script into mine.
Hope this helps.
I didn't compile it, no. You don't need to. Ableton does the compiling for you (from the .py file)
I just copied the melodic_pattern.py from the Live 10 to Live 11.
Are you copying the .py or the .pyc file to Ableton 11? If it's the .pyc then this will almost certainly produce an error as this is the file that Ableton 10 has already compiled. Ableton needs to 'see' the .py file and then compile it itself.
You're welcome to use my melodic_pattern.py though if you like? You can download it here:
https://drive.google.com/file/d/1Sm-0Ze ... sp=sharing
Just make sure you backup your original melodic_pattern.pyc (which I'm guessing you already have) and delete the melodic_pattern.pyc script that isn't working for you. If it's working for you (and I can't see any reason it shouldn't) you should just be able to copy the part where you define the scales from your old script into mine.
Hope this helps.
-
- Posts: 35
- Joined: Thu Feb 08, 2018 9:29 am
Re: Push 2 Scales
Indeed it does help tremendously !!! THANKS SO MUCH !! This has been bugging the h... out of me cause I couldn't get ableton support on this so I had no idea if I could safely upgrade to 11 and had to do it in time to get the 20% discount so now I got both bases covered so I'm ready for when 11 is released (apart from reading the damn manual lol) anyway thanks again, now I don't have to worry so much about what happened. But just in case anyone has a clue what went wrong (I'm pretty sure I did the same, copying over the .py file) so here it is copy pasted (the one giving me the error consistently):MauriceNorris wrote: ↑Wed Jan 20, 2021 2:59 pm@torbenscharling
I didn't compile it, no. You don't need to. Ableton does the compiling for you (from the .py file)
I just copied the melodic_pattern.py from the Live 10 to Live 11.
Are you copying the .py or the .pyc file to Ableton 11? If it's the .pyc then this will almost certainly produce an error as this is the file that Ableton 10 has already compiled. Ableton needs to 'see' the .py file and then compile it itself.
You're welcome to use my melodic_pattern.py though if you like? You can download it here:
https://drive.google.com/file/d/1Sm-0Ze ... sp=sharing
Just make sure you backup your original melodic_pattern.pyc (which I'm guessing you already have) and delete the melodic_pattern.pyc script that isn't working for you. If it's working for you (and I can't see any reason it shouldn't) you should just be able to copy the part where you define the scales from your old script into mine.
Hope this helps.
# uncompyle6 version 3.7.0
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.16 (v2.7.16:413a49145e, Mar 4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)]
# Embedded file name: c:\Jenkins\live\output\Live\win_64_static\Release\python-bundle\MIDI Remote Scripts\pushbase\melodic_pattern.py
# Compiled at: 2020-01-07 14:24:16
from __future__ import absolute_import, print_function, unicode_literals
from ableton.v2.base import NamedTuple, lazy_attribute, memoize, find_if
from . import consts
from .matrix_maps import FEEDBACK_CHANNELS
import Live
CIRCLE_OF_FIFTHS = tuple([ 7 * k % 12 for k in range(12) ])
ROOT_NOTES = CIRCLE_OF_FIFTHS[0:6] + CIRCLE_OF_FIFTHS[-1:5:-1]
NOTE_NAMES = (u'C', u'D\u266d', u'D', u'E\u266d', u'E', u'F', u'G\u266d', u'G', u'A\u266d',
u'A', u'B\u266d', u'B')
def pitch_index_to_string(index):
if 0 <= index < 128:
return NOTE_NAMES[(index % 12)] + str(index / 12 - 2)
return consts.CHAR_ELLIPSIS
class Scale(NamedTuple):
name = ''
notes = []
def to_root_note(self, root_note):
return Scale(name=NOTE_NAMES[root_note], notes=[ root_note + x for x in self.notes ])
@memoize
def scale_for_notes(self, notes):
return [ self.to_root_note(b) for b in notes ]
def __unicode__(self):
return self.name
def __str__(self):
return unicode(self).encode('utf-8')
def __eq__(self, other):
if isinstance(other, Scale):
return self.name == other.name and self.notes == other.notes
return False
EXTRA_SCALES = (
("ionian pentatonic", (0, 4, 5, 7, 11)),
("mixolydian pent.", (0, 4, 5, 7, 10)),
("ritusen", (0, 2, 5, 7, 9)),
("egyptian", (0, 2, 5, 7, 10)),
("neo. major pent.", (0, 4, 5, 6, 10)),
("vietnamese 1", (0, 3, 5, 7, ),
("lydian pentatonic", (0, 4, 6, 7, 11)),
("malkos raga", (0, 3, 5, 8, 10)),
("locrian pentatonic", (0, 3, 5, 6, 10)),
("minor six pent.", (0, 3, 5, 7, 9)),
("flat six pent.", (0, 2, 4, 7, ),
("scriabin", (0, 1, 4, 7, 9)),
("whole tone pent.", (0, 4, 6, 8, 10)),
("lydian #5P pent.", (0, 4, 6, 8, 11)),
("lydian dom. pent.", (0, 4, 6, 7, 10)),
("minor #7M pent.", (0, 3, 5, 7, 11)),
("sup. locrian pent.", (0, 3, 4, 6, 10)),
("minor hexatonic", (0, 2, 3, 5, 7, 11)),
("augmented", (0, 3, 4, 7, 8, 11)),
("major blues", (0, 2, 3, 4, 7, 9)),
("piongio", (0, 2, 5, 7, 9, 10)),
("prometheus neo.", (0, 1, 4, 6, 9, 10)),
("prometheus", (0, 2, 4, 6, 9, 10)),
("mystery #1", (0, 1, 4, 6, 8, 10)),
("6-tone symmetric", (0, 1, 4, 5, 8, 9)),
("locrian major", (0, 2, 4, 5, 6, 8, 10)),
("dbl. harm. lydian", (0, 1, 4, 6, 7, 8, 11)),
("locrian #2", (0, 2, 3, 5, 6, 8, 10)),
("mixolydian b6", (0, 2, 4, 5, 7, 8, 10)),
("dorian b2", (0, 1, 3, 5, 7, 9, 10)),
("ultralocrian", (0, 1, 3, 4, 6, 8, 9)),
("locrian 6", (0, 1, 3, 5, 6, 9, 10)),
("augmented hep.", (0, 3, 4, 5, 7, 8, 11)),
("lydian diminished", (0, 2, 3, 6, 7, 9, 11)),
("lead. whole tone", (0, 2, 4, 6, 8, 10, 11)),
("lydian minor", (0, 2, 4, 6, 7, 8, 10)),
("balinese", (0, 1, 3, 5, 7, 8, 11)),
("neopolitan major", (0, 1, 3, 5, 7, 9, 11)),
("hungarian major", (0, 3, 4, 6, 7, 9, 10)),
("oriental", (0, 1, 4, 5, 6, 9, 10)),
("flamenco", (0, 1, 3, 4, 6, 7, 10)),
("todi raga", (0, 1, 3, 6, 7, 8, 11)),
("persian", (0, 1, 4, 5, 6, 8, 11)),
("enigmatic", (0, 1, 4, 6, 8, 10, 11)),
("major augmented", (0, 2, 4, 5, 8, 9, 11)),
("lydian #9", (0, 3, 4, 6, 7, 9, 11)),
("purvi raga", (0, 1, 4, 5, 6, 7, 8, 11)),
("spanish hept.", (0, 1, 3, 4, 5, 7, 8, 10)),
("bebop", (0, 2, 4, 5, 7, 9, 10, 11)),
("bebop minor", (0, 2, 3, 4, 5, 7, 9, 10)),
("bebop major", (0, 2, 4, 5, 7, 8, 9, 11)),
("bebop locrian", (0, 1, 3, 5, 6, 7, 8, 10)),
("minor bebop", (0, 2, 3, 5, 7, 8, 10, 11)),
("ichikosucho", (0, 2, 4, 5, 6, 7, 9, 11)),
("minor six dim.", (0, 2, 3, 5, 7, 8, 9, 11)),
("kafi raga", (0, 3, 4, 5, 7, 9, 10, 11)),
("composite blues", (0, 2, 3, 4, 5, 6, 7, 9, 10))
)
SCALES = tuple([ Scale(name=x[0], notes=x[1]) for x in Live.Song.get_all_scales_ordered() + EXTRA_SCALES ])
def scale_by_name(name):
return find_if(lambda m: m.name == name, SCALES)
class NoteInfo(NamedTuple):
index = None
channel = 0
color = 'NoteInvalid'
class MelodicPattern(NamedTuple):
steps = [
0, 0]
scale = range(12)
root_note = 0
origin = [0, 0]
chromatic_mode = False
width = None
height = None
@lazy_attribute
def extended_scale(self):
if self.chromatic_mode:
first_note = self.scale[0]
return range(first_note, first_note + 12)
else:
return self.scale
@property
def is_aligned(self):
return not self.origin[0] and not self.origin[1] and abs(self.root_note) % 12 == self.extended_scale[0]
def note(self, x, y):
if not self._boundary_reached(x, y):
channel = y % len(FEEDBACK_CHANNELS) + FEEDBACK_CHANNELS[0]
return self._get_note_info(self._octave_and_note(x, y), self.root_note, channel)
return NoteInfo()
def __getitem__(self, i):
root_note = self.root_note
if root_note <= -12:
root_note = 0 if self.is_aligned else -12
return self._get_note_info(self._octave_and_note_linear(i), root_note)
def _boundary_reached(self, x, y):
return self.width is not None and x >= self.width or self.height is not None and y >= self.height
def _octave_and_note_by_index(self, index):
scale = self.extended_scale
scale_size = len(scale)
octave = index / scale_size
note = scale[(index % scale_size)]
return (octave, note)
def _octave_and_note(self, x, y):
index = self.steps[0] * (self.origin[0] + x) + self.steps[1] * (self.origin[1] + y)
return self._octave_and_note_by_index(index)
def _color_for_note(self, note):
if note == self.scale[0]:
return 'NoteBase'
else:
if note in self.scale:
return 'NoteScale'
return 'NoteNotScale'
def _get_note_info(self, (octave, note), root_note, channel=0):
note_index = 12 * octave + note + root_note
if 0 <= note_index <= 127:
return NoteInfo(index=note_index, channel=channel, color=self._color_for_note(note))
else:
return NoteInfo()
def _octave_and_note_linear(self, i):
origin = self.origin[0] or self.origin[1]
index = origin + i
return self._octave_and_note_by_index(index)
-
- Posts: 7
- Joined: Wed May 08, 2013 10:51 am
- Contact:
Re: Push 2 Scales
@torbenscharling
No worries! Glad you got it working in the end
There do seem to be quite a few differences in the script that wasn't working for you and the one that is, although I don't know enough about Python to know what these differences actually mean!
Here's the working one for reference if anyone else needs it:
No worries! Glad you got it working in the end
There do seem to be quite a few differences in the script that wasn't working for you and the one that is, although I don't know enough about Python to know what these differences actually mean!
Here's the working one for reference if anyone else needs it:
Code: Select all
# uncompyle6 version 3.6.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.17 (default, Sep 30 2020, 13:38:04)
# [GCC 7.5.0]
# Embedded file name: /Users/versonator/Jenkins/live/output/Live/mac_64_static/Release/python-bundle/MIDI Remote Scripts/pushbase/melodic_pattern.py
# Compiled at: 2020-11-06 11:19:13
from __future__ import absolute_import, print_function, unicode_literals
from __future__ import division
from builtins import str
from builtins import range
from past.utils import old_div
from ableton.v2.base import NamedTuple, lazy_attribute, memoize, find_if
from . import consts
from .matrix_maps import FEEDBACK_CHANNELS
import Live
CIRCLE_OF_FIFTHS = tuple([ 7 * k % 12 for k in range(12) ])
ROOT_NOTES = CIRCLE_OF_FIFTHS[0:6] + CIRCLE_OF_FIFTHS[-1:5:-1]
NOTE_NAMES = (u'C', u'D\u266d', u'D', u'E\u266d', u'E', u'F', u'G\u266d', u'G', u'A\u266d',
u'A', u'B\u266d', u'B')
def pitch_index_to_string(index):
if index is not None and 0 <= index < 128:
return NOTE_NAMES[(index % 12)] + str(old_div(index, 12) - 2)
else:
return consts.CHAR_ELLIPSIS
class Scale(NamedTuple):
name = ''
notes = []
def to_root_note(self, root_note):
return Scale(name=NOTE_NAMES[root_note], notes=[ root_note + x for x in self.notes ])
@memoize
def scale_for_notes(self, notes):
return [ self.to_root_note(b) for b in notes ]
def __unicode__(self):
return self.name
def __str__(self):
return str(self.name)
def __eq__(self, other):
if isinstance(other, Scale):
return self.name == other.name and self.notes == other.notes
return False
def __hash__(self):
return hash((self.name,))
EXTRA_SCALES = (
("Ionian Pentatonic", (0, 4, 5, 7, 11)),
("Mixolydian Pent.", (0, 4, 5, 7, 10)),
("Ritusen", (0, 2, 5, 7, 9)),
("Egyptian", (0, 2, 5, 7, 10)),
("Neo. Major Pent.", (0, 4, 5, 6, 10)),
("Vietnamese 1", (0, 3, 5, 7, 8)),
("Lydian Pentatonic", (0, 4, 6, 7, 11)),
("Malkos Raga", (0, 3, 5, 8, 10)),
("Locrian Pentatonic", (0, 3, 5, 6, 10)),
("Minor Six Pent.", (0, 3, 5, 7, 9)),
("Flat Six Pent.", (0, 2, 4, 7, 8)),
("Scriabin", (0, 1, 4, 7, 9)),
("Whole Tone Pent.", (0, 4, 6, 8, 10)),
("Lydian #5P Pent.", (0, 4, 6, 8, 11)),
("Lydian Dom. Pent.", (0, 4, 6, 7, 10)),
("Minor #7M Pent.", (0, 3, 5, 7, 11)),
("Sup. Locrian Pent.", (0, 3, 4, 6, 10)),
("Minor Hexatonic", (0, 2, 3, 5, 7, 11)),
("Augmented", (0, 3, 4, 7, 8, 11)),
("Major Blues", (0, 2, 3, 4, 7, 9)),
("Piongio", (0, 2, 5, 7, 9, 10)),
("Prometheus Neo.", (0, 1, 4, 6, 9, 10)),
("Prometheus", (0, 2, 4, 6, 9, 10)),
("Mystery #1", (0, 1, 4, 6, 8, 10)),
("6-tone Symmetric", (0, 1, 4, 5, 8, 9)),
("Locrian Major", (0, 2, 4, 5, 6, 8, 10)),
("Dbl. Harm. Lydian", (0, 1, 4, 6, 7, 8, 11)),
("Locrian #2", (0, 2, 3, 5, 6, 8, 10)),
("Mixolydian B6", (0, 2, 4, 5, 7, 8, 10)),
("Dorian B2", (0, 1, 3, 5, 7, 9, 10)),
("Ultralocrian", (0, 1, 3, 4, 6, 8, 9)),
("Locrian 6", (0, 1, 3, 5, 6, 9, 10)),
("Augmented Hep.", (0, 3, 4, 5, 7, 8, 11)),
("Lydian Diminished", (0, 2, 3, 6, 7, 9, 11)),
("Lead. Whole Tone", (0, 2, 4, 6, 8, 10, 11)),
("Lydian Minor", (0, 2, 4, 6, 7, 8, 10)),
("Balinese", (0, 1, 3, 5, 7, 8, 11)),
("Neopolitan Major", (0, 1, 3, 5, 7, 9, 11)),
("Hungarian Major", (0, 3, 4, 6, 7, 9, 10)),
("Oriental", (0, 1, 4, 5, 6, 9, 10)),
("Flamenco", (0, 1, 3, 4, 6, 7, 10)),
("Todi Raga", (0, 1, 3, 6, 7, 8, 11)),
("Persian", (0, 1, 4, 5, 6, 8, 11)),
("Enigmatic", (0, 1, 4, 6, 8, 10, 11)),
("Major Augmented", (0, 2, 4, 5, 8, 9, 11)),
("Lydian #9", (0, 3, 4, 6, 7, 9, 11)),
("Purvi Raga", (0, 1, 4, 5, 6, 7, 8, 11)),
("Spanish Hept.", (0, 1, 3, 4, 5, 7, 8, 10)),
("Bebop", (0, 2, 4, 5, 7, 9, 10, 11)),
("Bebop Minor", (0, 2, 3, 4, 5, 7, 9, 10)),
("Bebop Major", (0, 2, 4, 5, 7, 8, 9, 11)),
("Bebop Locrian", (0, 1, 3, 5, 6, 7, 8, 10)),
("Minor Bebop", (0, 2, 3, 5, 7, 8, 10, 11)),
("Ichikosucho", (0, 2, 4, 5, 6, 7, 9, 11)),
("Minor Six Dim.", (0, 2, 3, 5, 7, 8, 9, 11)),
("Kafi Raga", (0, 3, 4, 5, 7, 9, 10, 11)),
("Composite Blues", (0, 2, 3, 4, 5, 6, 7, 9, 10))
)
SCALES = tuple([ Scale(name=x[0], notes=x[1]) for x in Live.Song.get_all_scales_ordered() + EXTRA_SCALES ])
def scale_by_name(name):
return find_if(lambda m: m.name == name, SCALES)
class NoteInfo(NamedTuple):
index = None
channel = 0
color = 'NoteInvalid'
class MelodicPattern(NamedTuple):
steps = [
0, 0]
scale = list(range(12))
root_note = 0
origin = [0, 0]
chromatic_mode = False
width = None
height = None
@lazy_attribute
def extended_scale(self):
if self.chromatic_mode:
first_note = self.scale[0]
return list(range(first_note, first_note + 12))
else:
return self.scale
@property
def is_aligned(self):
return not self.origin[0] and not self.origin[1] and abs(self.root_note) % 12 == self.extended_scale[0]
def note(self, x, y):
if not self._boundary_reached(x, y):
channel = y % len(FEEDBACK_CHANNELS) + FEEDBACK_CHANNELS[0]
return self._get_note_info(self._octave_and_note(x, y), self.root_note, channel)
return NoteInfo()
def __getitem__(self, i):
root_note = self.root_note
if root_note <= -12:
root_note = 0 if self.is_aligned else -12
return self._get_note_info(self._octave_and_note_linear(i), root_note)
def _boundary_reached(self, x, y):
return self.width is not None and x >= self.width or self.height is not None and y >= self.height
def _octave_and_note_by_index(self, index):
scale = self.extended_scale
scale_size = len(scale)
octave = old_div(index, scale_size)
note = scale[(index % scale_size)]
return (
octave, note)
def _octave_and_note(self, x, y):
index = self.steps[0] * (self.origin[0] + x) + self.steps[1] * (self.origin[1] + y)
return self._octave_and_note_by_index(index)
def _color_for_note(self, note):
if note == self.scale[0]:
return 'NoteBase'
else:
if note in self.scale:
return 'NoteScale'
return 'NoteNotScale'
def _get_note_info(self, octave_note, root_note, channel=0):
octave, note = octave_note
note_index = 12 * octave + note + root_note
if 0 <= note_index <= 127:
return NoteInfo(index=note_index, channel=channel, color=self._color_for_note(note))
else:
return NoteInfo()
def _octave_and_note_linear(self, i):
origin = self.origin[0] or self.origin[1]
index = origin + i
return self._octave_and_note_by_index(index)
Re: Push 2 Scales
I recently purchased a push 3 (standalone) and was hoping to add more scales to the menu. I found this thread and followed the steps....however, nothing changes on the push 3 when I restart ableton / power cycle the push 3.
I decompiled the melodic_pattern.pyc file and created a new melodic_pattern.py file with the following:
My music production setup is currently in Windows, so I put the file in and made sure to rename the old melodic_pattern.pyc to melodic_pattern.pyc_old.
I've tried power cycling and restarting the software multiple times, but haven't had any luck getting new scales to appear. Has anyone successfully done this with a Push 3 standalone and the latest version of Live 11? BTW, I am currently using the push 3 in controller mode for this mod, so I would expect it to work similarly to Push 2. Any help would be appreciated...
I decompiled the melodic_pattern.pyc file and created a new melodic_pattern.py file with the following:
Code: Select all
# decompyle3 version 3.9.0
# Python bytecode version base 3.7.0 (3394)
# Decompiled from: Python 3.9.5 (tags/v3.9.5:0a7dcbd, May 3 2021, 17:27:52) [MSC v.1928 64 bit (AMD64)]
# Embedded file name: ..\..\..\output\Live\win_64_static\Release\python-bundle\MIDI Remote Scripts\pushbase\melodic_pattern.py
# Compiled at: 2023-03-03 08:20:15
# Size of source mod 2**32: 4653 bytes
from __future__ import absolute_import, division, print_function, unicode_literals
from builtins import range, str
from past.utils import old_div
import Live
from ableton.v2.base import NamedTuple, find_if, lazy_attribute, memoize
from . import consts
from .matrix_maps import FEEDBACK_CHANNELS
CIRCLE_OF_FIFTHS = tuple([7 * k % 12 for k in range(12)])
ROOT_NOTES = CIRCLE_OF_FIFTHS[0:6] + CIRCLE_OF_FIFTHS[-1:5:-1]
NOTE_NAMES = ('C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B')
def pitch_index_to_string(index):
if index is not None:
if 0<= index < 128:
return NOTE_NAMES[index % 12] + str(old_div(index, 12) - 2)
return consts.CHAR_ELLIPSIS
class Scale(NamedTuple):
name = ''
notes = []
def to_root_note(self, root_note):
return Scale(name=(NOTE_NAMES[root_note]),
notes=[root_note + x for x in self.notes])
@memoize
def scale_for_notes(self, notes):
return [self.to_root_note(b) for b in notes]
def __unicode__(self):
return self.name
def __str__(self):
return str(self.name)
def __eq__(self, other):
if isinstance(other, Scale):
return self.name == other.name and self.notes == other.notes
return False
def __hash__(self):
return hash((self.name,))
EXTRA_SCALES = (
("Ionian Pentatonic", (0, 4, 5, 7, 11)),
("Mixolydian Pent.", (0, 4, 5, 7, 10)),
("Ritusen", (0, 2, 5, 7, 9)),
("Egyptian", (0, 2, 5, 7, 10)),
("Neo. Major Pent.", (0, 4, 5, 6, 10)),
("Vietnamese 1", (0, 3, 5, 7, 8)),
("Lydian Pentatonic", (0, 4, 6, 7, 11)),
("Malkos Raga", (0, 3, 5, 8, 10)),
("Locrian Pentatonic", (0, 3, 5, 6, 10)),
("Minor Six Pent.", (0, 3, 5, 7, 9)),
("Flat Six Pent.", (0, 2, 4, 7, 8)),
("Scriabin", (0, 1, 4, 7, 9)),
("Whole Tone Pent.", (0, 4, 6, 8, 10)),
("Lydian #5P Pent.", (0, 4, 6, 8, 11)),
("Lydian Dom. Pent.", (0, 4, 6, 7, 10)),
("Minor #7M Pent.", (0, 3, 5, 7, 11)),
("Sup. Locrian Pent.", (0, 3, 4, 6, 10)),
("Minor Hexatonic", (0, 2, 3, 5, 7, 11)),
("Augmented", (0, 3, 4, 7, 8, 11)),
("Major Blues", (0, 2, 3, 4, 7, 9)),
("Piongio", (0, 2, 5, 7, 9, 10)),
("Prometheus Neo.", (0, 1, 4, 6, 9, 10)),
("Prometheus", (0, 2, 4, 6, 9, 10)),
("Mystery #1", (0, 1, 4, 6, 8, 10)),
("6-tone Symmetric", (0, 1, 4, 5, 8, 9)),
("Locrian Major", (0, 2, 4, 5, 6, 8, 10)),
("Dbl. Harm. Lydian", (0, 1, 4, 6, 7, 8, 11)),
("Locrian #2", (0, 2, 3, 5, 6, 8, 10)),
("Mixolydian B6", (0, 2, 4, 5, 7, 8, 10)),
("Dorian B2", (0, 1, 3, 5, 7, 9, 10)),
("Ultralocrian", (0, 1, 3, 4, 6, 8, 9)),
("Locrian 6", (0, 1, 3, 5, 6, 9, 10)),
("Augmented Hep.", (0, 3, 4, 5, 7, 8, 11)),
("Lydian Diminished", (0, 2, 3, 6, 7, 9, 11)),
("Lead. Whole Tone", (0, 2, 4, 6, 8, 10, 11)),
("Lydian Minor", (0, 2, 4, 6, 7, 8, 10)),
("Balinese", (0, 1, 3, 5, 7, 8, 11)),
("Neopolitan Major", (0, 1, 3, 5, 7, 9, 11)),
("Hungarian Major", (0, 3, 4, 6, 7, 9, 10)),
("Oriental", (0, 1, 4, 5, 6, 9, 10)),
("Flamenco", (0, 1, 3, 4, 6, 7, 10)),
("Todi Raga", (0, 1, 3, 6, 7, 8, 11)),
("Persian", (0, 1, 4, 5, 6, 8, 11)),
("Enigmatic", (0, 1, 4, 6, 8, 10, 11)),
("Major Augmented", (0, 2, 4, 5, 8, 9, 11)),
("Lydian #9", (0, 3, 4, 6, 7, 9, 11)),
("Purvi Raga", (0, 1, 4, 5, 6, 7, 8, 11)),
("Spanish Hept.", (0, 1, 3, 4, 5, 7, 8, 10)),
("Bebop", (0, 2, 4, 5, 7, 9, 10, 11)),
("Bebop Minor", (0, 2, 3, 4, 5, 7, 9, 10)),
("Bebop Major", (0, 2, 4, 5, 7, 8, 9, 11)),
("Bebop Locrian", (0, 1, 3, 5, 6, 7, 8, 10)),
("Minor Bebop", (0, 2, 3, 5, 7, 8, 10, 11)),
("Ichikosucho", (0, 2, 4, 5, 6, 7, 9, 11)),
("Minor Six Dim.", (0, 2, 3, 5, 7, 8, 9, 11)),
("Kafi Raga", (0, 3, 4, 5, 7, 9, 10, 11)),
("Composite Blues", (0, 2, 3, 4, 5, 6, 7, 9, 10))
)
SCALES = tuple([ Scale(name=x[0], notes=x[1]) for x in Live.Song.get_all_scales_ordered() + EXTRA_SCALES ])
#SCALES = tuple([Scale(name=(x[0]), notes=(x[1])) for x in Live.Song.get_all_scales_ordered()])
def scale_by_name(name):
return find_if(lambda m: m.name == name
, SCALES)
class NoteInfo(NamedTuple):
index = None
channel = 0
color = 'NoteInvalid'
class MelodicPattern(NamedTuple):
steps = [
0, 0]
scale = list(range(12))
root_note = 0
origin = [0, 0]
chromatic_mode = False
width = None
height = None
@lazy_attribute
def extended_scale(self):
if self.chromatic_mode:
first_note = self.scale[0]
return list(range(first_note, first_note + 12))
return self.scale
@property
def is_aligned(self):
return not self.origin[0] and not self.origin[1] and abs(self.root_note) % 12 == self.extended_scale[0]
def note(self, x, y):
if not self._boundary_reached(x, y):
channel = y % len(FEEDBACK_CHANNELS) + FEEDBACK_CHANNELS[0]
return self._get_note_info(self._octave_and_note(x, y), self.root_note, channel)
return NoteInfo()
def __getitem__(self, i):
root_note = self.root_note
if root_note <= -12:
root_note = 0 if self.is_aligned else -12
return self._get_note_info(self._octave_and_note_linear(i), root_note)
def _boundary_reached(self, x, y):
return (self.width is not None) and (x >= self.width) or (self.height is not None and y >= self.height)
def _octave_and_note_by_index(self, index):
scale = self.extended_scale
scale_size = len(scale)
octave = old_div(index, scale_size)
note = scale[index % scale_size]
return (
octave, note)
def _octave_and_note(self, x, y):
index = self.steps[0] * (self.origin[0] + x) + self.steps[1] * (self.origin[1] + y)
return self._octave_and_note_by_index(index)
def _color_for_note(self, note):
if note == self.scale[0]:
return 'NoteBase'
if note in self.scale:
return 'NoteScale'
return 'NoteNotScale'
def _get_note_info(self, octave_note, root_note, channel=0):
octave, note = octave_note
note_index = 12 * octave + note + root_note
if 0<= note_index <= 127:
return NoteInfo(index=note_index,
channel=channel,
color=(self._color_for_note(note)))
return NoteInfo()
def _octave_and_note_linear(self, i):
origin = self.origin[0] or self.origin[1]
index = origin + i
return self._octave_and_note_by_index(index)
Code: Select all
C:\ProgramData\Ableton\Live 11 Suite\Resources\MIDI Remote Scripts\pushbase
I've tried power cycling and restarting the software multiple times, but haven't had any luck getting new scales to appear. Has anyone successfully done this with a Push 3 standalone and the latest version of Live 11? BTW, I am currently using the push 3 in controller mode for this mod, so I would expect it to work similarly to Push 2. Any help would be appreciated...
Re: Push 2 Scales
Works in live 11 thank you !!
Also, I'd like to change the layout (4ths, 3ds...)
Can I do this ?
Also, I'd like to change the layout (4ths, 3ds...)
Can I do this ?
Re: Push 2 Scales
All the files are in a different place for the Push 3. But when I tried changing them it still didnt work, if I add new scales then the whole thing crashes. Maybe its because the Push 3 has to have code in Ableton Live which will do the MPE pitch bends between notes in the scales on the pad grid, and this involves code on the non-python side of things which we cant modify, and that perhaps that code goes wrong when unexpected scales are included in the list generated on the python side of things. However this is just one theory, there could be a different issue.jschunick wrote: ↑Wed Aug 02, 2023 3:55 amI've tried power cycling and restarting the software multiple times, but haven't had any luck getting new scales to appear. Has anyone successfully done this with a Push 3 standalone and the latest version of Live 11? BTW, I am currently using the push 3 in controller mode for this mod, so I would expect it to work similarly to Push 2. Any help would be appreciated...
I cant tell you where the Push 3 version is on Windows. On mac they are within a bundle called Push3 inside a folder called Helpers.
-
- Posts: 9
- Joined: Tue Feb 27, 2024 10:48 pm
Re: Push 2 Scales
Does not work with Live 12. Any help would be greatly appreciated.