Exemple #1
0
    def set_length_and_period(self, length=None, period=None):
        """
        cat: edit
        desc: set the length and period of this rhythm. Give 0 for either argument to keep the current value
        args:
            length: length of the rhythm in beats
            period: standard subdivision of this rhythm, in beats
        """
        if length == 0 and self.length is not None:
            pass
        elif length is None:
            p("Enter a length in beats for this Rhythm")
            length = inpt('beats')
            if length != 0:
                self.length = length
            elif self.length is None:
                err_mess(
                    "There is no current value for length, enter a valid value in beats"
                )
                return self.set_length_and_period(None, period)
        else:
            self.length = inpt_validate(length, 'beats')

        if period == 0 and self.period is not None:
            pass
        elif period is None:
            p("Enter the period, or smallest beat that this Rhythm usually lands on",
              h=True)
            self.period = inpt('beat')
        else:
            self.period = inpt_validate(period, "beat")
Exemple #2
0
 def record_live(self):
     """
     record -- but get this -- live!
     """
     section_head("Record mode")
     device_ind, device_name = sd_select_device()
     p("Enter recording duration (in seconds)")
     record_time = inpt('beatsec')
     p('Choose sample rate to record at, in samples per second. Hit enter to use default 44100')
     rate = inpt('int', required=False)
     if rate == '':
         rate = 44100
     self.rate = Units.rate(rate)
     print("  Press Enter to begin recording, or 'q' to quit: ", end="")
     inpt("none", required=False)
     time.sleep(0.05)
     section_head("Recording at input {0} ({1}) for {2}".format(device_ind, \
         device_name, record_time))
     sd.default.channels = 2
     recording = sd.rec(
         ind(record_time * self.rate), 
         self.rate.magnitude, 
         device=device_name)
     sd.wait()
     info_block("Finished recording")
     self.arr = recording
     if len(self.arr.shape) < 2:
         transpose = self.arr.reshape(-1, 1)
         self.arr = np.hstack((transpose, transpose))
     self.source_block = {
         'live recording': "input '{0}'".format(device_name)
     }
Exemple #3
0
    def handle_missing_proj(self, proj_name):
        """
        locate or remove proj, rewrite file
        """
        self.projects[proj_name] = "None"

        p("Locate '{0}'?".format(proj_name), o="y/n")

        located = False
        if inpt("yn"):
            p("Select the project's folder/directory (should be named '{0}.Project'"
              .format(proj_name),
              start="\n")
            try:
                directory = input_dir()
                self.projects[proj_name] = directory
                located = True
            except Cancel:
                pass

        if not located:
            p("Failed to locate. Remove this Project from known projects?",
              o="y/n")
            if inpt("yn"):
                del self.projects[proj_name]

        self.write_proj_file()
Exemple #4
0
    def add_rhythm(self, new_rhythm=None):
        if not isinstance(new_rhythm, Rhythm):
            p("Create new rhythm (C) or Load from another sampler (L)?")
            source = inpt("letter", allowed="cl")
            if source == 'c':
                new_rhythm = Rhythm()
            else:
                # load from sampler
                raise NotImplementedError

        self.rhythms.append(new_rhythm)
        self.list_rhythms()
        p("Process this rhythm? y/n")
        if inpt("yn"):
            process(new_rhythm)
Exemple #5
0
 def rhythms_help(self):
     info_block(
         "Rhythms are made up of multiple beats. Each beat follows the format of " + \
         "<place> <length> <optional: start>, all of which are in beat notation: ",
         trailing_newline=False
     )
     info_block(
         "<place>: the time at which this beat starts within the rhythm. For example" +\
         " 'qn' would mean this beat starts one quarter-note after the beginning of the rhythm",
         trailing_newline=False
     )
     info_block(
         "<length>: how long the snippet of the sample will be. 'qn' would mean it lasts for one quarter-note. " +\
         "no entry, or 0, means that the entire sample will be used",
         trailing_newline=False
     )
     info_block(
         "<start>: an optional parameter, which selects where in the sample to start playback " +\
         "for this one beat, as if trimming it on the front. 'qn' means the beat would begin " +\
         "from one quarter-note in to the sample",
         trailing_newline=False
     )
     print("        3q 1q")
     info_block(
         "will create a beat that start on the third quarter of the rhythm, and" + \
         "lasts for one quarter note"
     )
     p("Do you need info on how to create properly formed beats?", o="y/n")
     if inpt('yn'):
         beat_options()
