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

Changes from UTC Sheffield's Algorave Club #270

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion FoxDot/lib/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.8.12
0.8.13
125 changes: 123 additions & 2 deletions FoxDot/lib/Patterns/Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import functools
import inspect
from math import floor

# Decorator functions for nested expansion of pattern functions and methods

Expand Down Expand Up @@ -76,7 +77,7 @@ def ClassPatternMethod(f):
setattr(metaPattern, f.__name__, classmethod(f))
return

# Begin Pattern Abstratct Base Class
# Begin Pattern Abstract Base Class

class metaPattern(object):
""" Abstract base class for Patterns """
Expand Down Expand Up @@ -627,6 +628,126 @@ def shufflets(self, n):
new = self.data[:]
return Pattern([Pattern(new).shuffle().asGroup() for i in range(n)])


'''
bubble_sort written by Dillon Dawson
https://github.com/Dillon-Dawson/MelodyExtFD
Part of his A Level Computer Science Project
'''
def bubble_sort(self, swaps=False, debug = False, palindrome = False):
''' Returns the pattern and each stage of the pattern going through a bubble sort
e.g. `P[50,25,5,20,10].bubble_sort()` will return `P[50,25,5,20,10,25,5,20,10,50,5,20,10,25,50,5,10,20,25,50]`
and `P[50,25,5,20,10].bubble_sort(swaps = True)` will add to the output for every number swap returning `P[50,25,5,20,10,25,50,5,20,10,25,5,50,20,10,25,5,20,50,10,25,5,20,10,50,5,25,20,10,50,5,20,25,10,50,5,20,10,25,50,5,10,20,25,50]`
and `P[0.5 ,2.0 ,1 ,1.5].bubble_sort(palindrome=True)` will also undo the change to smoothly return to the orignal pattern P[0.5, 2.0, 1, 1.5, 0.5, 1, 1.5, 2.0, 0.5, 1, 1.5, 2.0, 0.5, 2.0, 1, 1.5]
'''

items = self.data
changes = passes = 0 # This sets the changes and passes to 0 every time this section is ran.
last = len(items) #lens is a method that returns the length of a list.
swapped = True
output = []
output += items #output = output + items
outputP = []
outputP = items + outputP


while swapped:
swapped = False
passes += 1
for j in range(1, last):
if items[j - 1] > items[j]:
items[j], items[j - 1] = items[j - 1], items[j] # Swap
if swaps == True:
output += items
changes += 1
swapped = True
last = j
if changes == 0:
#raise Warning("Data Presorted")
print("Data Presorted", self.data)
if swapped == True and swaps == False:
output += items
outputP = items + outputP

if palindrome:
output += outputP
if debug == True:
print(output)
return self.new(output)
#return self.__class__(output)


'''
Shell_Sort and original tests written by Dillon Dawson
https://github.com/Dillon-Dawson/MelodyExtFD
Part of his A Level Computer Science Project
'''

def makehalves(self, length):
i = length
list = []
while i>2:
i = floor(i/2)
if(i>1):
list.append(i)
return list

def inssort2(self, items, start, incr):
output = []
outputP = []

for i in range(start+incr, len(items), incr):
j=i
while (j>=incr) and (items[j] < items[j-incr]):
items[j], items[j-incr] = items[j-incr], items[j]
#print("Swapping", items)
output += items
outputP = items + outputP
j-=incr

return(output,outputP)

def shell_sort(self, swaps=False,debug = False, palindrome = False): #This defines the section of the code that does the
''' Returns the pattern and each stage of the pattern going through a shell sort
e.g. `P[50,25,5,20,10].shell_sort()` will return `P[50, 25, 5, 20, 10, 5, 25, 10, 20, 50, 5, 20, 10, 25, 50, 5, 10, 20, 25, 50]`
and `P[50,25,5,20,10].shell_sort(swaps = True)` will add to the output for every number swap returning `P[50,25,5,20,10,5,25,50,20,10,5,25,10,20,50,5,20,10,25,50,5,10,20,25,50]`
and `P[50,25,5,20,10].shell_sort(palindrome=True)` will also undo the change to smoothly return to the orignal pattern P[50, 25, 5, 20, 10, 5, 25, 10, 20, 50, 5, 20, 10, 25, 50, 5, 10, 20, 25, 50,5, 10, 20, 25, 50,5, 20, 10, 25, 50,5, 25, 10, 20, 50,50, 25, 5, 20, 10]
'''
items = self.data
output = []
output += items #output = output + items
outputP = []
outputP = items + outputP

