Push 2 Scales

Come here to discuss Push with other users.
For tech support, please head to http://www.ableton.com/help
MauriceNorris
Posts: 7
Joined: Wed May 08, 2013 10:51 am
Contact:

Re: Push 2 Scales

Post by MauriceNorris » Wed Nov 11, 2020 9:30 am

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.

torbenscharling
Posts: 35
Joined: Thu Feb 08, 2018 9:29 am

Re: Push 2 Scales

Post by torbenscharling » Mon Dec 21, 2020 5:36 am

MauriceNorris wrote:
Wed Nov 11, 2020 9:30 am
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.
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 :(

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 :)

Image

[jur]
Site Admin
Posts: 2604
Joined: Mon Jun 01, 2015 3:04 pm
Location: Ableton

Re: Push 2 Scales

Post by [jur] » Mon Jan 04, 2021 12:44 am

L11 now uses v3 of Python, and 3rd party scripts need to be updated to work with it.
Ableton Forum Moderator

MauriceNorris
Posts: 7
Joined: Wed May 08, 2013 10:51 am
Contact:

Re: Push 2 Scales

Post by MauriceNorris » Sun Jan 17, 2021 8:55 pm

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 :(
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
Posts: 35
Joined: Thu Feb 08, 2018 9:29 am

Re: Push 2 Scales

Post by torbenscharling » Wed Jan 20, 2021 3:13 am

MauriceNorris wrote:
Sun Jan 17, 2021 8:55 pm
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 :(
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.
I'm on 23 now and still does it..Push 2 logo on the push and ableton says Script could not be loaded

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.

MauriceNorris
Posts: 7
Joined: Wed May 08, 2013 10:51 am
Contact:

Re: Push 2 Scales

Post by MauriceNorris » 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.

torbenscharling
Posts: 35
Joined: Thu Feb 08, 2018 9:29 am

Re: Push 2 Scales

Post by torbenscharling » Thu Jan 21, 2021 2:59 am

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.
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):

# 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, 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 = 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)

MauriceNorris
Posts: 7
Joined: Wed May 08, 2013 10:51 am
Contact:

Re: Push 2 Scales

Post by MauriceNorris » Thu Jan 21, 2021 9:19 am

@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:

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)
 

Post Reply