Exemple #6
0
def process_validate(command, obj):
    """
    check command as valid or one of the shortcuts
    return True on valid
    """
    if command == []:
        err_mess("No command entered")
        command = "None"
    elif command == ['']:
        err_mess(
            "Only alphanumeric characters, spaces, and underscores are allowed"
        )
    elif command[0] in ("q", "quit"):
        p("Save before exiting?")
        if inpt("yn"):
            obj.save()
        info_block("Exiting processing of {0} '{1}'...".format(
            obj.reltype, obj.name))
        raise Cancel(obj)
    elif command[0] in ("o", "options"):
        obj.options()
    elif command[0] in ("h", "help"):
        pass  # callback handled during inpt()
    else:
        return True
    return False
Exemple #7
0
def process(obj):
    """
    process an object.
    'self.name', 'self.reltype' required.
    """
    section_head("Processing {0} '{1}'".format(obj.reltype, obj.name))

    while True:

        try:
            obj.process_message()
        except AttributeError:
            pass

        with style("cyan, bold"):
            print("\n{0} ".format(RelGlobals.get_process_num()), end="")
        p("What process to run on {0} '{1}'?".format(obj.reltype, obj.name),
          h=True,
          o="'o' to view process options",
          indent=0,
          hang=4,
          leading_newline=False)

        try:
            command = inpt(mode='split',
                           split_modes='arg',
                           help_callback=processes_help)
            if process_validate(command, obj):
                do_command(command, obj)
        except Cancel:
            return
Exemple #8
0
    def init_mode(self):
        """
        fill in initialization via input
        get recording by mode
        call get_help/playback if asked
        returns rec array
        """
        valid_modes = (
            "live Record (R)", 
            "read from File (F)", 
            "relativism project or sampler Object (O)", 
            "Help (H)"
        )
        info_title("Available modes:")
        info_list(valid_modes)
        p("Enter desired mode's letter")
        mode = inpt('letter', allowed='rfh')

        # Record Mode
        if mode == "r":
            self.record_live()
        # File Mode
        elif mode == "f":
            self.read_file()
        elif mode == "o":
            raise NotImplementedError
        # Help
        elif mode == "h":
            raise NotImplementedError
Exemple #9
0
def sd_select_device(device_type='in'):
    """
    type: in or out
    returns [index, name] of device
    """
    info_title("Devices by index ({0} found):".format(len(sd.query_devices())))
    for i in str(sd.query_devices()).split('\n'):
        info_line(i)
    while True:
        p("Enter desired device index")
        device_ind = inpt('int')
        try:
            device = sd.query_devices()[device_ind]
        except IndexError:
            err_mess("No device with index {0}".format(device_ind))
            continue
        if device_type in ('in', 'input'):
            if device['max_input_channels'] < 1:
                err_mess("Device cannot be used as an input")
                continue
        elif device_type in ('out', 'output'):
            if device['max_output_channels'] < 1:
                err_mess("Device cannot be used as an output")
        device_name = device['name']
        info_block("'{0}' selected".format(device_name))
        return [device_ind, device_name]
Exemple #10
0
 def process_child(self, child_name=None):
     """
     cat: edit
     desc: edit a child member of this object
     args:
         [child_name: name of child to edit, omit to list children]
     """
     if len(self.children) == 0:
         err_mess("This Project has no children to process!")
     if child_name is None:
         self.list_children()
         p("Enter the name of the child you wish to edit")
         child_name = inpt("name")
     else:
         child_name = inpt_validate(child_name, "name")
     try:
         child_name = autofill(child_name, [i.name for i in self.children])
     except AutofillError as e:
         err_mess("Child name '{0}' not found".format(e.word))
         self.process_child()
         return
     child = None
     for i in self.children:
         if i.name == child_name:
             if child is not None:
                 raise UnexpectedIssue("Multiple children with name {0}".format(child_name))
             child = i
     process(child)
     child.save()
Exemple #11
0
 def rename(self, name=None):
     if name is None:
         print("  Give this active pair a name: ", end="")
         name = inpt("obj")
         print("  named '{0}'".format(name))
     else:
         name = inpt_validate(name, "obj")
     self.name = name
Exemple #12
0
 def validate_change_type(self, change_type):
     if change_type is None:
         return self.change_type_options[0]
     while change_type not in self.valid_change_types:
         err_mess("Invalid change type '{0}'".format(change_type))
         p("Select one of: {0}".format(", ".join(self.valid_change_types)))
         change_type = inpt('alphanum')
     return change_type