for i in self.makehalves(len(items)):
for j in range(i):
sortoutput, sortoutputP = self.inssort2(items, j, i)
#print("after inssort2(items, "+str(j)+", "+str(i)+")", items)
if swaps == False:
output += items
outputP = items + outputP
if swaps == True:
output += sortoutput
outputP = sortoutputP + outputP
sortoutput, sortoutputP = self.inssort2(items, 0, 1)
#print("After pass at 1", items)
if swaps == False:
output += items
outputP = items + outputP
if swaps == True:
output += sortoutput
outputP = sortoutputP + outputP

if palindrome:
output += outputP

if debug == True:
print("Output",output)

return self.new(output)



# Loop methods

@loop_pattern_method
Expand Down Expand Up @@ -897,7 +1018,7 @@ def startswith(self, prefix):

def all(self, func=(lambda x: bool(x))):
""" Returns true if all of the patterns contents satisfies func(x) - default is nonzero """
if len(self.data) is 0:
if len(self.data) == 0:
return False

for item in self.data:
Expand Down
27 changes: 27 additions & 0 deletions FoxDot/lib/Patterns/Sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,33 @@ def PStrum(n=4):
""" Returns a pattern of durations similar to how you might strum a guitar """
return (Pattern([1,1/2]).stutter([1,n + 1])|Pattern([1.5,1/2]).stutter([1,n])|1)

@loop_pattern_func
def PBase(n, b=2, l=1):
''' Returns the 'n' number in base 'b' split into digits.
e.g. `PBase(5)` will return `P[1,0,1]`
and `PBase(5,4)` will return `P[1,1]`
and `PBase(5,4,4)` will return `P[0,0,1,1]`
'''

number = (0+n) if n>=0 else (abs(n)+b)

from_base10_to_anybase_num = [] # Initialize the number in any base
while number > 0: # Iterate while the number is greater than zero
remainder = int(number % b) # change remainder in integer
#from_base10_to_anybase_num.append( remainder )
from_base10_to_anybase_num.insert(0, remainder )
number //= b # take the integer part after division

number_list = [int(i) for i in from_base10_to_anybase_num]

while(len(number_list) < l):
number_list.insert(0, 0)

#print("from_10_to_anybase("+str(num)+","+str(base)+")", number_list)
Copy link
Owner

Choose a reason for hiding this comment

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

Hey @stretchyboy would you mind doing a quick pass on some of the commented out prints and I can merge this in?

Copy link
Author

Choose a reason for hiding this comment

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

Hi I assume you mean delete them / tidy up? Can I do that in the pull request or do I do another?

Copy link
Owner

Choose a reason for hiding this comment

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

If it's possible to do that in this pull request, that would be great - thanks!


return Pattern( number_list )


def PQuicken(dur=1/2, stepsize=3, steps=6):
""" Returns a PGroup of delay amounts that gradually decrease """
delay = []
Expand Down
19 changes: 19 additions & 0 deletions FoxDot/lib/Players.py
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,25 @@ def __call__(self, *args, **kwargs):
if callable(p):
p.__call__(*args, **kwargs)



def group_method(f):
""" Decorator for assigning functions as Group methods.
If the function name contains "_group" that will be removed while assigning
allowing you to a have a function, a player method and group method all called the same thing

>>> @group_method
... def test(self):
... print(self)

>>> p1.test()
"""
name = f.__name__.replace("_group", "")
setattr(Group, name, f)
return getattr(Group, name)

GroupMethod = group_method # Temporary alias

class rest(object):
''' Represents a rest when used with a Player's `dur` keyword
'''
Expand Down
66 changes: 63 additions & 3 deletions FoxDot/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,18 @@ def __getitem__(self, key):

