Add custom scale to push?

Discuss Push with other users.
Warmonger
Posts: 130
Joined: Wed Aug 01, 2007 7:02 pm
Location: Warsaw, Poland
Contact:

Add custom scale to push?

Post by Warmonger » Tue Oct 03, 2017 1:29 pm

I would like to add my own scale to Push 1. Know there WAS such a feature, but somehow Google is not helpful this time. Any tips?

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

Re: Add custom scale to push?

Post by [jur] » Tue Oct 03, 2017 3:42 pm

Ableton Forum Moderator

8E
Posts: 392
Joined: Sun May 05, 2013 11:25 am
Location: +ICXC·NIKA+

Re: Add custom scale to push?

Post by 8E » Tue Oct 03, 2017 8:38 pm

Warmonger wrote:I would like to add my own scale to Push 1. Know there WAS such a feature, but somehow Google is not helpful this time. Any tips?
Yes.

I have a pyc file that you need to edit by your wish.

Works good on my Push 1.

filename: melodic_pattern.py

Code: Select all

# ressources-> midi remotescripts -> pushbase            Embedded file name: /Users/versonator/Jenkins/live/output/mac_64_static/Release/python-bundle/MIDI Remote Scripts/pushbase/melodic_pattern.py
from __future__ import absolute_import, print_function
from ableton.v2.base import NamedTuple, lazy_attribute, memoize, find_if
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 = (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')


SCALES = (Scale(name='Major', notes=[0,
  2,
  4,
  5,
  7,
  9,
  11]),
 Scale(name='Minor', notes=[0,
  2,
  3,
  5,
  7,
  8,
  10]),
 Scale(name='Dorian', notes=[0,
  2,
  3,
  5,
  7,
  9,
  10]),
 Scale(name='Mixolydian', notes=[0,
  2,
  4,
  5,
  7,
  9,
  10]),
 Scale(name='Lydian', notes=[0,
  2,
  4,
  6,
  7,
  9,
  11]),
 Scale(name='Phrygian', notes=[0,
  1,
  3,
  5,
  7,
  8,
  10]),
 Scale(name='Locrian', notes=[0,
  1,
  3,
  5,
  6,
  8,
  10]),
 Scale(name='Diminished', notes=[0,
  1,
  3,
  4,
  6,
  7,
  9,
  10]),
 Scale(name='Whole-half', notes=[0,
  2,
  3,
  5,
  6,
  8,
  9,
  11]),
 Scale(name='Whole Tone', notes=[0,
  2,
  4,
  6,
  8,
  10]),
 Scale(name='Minor Pentatonic', notes=[0,
  3,
  5,
  7,
  10]),
 Scale(name='Major Pentatonic', notes=[0,
  2,
  4,
  7,
  9]),
 Scale(name='Harmonic Minor', notes=[0,
  2,
  3,
  5,
  7,
  8,
  11]),
 Scale(name='Melodic Minor', notes=[0,
  2,
  3,
  5,
  7,
  9,
  11]),
 Scale(name='Super Locrian', notes=[0,
  1,
  3,
  4,
  6,
  8,
  10]),
 Scale(name='Bhairav', notes=[0,
  1,
  4,
  5,
  7,
  8,
  11]),
 Scale(name='Hungarian Minor', notes=[0,
  2,
  3,
  6,
  7,
  8,
  11]),
 Scale(name='Minor Gypsy', notes=[0,
  1,
  4,
  5,
  7,
  8,
  10]),
 Scale(name='Persian', notes=[0,
  1,
  4,
  5,
  6,
  8,
  11]),
 Scale(name='Acoustic', notes=[0,
  2,
  4,
  6,
  7,
  9,
  10]),
 Scale(name='Algerian-9', notes=[0,
  2,
  3,
  6,
  7,
  8,
  11]),
 Scale(name='Altered', notes=[0,
  1,
  3,
  4,
  6,
  8,
  10]),
 Scale(name='Spanish', notes=[0,
  1,
  3,
  4,
  5,
  6,
  8,
  10]))

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

    @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):
        return self._get_note_info(self._octave_and_note(x, y), self.root_note, x + FEEDBACK_CHANNELS[0])

    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 _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'
        elif note in self.scale:
            return 'NoteScale'
        else:
            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)