Exemple #13
0
 def add_child(self, child):
     """
     backend of add_x processes
     """
     self.children.append(child)
     self.save_metadata()
     p("Process new {0} '{1}'? [y/n]".format(child.reltype, child.name))
     if inpt("yn"):
         self.process_child(child.name)
Exemple #14
0
    def rename(self, name=None):
        """
        cat: meta
        dev: call this method via super, and implement renaming of files other than 
        datafile and its self.path directory
        """
        old_name = self.name
        if old_name is not None:
            old_data_dir = self.get_data_dir()
            old_datafile_name = self.get_data_filename()

        if name is None:
            p("Give this {0} a name".format(self.reltype))
            name = inpt("obj")
        else:
            name = inpt_validate(name, 'obj')

        # validate
        if hasattr(self.parent, "validate_child_name"):
            if self.parent.validate_child_name(self, name):
                self.name = name
                info_block("Named '{0}'".format(name))
            else:
                err_mess("Invalid name")
                self.rename()
        else:
            if Settings.is_debug():
                show_error(
                    AttributeError(
                        "Parent obj '{0}' does not have validate_child_name".
                        format(self.parent)))
            else:
                try:
                    log_err(
                        "Parent object type {0} has no 'validate_child_name' method"
                        .format(self.parent.reltype))
                except AttributeError:
                    log_err(
                        "Parent object '{0}' of '{1}' has no 'validate_child_name' method"
                        .format(self.parent, self))
            self.name = name
            info_block("Named '{0}'".format(name))

        # if actual renaming and not an initial naming
        if old_name is not None:
            new_data_dir = self.get_data_dir()
            # rename dir
            os.rename(old_data_dir, new_data_dir)

            # rename datafile (which is in newdatadir now)
            old_datafile = join_path(new_data_dir,
                                     old_datafile_name,
                                     ext=self.datafile_extension)
            new_datafile = self.get_datafile_fullpath()
            os.rename(old_datafile, new_datafile)
Exemple #15
0
def complete_args(e, method_name, args, obj):
    """
    handle wrong number of args
    """
    if method_name not in str(e):
        show_error(e)
    err_mess("Wrong number of arguments: {0}".format(str(e)))
    info_title("Arguments for {0}: ".format(method_name), indent=4)
    obj.get_process(method_name)._rel_data.display_args()
    # too many
    command_str = "\n      " + method_name + " "
    if "were given" in str(e):
        p("Enter intended arguments", start=command_str)
        new_args = inpt('split', 'arg')
        return [method_name] + new_args
    # not enough
    else:
        if len(args) > 0:
            command_str += " ".join(args) + " "
        p("Complete arguments", start=command_str)
        new_args = inpt('split', 'arg')
        return [method_name] + args + new_args
Exemple #16
0
 def generate(self, reps=None):
     """
     desc: generate variable sampler output
     args:
         active name: name of active pair to generate
         reps: number of repetitions of active rhythm to generate
     """
     length = samps(inpt('beats'), RelGlobals.DEFAULT_SAMPLERATE)
     recs = []
     for a in self.active:
         if not a.muted:
             recs.append(a.generate_active(length))
     mixed = mix_multiple(recs)
     mixed.playback()
Exemple #17
0
    def open_proj(self):
        """
        desc: open a project
        """
        section_head("Opening Project")

        self.list_projects()
        p("Enter name of project you want to open, or 'see <name>' to see info about that project"
          )
        name_input = inpt("split", "obj")
        see = False
        if name_input[0] == "see":
            try:
                proj_name = name_input[1]
            except IndexError:
                err_mess("No name provided to 'see'")
                self.open_proj()
                return
            see = True
        else:
            proj_name = name_input[0]

        try:
            proj_path = self.projects[proj_name]
        except KeyError:
            try:
                proj_name = autofill(proj_name, self.projects.keys(), "name")
            except AutofillError as e:
                err_mess("No project matches name '{0}'".format(e.word))
                return
            proj_path = self.projects[proj_name]

        if proj_path == "None":
            err_mess("Project {0} is missing".format(proj_name))
            self.handle_missing_proj(proj_name)
            return

        if see:
            self.see_proj(proj_name, proj_path)
            self.open_proj()
            return

        try:
            loader = ProjectLoader("{0}.Project".format(proj_name), proj_path,
                                   self)
            self.current_open_proj = loader.get_proj()
        except FileNotFoundError as e:
            err_mess("File Not Found: '{0}'".format(e.filename))
            self.handle_missing_proj(proj_name)
            return