def player_method(f):
""" Decorator for assigning functions as Player methods.
If the function name contains "_player" that will be removed while assigning
allowing you to a have a function a player method and group method all called the same thing

>>> @player_method
... def test(self):
... print(self.degree)

>>> p1.test()
"""
setattr(Player, f.__name__, f)
return getattr(Player, f.__name__)
name = f.__name__.replace("_player", "")
setattr(Player, name, f)
return getattr(Player, name)

PlayerMethod = player_method # Temporary alias

Expand Down Expand Up @@ -88,7 +91,7 @@ def next_bar(n=0):

nextBar = next_bar # temporary alias

def futureBar(n=0):
def future_bar(n=0):
''' Schedule functions when you define them with @futureBar
Functions will run n bars in the future (0 is the next bar)

Expand All @@ -100,6 +103,63 @@ def futureBar(n=0):
'''
return _futureBarDecorator(n, Clock.bar_length())

futureBar = future_bar # temporary alias

@player_method
def soloBars(self,n=2,end=False):
''' Solo's the current player from the next bar for the specified amount of bars
'''
nextBar(self.solo)
soloEnd = Clock.next_bar() + (n * Clock.bar_length())
Clock.schedule(self.metro.solo.reset, soloEnd)
if(end):
Clock.schedule(self.stop, soloEnd)


@player_method
def soloBeats(self, n=8, end=False):
''' Solo's the current player from now for the specified amount of beats
'''
Clock.schedule(self.solo, Clock.now())
soloEnd = Clock.now() + n
Clock.schedule(self.metro.solo.reset, soloEnd)
if(end):
Clock.schedule(self.stop, soloEnd)


@group_method
def soloBars_group(self,n=2, end=False):
Copy link
Owner

Choose a reason for hiding this comment

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

We could add these to the Group class itself and also add in the clock there. Would that work for you?

Copy link
Author

Choose a reason for hiding this comment

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

I think so, can't remember why it ended up there in the first place.

''' Solo's the current group from the next bar for the specified amount of bars
'''
if self.metro is None:
self.__class__.metro = Player.metro

soloEnd = Clock.next_bar() + (n * Clock.bar_length())
Clock.schedule(self.metro.solo.reset, soloEnd)
if(end):
for player in list(self.metro.playing):
if player in self.players:
Clock.schedule(player.stop, soloEnd)

nextBar(self.solo)

@group_method
def soloBeats_group(self,n=8, end=False):
''' Solo's the current group from now for the specified amount of beats
'''
if self.metro is None:
self.__class__.metro = Player.metro

soloEnd = Clock.now() + n
Clock.schedule(self.metro.solo.reset, soloEnd)
if(end):
for player in list(self.metro.playing):
if player in self.players:
Clock.schedule(player.stop, soloEnd)

Clock.schedule(self.solo, Clock.now())


def update_foxdot_clock(clock):
""" Tells the TimeVar, Player, and MidiIn classes to use
a new instance of TempoClock. """
Expand Down
18 changes: 18 additions & 0 deletions default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{ lib, pkgs ? import <nixpkgs> { } }:
Copy link
Owner

Choose a reason for hiding this comment

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

How do I/we add comments to these files to specify they're required for NixOS?

Copy link
Author

Choose a reason for hiding this comment

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

I will have to ask my NixOS guru on Monday


with pkgs.python310Packages;

buildPythonPackage rec {
name = "FoxDot";
version = "0.1";
src = ./.;
propagatedBuildInputs = [ setuptools wheel tkinter ];
pythonImportsCheck = [ "FoxDot" ];
doCheck = false;

meta = with lib; {
description = "Our FoxDot clone";
homepage = "https://github.com/UTCSheffield/FoxDot";
maintainers = with maintainers; [ devramsean0 ];
};
}
8 changes: 8 additions & 0 deletions shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{ pkgs ? import <nixpkgs> {} }:

with pkgs;

mkShell {
name = "FoxDot";
buildInputs = [ (callPackage ./. {}) ];
}