MacOS Mojave MacBook Pro (15", Mid 2015), 2,5 GHz i7, 16GB RAM
Live Suite 10-latest + Push 1
U-PHORIA UMC204HD

Warmonger
Posts: 130
Joined: Wed Aug 01, 2007 7:02 pm
Location: Warsaw, Poland
Contact:

Re: Add custom scale to push?

Post by Warmonger » Wed Oct 04, 2017 8:50 pm

Okay, but what do I do with this file?

The link reads:
– BACKUP the whole Push folder with all *.pyc files
On Win, backup the whole folder “C:\Program Files\Ableton\Live x.x.x\Resources\MIDI Remote Scripts”
– Alter a file in the python sources provided on github
– Take that .py file and put it in he Push folder in your Live folders (check the correct folder above)
Remove the corresponding .pyc in the Live folder and restart Live Then it should work. In order to debug, that’s not hard (I mean to check a debug log, not to debug actually)
There is no "melodic_patter.pyc or "consts.pyc" to remove. If I try to remove all the .pyc files and use whole Push folder from git, only two .pyc files are rebuilt and it doesn't work.
Last edited by Warmonger on Sun Oct 08, 2017 10:13 am, edited 1 time in total.

8E
Posts: 392
Joined: Sun May 05, 2013 11:25 am
Location: +ICXC·NIKA+

Re: Add custom scale to push?

Post by 8E » Wed Oct 04, 2017 9:01 pm

Warmonger wrote:Okay, but what do I do with this file?

The link reads:
– BACKUP the whole Push folder with all *.pyc files
On Win, backup the whole folder “C:\Program Files\Ableton\Live x.x.x\Resources\MIDI Remote Scripts”
– Alter a file in the python sources provided on github
– Take that .py file and put it in he Push folder in your Live folders (check the correct folder above)
Remove the corresponding .pyc in the Live folder and restart Live Then it should work. In order to debug, that’s not hard (I mean to check a debug log, not to debug actually)
There is no "melodic_patter.pyc or "consts.pyc" to remove. If I try to remove all the .pyc files and use whole Push folder from git, only two .pyc filesare rebuilt and it doesn't work.
Save this text as py file.
Remove the original pyc file.
Add this into -> MIDI Remote Scripts -> pushbase
I am not sure where it is located in Windows, but the folder is pushbase, inside of MIDI Remote Scripts.
MacOS Mojave MacBook Pro (15", Mid 2015), 2,5 GHz i7, 16GB RAM
Live Suite 10-latest + Push 1
U-PHORIA UMC204HD

Warmonger
Posts: 130
Joined: Wed Aug 01, 2007 7:02 pm
Location: Warsaw, Poland
Contact:

Re: Add custom scale to push?

Post by Warmonger » Thu Oct 05, 2017 5:10 am

It works! Thanks.

Looks like the sources on git are severly outdated and not relevant anymore.

aragoto
Posts: 2
Joined: Thu Feb 15, 2018 4:02 pm

Re: Add custom scale to push?

Post by aragoto » Thu Feb 15, 2018 4:21 pm

I came across this thread via Google, hence being a bit late to the game. I've just started working through Nicolas Slonimsky's "Thesaurus of Scales and Melodic Patterns" and was wondering how to customize Push scales to try out some of the examples.

This leads to my additional question: Many of Slonimsky's progressions span more than one octave. Would adding one of these require modifications to the script below, or is it possible to specify a scale that spans two octaves by adding notes between 0 and 23, for example?

Thanks for any advice!

8E
Posts: 392
Joined: Sun May 05, 2013 11:25 am
Location: +ICXC·NIKA+

Re: Add custom scale to push?

Post by 8E » Thu Feb 15, 2018 6:46 pm

aragoto wrote:I came across this thread via Google, hence being a bit late to the game. I've just started working through Nicolas Slonimsky's "Thesaurus of Scales and Melodic Patterns" and was wondering how to customize Push scales to try out some of the examples.

This leads to my additional question: Many of Slonimsky's progressions span more than one octave. Would adding one of these require modifications to the script below, or is it possible to specify a scale that spans two octaves by adding notes between 0 and 23, for example?

Thanks for any advice!
Interesting. Are you a classical composer?

I have never heard about that book but sounds very interesting.

I am not sure about your question, but I believe it is not possible to edit the octavization of the Push. You can try to edit above script by adding an additional number, such as 13, 14...

But to give another approach: try to use a rack of scales, so that you apply numerous scales (complete or limited) to the key ranges. That would work I guess.
MacOS Mojave MacBook Pro (15", Mid 2015), 2,5 GHz i7, 16GB RAM
Live Suite 10-latest + Push 1
U-PHORIA UMC204HD

aragoto
Posts: 2
Joined: Thu Feb 15, 2018 4:02 pm

Re: Add custom scale to push?

Post by aragoto » Fri Feb 16, 2018 12:53 am

Interesting. Are you a classical composer?
No, just curious! I was actually turned onto the book by a Quincy Jones interview where he mentions that John Coltrane carried the book around "till the pages fell off": http://www.vulture.com/2018/02/quincy-j ... ation.html
But to give another approach: try to use a rack of scales, so that you apply numerous scales (complete or limited) to the key ranges. That would work I guess.
Just to be clear here - when you say a "rack of scales", is it possible to define this in the Push settings, or are you suggesting changing manually between scales depending on the key range?

8E
Posts: 392
Joined: Sun May 05, 2013 11:25 am
Location: +ICXC·NIKA+

Re: Add custom scale to push?

Post by 8E » Fri Feb 16, 2018 12:27 pm

aragoto wrote:Just to be clear here - when you say a "rack of scales", is it possible to define this in the Push settings, or are you suggesting changing manually between scales depending on the key range?
That is defined outside of Push.

It is just a MIDI rack with scales inside of Live. Of course, once you manually edit that, it is automatised.

And of course, you can use whatever keyboard attached to Live, not only Push, and your scale system will work.
MacOS Mojave MacBook Pro (15", Mid 2015), 2,5 GHz i7, 16GB RAM
Live Suite 10-latest + Push 1
U-PHORIA UMC204HD

8E
Posts: 392
Joined: Sun May 05, 2013 11:25 am
Location: +ICXC·NIKA+

Re: Add custom scale to push?

Post by 8E » Sat Feb 17, 2018 7:59 pm

You might try to edit the span of the octavization in the code above. I don't guarantee that it will work. I don't think you can break anything, but backup your settings folder.
Try to edit all 12 to, for example, 20 to see if it will work. For instance here:

Code: Select all

class MelodicPattern(NamedTuple):
    steps = [0, 0]
    scale = range(12)
    root_note = 0
    origin = [0, 0]
    chromatic_mode = False
MacOS Mojave MacBook Pro (15", Mid 2015), 2,5 GHz i7, 16GB RAM
Live Suite 10-latest + Push 1
U-PHORIA UMC204HD

8E
Posts: 392
Joined: Sun May 05, 2013 11:25 am
Location: +ICXC·NIKA+

Re: Add custom scale to push?

Post by 8E » Wed Feb 28, 2018 3:43 pm

I have got help from a friend to decompile "melodic_pattern" that is found in version 9.7.5
Here is the code, it seems to be different than previous.

Code: Select all

# uncompyle6 version 3.0.0
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.10 (default, Jul 15 2017, 17:16:57) 
# [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)]
# Embedded file name: /Users/versonator/Jenkins/live/output/mac_64_static/Release/python-bundle/MIDI Remote Scripts/pushbase/melodic_pattern.py
# Compiled at: 2017-10-03 05:03:15
from __future__ import absolute_import, print_function
from ableton.v2.base import NamedTuple, lazy_attribute, memoize, find_if
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 = (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')


SCALES = (
 Scale(name='Major', notes=[0, 2, 4, 5, 7, 9, 11]),
 Scale(name='Minor', notes=[0, 2, 3, 5, 7, 8, 10]),
 Scale(name='Dorian', notes=[0, 2, 3, 5, 7, 9, 10]),
 Scale(name='Mixolydian', notes=[0, 2, 4, 5, 7, 9, 10]),
 Scale(name='Lydian', notes=[0, 2, 4, 6, 7, 9, 11]),
 Scale(name='Phrygian', notes=[0, 1, 3, 5, 7, 8, 10]),
 Scale(name='Locrian', notes=[0, 1, 3, 5, 6, 8, 10]),
 Scale(name='Diminished', notes=[0, 1, 3, 4, 6, 7, 9, 10]),
 Scale(name='Whole-half', notes=[0, 2, 3, 5, 6, 8, 9, 11]),
 Scale(name='Whole Tone', notes=[0, 2, 4, 6, 8, 10]),
 Scale(name='Minor Blues', notes=[0, 3, 5, 6, 7, 10]),
 Scale(name='Minor Pentatonic', notes=[0, 3, 5, 7, 10]),
 Scale(name='Major Pentatonic', notes=[0, 2, 4, 7, 9]),
 Scale(name='Harmonic Minor', notes=[0, 2, 3, 5, 7, 8, 11]),
 Scale(name='Melodic Minor', notes=[0, 2, 3, 5, 7, 9, 11]),
 Scale(name='Super Locrian', notes=[0, 1, 3, 4, 6, 8, 10]),
 Scale(name='Bhairav', notes=[0, 1, 4, 5, 7, 8, 11]),
 Scale(name='Hungarian Minor', notes=[0, 2, 3, 6, 7, 8, 11]),
 Scale(name='Minor Gypsy', notes=[0, 1, 4, 5, 7, 8, 10]),
 Scale(name='Hirojoshi', notes=[0, 2, 3, 7, 8]),
 Scale(name='In-Sen', notes=[0, 1, 5, 7, 10]),
 Scale(name='Iwato', notes=[0, 1, 5, 6, 10]),
 Scale(name='Kumoi', notes=[0, 2, 3, 7, 9]),
 Scale(name='Pelog', notes=[0, 1, 3, 4, 7, 8]),
 Scale(name='Spanish', notes=[0, 1, 3, 4, 5, 6, 8, 10]))

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)
        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):
            return self._get_note_info(self._octave_and_note(x, y), self.root_note, x + FEEDBACK_CHANNELS[0])
        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'
        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))
        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)
# okay decompiling /users/daw/Downloads/melodic_pattern.pyc
Anyone willing to test, please give the feedback.
MacOS Mojave MacBook Pro (15", Mid 2015), 2,5 GHz i7, 16GB RAM
Live Suite 10-latest + Push 1
U-PHORIA UMC204HD

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

Re: Add custom scale to push?

Post by MauriceNorris » Thu Jun 14, 2018 10:30 am

Seems to have changed again in Live 10. Here's another decompiled 'melodic_pattern'. Tested and working in Live 10.0.2 with Push 2:

Code: Select all

# Embedded file name: /Users/versonator/Jenkins/live/output/mac_64_static/Release/python-bundle/MIDI Remote Scripts/pushbase/melodic_pattern.py
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
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 = u''
    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(u'utf-8')


SCALES = (Scale(name=u'Major', notes=[0,
  2,
  4,
  5,
  7,
  9,
  11]),
 Scale(name=u'Minor', notes=[0,
  2,
  3,
  5,
  7,
  8,
  10]),
 Scale(name=u'Dorian', notes=[0,
  2,
  3,
  5,
  7,
  9,
  10]),
 Scale(name=u'Mixolydian', notes=[0,
  2,
  4,
  5,
  7,
  9,
  10]),
 Scale(name=u'Lydian', notes=[0,
  2,
  4,
  6,
  7,
  9,
  11]),
 Scale(name=u'Phrygian', notes=[0,
  1,
  3,
  5,
  7,
  8,
  10]),
 Scale(name=u'Locrian', notes=[0,
  1,
  3,
  5,
  6,
  8,
  10]),
 Scale(name=u'Diminished', notes=[0,
  1,
  3,
  4,
  6,
  7,
  9,
  10]),
 Scale(name=u'Whole-half', notes=[0,
  2,
  3,
  5,
  6,
  8,
  9,
  11]),
 Scale(name=u'Whole Tone', notes=[0,
  2,
  4,
  6,
  8,
  10]),
 Scale(name=u'Minor Blues', notes=[0,
  3,
  5,
  6,
  7,
  10]),
 Scale(name=u'Minor Pentatonic', notes=[0,
  3,
  5,
  7,
  10]),
 Scale(name=u'Major Pentatonic', notes=[0,
  2,
  4,
  7,
  9]),
 Scale(name=u'Harmonic Minor', notes=[0,
  2,
  3,
  5,
  7,
  8,
  11]),
 Scale(name=u'Melodic Minor', notes=[0,
  2,
  3,
  5,
  7,
  9,
  11]),
 Scale(name=u'Super Locrian', notes=[0,
  1,
  3,
  4,
  6,
  8,
  10]),
 Scale(name=u'Bhairav', notes=[0,
  1,
  4,
  5,
  7,
  8,
  11]),
 Scale(name=u'Hungarian Minor', notes=[0,
  2,
  3,
  6,
  7,
  8,
  11]),
 Scale(name=u'Minor Gypsy', notes=[0,
  1,
  4,
  5,
  7,
  8,
  10]),
 Scale(name=u'Hirojoshi', notes=[0,
  2,
  3,
  7,
  8]),
 Scale(name=u'In-Sen', notes=[0,
  1,
  5,
  7,
  10]),
 Scale(name=u'Iwato', notes=[0,
  1,
  5,
  6,
  10]),
 Scale(name=u'Kumoi', notes=[0,
  2,
  3,
  7,
  9]),
 Scale(name=u'Pelog', notes=[0,
  1,
  3,
  4,
  7,
  8]),
 Scale(name=u'Spanish', notes=[0,
  1,
  3,
  4,
  5,
  6,
  8,
  10]))

def scale_by_name(name):
    return find_if(lambda m: m.name == name, SCALES)


class NoteInfo(NamedTuple):
    index = None
    channel = 0
    color = u'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 u'NoteBase'
        elif note in self.scale:
            return u'NoteScale'
        else:
            return u'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)

Stromkraft
Posts: 7033
Joined: Wed Jun 25, 2014 11:34 am

Re: Add custom scale to push?

Post by Stromkraft » Thu Jun 14, 2018 6:31 pm

Thank you @MauriceNorris!
Make some music!

roesenthaller
Posts: 9
Joined: Fri Apr 06, 2018 4:41 pm

Re: Add custom scale to push?

Post by roesenthaller » Sat Jul 21, 2018 6:21 pm

Hi Sorry, but could you explain to a complete novice/layperson what I need to do to implement this?

What do i need to edit the .py file and save it in the correct format? The Python application?


I'm am trying to figure out how to lay out pads in Piano configuration like this, would really appreciate any help:

Image

Post Reply