Exemple #18
0
    def __init__(self,
                 name,
                 val_units,
                 time_units="beats",
                 val_allowed=None,
                 time_allowed=None,
                 start=None,
                 reltype="Controller",
                 rel_id=None,
                 path=None,
                 markers=None,
                 parent=None,
                 mode="create",
                 **kwargs):
        super().__init__(rel_id=rel_id,
                         reltype=reltype,
                         name=name,
                         path=path,
                         parent=parent,
                         mode=mode,
                         **kwargs)

        self.start = start
        self.markers = {} if markers is None else markers  # {sample_ind : ControllerMarker}

        if time_units is None or time_units not in ("beat", "beats", "sec",
                                                    "secs", "second",
                                                    "seconds"):
            p("Select the timing units to be used for this controller, 'b' for beats notation (recommended), 's' for seconds"
              )
            time_mode = inpt("letter", allowed="bs")
            if time_mode == "b":
                time_units = "beats"
            else:
                time_units = "secs"
        self.time_units = time_units
        self.val_units = val_units
        self.val_allowed = val_allowed
        self.time_allowed = (Units.beats("0b"), None)

        desc = get_reldata(self.add, "desc")
        try:
            new_desc = desc.format(val_units=self.val_units,
                                   time_units=time_units)
        except:
            # if format fails, it means add docstring is overridden somewhere,
            # and will be handled there
            pass
        else:
            add_reldata(self.add, "desc", new_desc)
Exemple #19
0
 def choose(self, attr, name=None):
     """
     get an object from attribute ('sample', 'rhythm', or 'active') by name
     """
     if attr == 'active':
         if name is None:
             if self.list_active() is False:
                 return
             print("  : ", end="")
             name = inpt('name')
         for i in self.active:
             if i.get_name() == name:
                 return i
         print("  > Name doesnt exist. Enter intended value (q to quit): ")
         return self.choose(attr)
     elif attr == "sample":
         if name is None:
             if self.list_samples() is False:
                 return
             print("  : ", end="")
             name = inpt('name')
         for i in self.smps:
             if i.get_name() == name:
                 return i
         print("  > Name doesnt exist. Enter intended value (q to quit): ")
         return self.choose(attr)
     elif attr == "rhythm":
         if name is None:
             if self.list_rhythms() is False:
                 return
             print("  : ", end="")
             name = inpt('name')
         for i in self.rhythms:
             if i.get_name() == name:
                 return i
         print("  > Name doesnt exist. Enter intended value (q to quit): ")
         return self.choose(attr)
Exemple #20
0
 def add_sample(self, new_samp=None):
     """
     desc: add a sample from file, project, or another sampler
     cat: edit
     """
     if isinstance(new_samp, Recording):
         new_samp.reltype = "Sample"
     else:
         new_samp = Recording(reltype="Sample", parent=self)
     self.smps.append(new_samp)
     self.list_samples()
     nl()
     p("Process this sample? y/n")
     if inpt("yn"):
         process(new_samp)
Exemple #21
0
 def main_menu(self):
     while True:
         section_head("Relativism Main Menu")
         p("Would you like to edit Projects (P), Settings (S), or get Help (H)?"
           )
         choice = inpt("letter", allowed="psh")
         try:
             if choice == "p":
                 self.projects_menu()
             elif choice == "s":
                 self.settings_menu()
             else:
                 self.help_menu()
         except Cancel:
             pass
Exemple #22
0
 def process_child_sample(self, name=None):
     """
     desc: process a sample contained in this group
     """
     while True:
         if name is None:
             self.list_samples()
             p("Enter the name of the Sample to process")
             name = inpt('name')
         else:
             name = inpt_validate(name, 'name')
         try:
             self.samples[name]
             break
         except KeyError:
             err_mess("> Sample '{0}' does not exist!".format(name))
     process(self.samples[name])
Exemple #23
0
 def export_to_wav(self, outfile=None):
     """
     cat: save
     desc: save recording to wav file
     args:
         outfile: filename to save to. do not include '.wav' or any other extention
     """
     section_head("Writing to file")
     if outfile is None:
         print("  Enter output file name: ", end="")
         outfile = inpt("file")
     try:
         info_line("writing...")
         t1 = time.time()
         self.write_audio(outfile)
         t2 = time.time()
         info_line("written successfully in {0:.4f} seconds".format(t2 - t1))
     except TypeError as e:
         print("  > Failed to write to file '{0}': {1}".format(outfile, e))
Exemple #24
0
 def process():
     section_head("Editing User Settings")
     method_strs = [func for func in dir(Settings) if "__" not in func and 
         is_public_process(getattr(Settings, func))]
     while True:
         info_title("Available processes:")
         info_list(method_strs)
         p("What process to run?")
         proc = inpt("alphanum")
         try:
             proc = autofill(proc, method_strs)
             method = getattr(Settings, proc)
             if is_public_process(method):
                 method()
             else:
                 raise AttributeError
         except AutofillError as e:
             err_mess("No process matches '{0}'!".format(e.word))
         except AttributeError:
             err_mess("No process matches '{0}'!".format(proc))
Exemple #25
0
    def __init__(self,
                 parent,
                 path,
                 act_rhythm,
                 act_sample,
                 reltype=None,
                 name=None,
                 rel_id=None,
                 muted=None):

        super().__init__(rel_id, reltype, name, path, parent)
        print("\n* Initializing active pair")
        self.reltype = "ActivePair"
        self.rhythm = act_rhythm
        self.sample = act_sample
        self.muted = muted
        self.variability = Active.Variability()
        if name is None:
            self.rename()
        if muted is None:
            p("Should this active pair begin muted?", o='y/n')
            self.muted = inpt('yn')
Exemple #26
0
 def trim(self, left, right=None):
     """
     cat: edit
     desc: trim to only contain audio between <left> and <right>
     args:
         left: beat/second; 0, 5;
         [right: beat/second. defaults to end; 10, 20;]
     """
     left = inpt_validate(left, 'beatsec')
     if right is None:
         print("  trimming first {0}".format(left))
         right = self.size_samps()
     else:
         right = inpt_validate(right, 'beatsec')
         print("  trimming everything outside {0} to {1}".format(left, right))
     left, right = left.to_secs(), right.to_secs()
     if left * self.rate > self.size_samps():
         print("  > this will empty the recording, confirm? [y/n]: ", end="")
         if not inpt("yn"):
             return
         self.arr = np.empty(shape=(0,2))
     else:
         self.arr = self.arr[ind(left * self.rate) : ind(right * self.rate)]  
Exemple #27
0
    def projects_menu(self):
        """
        top menu for opening or creating projects
        """
        while True:
            section_head("Projects Menu")

            # choose open type: open or create
            while self.current_open_proj is None:
                if bool(self.projects):
                    p("Open existing project (O) or Create new (C)?")
                    open_or_create = inpt("letter", allowed="oc")

                    if open_or_create == 'c':
                        self.create_proj()
                    else:
                        self.open_proj()
                else:
                    info_block(
                        "No existing projects. Defaulting to create new")
                    self.create_proj()

            self.process_project()
Exemple #28
0
    def add_beats(self):
        """
        dev: create beats through prompts or pass 'beat' param to set (??)
        """
        info_block("Creating new Rhythm '{0}'".format(self.name))
        while True:
            info_block(
                "Enter a beat as <place in rhythm> <optional: length> ('q' to finish, 'i' for more info)",
                indent=2,
                hang=2,
                trailing_newline=False)
            print("  : ", end="")
            try:
                new_beat = inpt("split",
                                "beat",
                                help_callback=self.rhythms_help)
            except Cancel:
                info_block("Finished creating Rhythm '{0}'".format(self.name))
                return
            if not (1 <= len(new_beat) <= 2):
                err_mess(
                    "Wrong number of arguments! From 1 to 2 are required, {0} were supplied"
                    .format(len(new_beat)))
                continue
            if secs(new_beat[0]) >= secs(str(self.length) + 'b'):
                err_mess(
                    "This beat begins after the end of the rhythm! Try again")
                continue

            self.beats.append(new_beat)

            while len(new_beat) < 3:
                new_beat.append(0)
            if new_beat[1] == 0:
                new_beat[1] = "all"
            info_line("  Added beat - " + self.beat_repr(new_beat))
Exemple #29
0
 def maybe_playback(self):
     p("Playback before analyzing? [y/n]")
     if inpt("yn"):
         self.obj.playback()
Exemple #30
0
 def set_variability(self, var=None):
     if var is None:
         p("Enter the variability (in percentage, 0-100%) of this Rhythm")
         self.variability = inpt('pcnt')
     else:
         self.variability = inpt_validate(var, 'pcnt')