algorithms/asa.py
def _form_onset_offset_fronts(ons_or_offs, sample_rate_hz, threshold_ms=20):
    """
    Takes an array of onsets or offsets (shape = [nfrequencies, nsamples], where a 1 corresponds to an on/offset,
    and samples are 0 otherwise), and returns a new array of the same shape, where each 1 has been replaced by
    either a 0, if the on/offset has been discarded, or a non-zero positive integer, such that
    each front within the array has a unique ID - for example, all 2s in the array will be the front for on/offset
    front 2, and all the 15s will be the front for on/offset front 15, etc.

    Due to implementation details, there will be no 1 IDs.
    """
    threshold_s = threshold_ms / 1000
    threshold_samples = sample_rate_hz * threshold_s

    ons_or_offs = np.copy(ons_or_offs)

    claimed = []
    this_id = 2
    # For each frequency,
    for frequency_index, row in enumerate(ons_or_offs[:, :]):
        ones = np.reshape(np.where(row == 1), (-1,))

        # for each 1 in that frequency,
        for top_level_frequency_one_index in ones:
            claimed.append((frequency_index, top_level_frequency_one_index))

            found_a_front = False
            # for each frequencies[i:],
            for other_frequency_index, other_row in enumerate(ons_or_offs[frequency_index + 1:, :], start=frequency_index + 1):

                # for each non-claimed 1 which is less than theshold_ms away in time,
                upper_limit_index = top_level_frequency_one_index + threshold_samples
                lower_limit_index = top_level_frequency_one_index - threshold_samples
                other_ones = np.reshape(np.where(other_row == 1), (-1,))  # Get the indexes of all the 1s in row
                tmp = np.reshape(np.where((other_ones >= lower_limit_index)  # Get the indexes in the other_ones array of all items in bounds
                                        & (other_ones <= upper_limit_index)), (-1,))
                other_ones = other_ones[tmp]  # Get the indexes of all the 1s in the row that are in bounds
                if len(other_ones) > 0:
                    unclaimed_idx = other_ones[0]  # Take the first one
                    claimed.append((other_frequency_index, unclaimed_idx))
                elif len(claimed) < 3:
                    # revert the top-most 1 to 0
                    ons_or_offs[frequency_index, top_level_frequency_one_index] = 0
                    claimed = []
                    break  # Break from the for-each-frequencies[i:] loop so we can move on to the next item in the top-most freq
                elif len(claimed) >= 3:
                    found_a_front = True
                    # this group of so-far-claimed forms a front
                    claimed_as_indexes = tuple(np.array(claimed).T)
                    ons_or_offs[claimed_as_indexes] = this_id
                    this_id += 1
                    claimed = []
                    break  # Move on to the next item in the top-most array
            # If we never found a frequency that did not have a matching offset, handle that case here
            if len(claimed) >= 3:
                claimed_as_indexes = tuple(np.array(claimed).T)
                ons_or_offs[claimed_as_indexes] = this_id
                this_id += 1
                claimed = []
            elif found_a_front:
                this_id += 1
            else:
                ons_or_offs[frequency_index, top_level_frequency_one_index] = 0
                claimed = []

    return ons_or_offs
def _form_onset_offset_fronts(ons_or_offs, sample_rate_hz, threshold_ms=20):
    """
    Takes an array of onsets or offsets (shape = [nfrequencies, nsamples], where a 1 corresponds to an on/offset,
    and samples are 0 otherwise), and returns a new array of the same shape, where each 1 has been replaced by
    either a 0, if the on/offset has been discarded, or a non-zero positive integer, such that
    each front within the array has a unique ID - for example, all 2s in the array will be the front for on/offset
    front 2, and all the 15s will be the front for on/offset front 15, etc.

    Due to implementation details, there will be no 1 IDs.
    """
    threshold_s = threshold_ms / 1000
    threshold_samples = sample_rate_hz * threshold_s

    ons_or_offs = np.copy(ons_or_offs)

    claimed = []
    this_id = 2
    # For each frequency,
    for frequency_index, row in enumerate(ons_or_offs[:, :]):
        ones = np.reshape(np.where(row == 1), (-1,))

        # for each 1 in that frequency,
        for top_level_frequency_one_index in ones:
            claimed.append((frequency_index, top_level_frequency_one_index))

            found_a_front = False
            # for each frequencies[i:],
            for other_frequency_index, other_row in enumerate(ons_or_offs[frequency_index + 1:, :], start=frequency_index + 1):

                # for each non-claimed 1 which is less than theshold_ms away in time,
                upper_limit_index = top_level_frequency_one_index + threshold_samples
                lower_limit_index = top_level_frequency_one_index - threshold_samples
                other_ones = np.reshape(np.where(other_row == 1), (-1,))  # Get the indexes of all the 1s in row
                tmp = np.reshape(np.where((other_ones >= lower_limit_index)  # Get the indexes in the other_ones array of all items in bounds
                                        & (other_ones <= upper_limit_index)), (-1,))
                other_ones = other_ones[tmp]  # Get the indexes of all the 1s in the row that are in bounds
                if len(other_ones) > 0:
                    unclaimed_idx = other_ones[0]  # Take the first one
                    claimed.append((other_frequency_index, unclaimed_idx))
                elif len(claimed) < 3:
                    # revert the top-most 1 to 0
                    ons_or_offs[frequency_index, top_level_frequency_one_index] = 0
                    claimed = []
                    break  # Break from the for-each-frequencies[i:] loop so we can move on to the next item in the top-most freq
                elif len(claimed) >= 3:
                    found_a_front = True
                    # this group of so-far-claimed forms a front
                    claimed_as_indexes = tuple(np.array(claimed).T)
                    ons_or_offs[claimed_as_indexes] = this_id
                    this_id += 1
                    claimed = []
                    break  # Move on to the next item in the top-most array
            # If we never found a frequency that did not have a matching offset, handle that case here
            if len(claimed) >= 3:
                claimed_as_indexes = tuple(np.array(claimed).T)
                ons_or_offs[claimed_as_indexes] = this_id
                this_id += 1
                claimed = []
            elif found_a_front:
                this_id += 1
            else:
                ons_or_offs[frequency_index, top_level_frequency_one_index] = 0
                claimed = []

    return ons_or_offs
def _form_onset_offset_fronts ( ons_or_offs , sample_rate_hz , threshold_ms = 20 ) : threshold_s = threshold_ms / 1000 threshold_samples = sample_rate_hz * threshold_s ons_or_offs = np . copy ( ons_or_offs ) claimed = [ ] this_id = 2 # For each frequency, for frequency_index , row in enumerate ( ons_or_offs [ : , : ] ) : ones = np . reshape ( np . where ( row == 1 ) , ( - 1 , ) ) # for each 1 in that frequency, for top_level_frequency_one_index in ones : claimed . append ( ( frequency_index , top_level_frequency_one_index ) ) found_a_front = False # for each frequencies[i:], for other_frequency_index , other_row in enumerate ( ons_or_offs [ frequency_index + 1 : , : ] , start = frequency_index + 1 ) : # for each non-claimed 1 which is less than theshold_ms away in time, upper_limit_index = top_level_frequency_one_index + threshold_samples lower_limit_index = top_level_frequency_one_index - threshold_samples other_ones = np . reshape ( np . where ( other_row == 1 ) , ( - 1 , ) ) # Get the indexes of all the 1s in row tmp = np . reshape ( np . where ( ( other_ones >= lower_limit_index ) # Get the indexes in the other_ones array of all items in bounds & ( other_ones <= upper_limit_index ) ) , ( - 1 , ) ) other_ones = other_ones [ tmp ] # Get the indexes of all the 1s in the row that are in bounds if len ( other_ones ) > 0 : unclaimed_idx = other_ones [ 0 ] # Take the first one claimed . append ( ( other_frequency_index , unclaimed_idx ) ) elif len ( claimed ) < 3 : # revert the top-most 1 to 0 ons_or_offs [ frequency_index , top_level_frequency_one_index ] = 0 claimed = [ ] break # Break from the for-each-frequencies[i:] loop so we can move on to the next item in the top-most freq elif len ( claimed ) >= 3 : found_a_front = True # this group of so-far-claimed forms a front claimed_as_indexes = tuple ( np . array ( claimed ) . T ) ons_or_offs [ claimed_as_indexes ] = this_id this_id += 1 claimed = [ ] break # Move on to the next item in the top-most array # If we never found a frequency that did not have a matching offset, handle that case here if len ( claimed ) >= 3 : claimed_as_indexes = tuple ( np . array ( claimed ) . T ) ons_or_offs [ claimed_as_indexes ] = this_id this_id += 1 claimed = [ ] elif found_a_front : this_id += 1 else : ons_or_offs [ frequency_index , top_level_frequency_one_index ] = 0 claimed = [ ] return ons_or_offs
Takes an array of onsets or offsets (shape = [nfrequencies, nsamples], where a 1 corresponds to an on/offset,
    and samples are 0 otherwise), and returns a new array of the same shape, where each 1 has been replaced by
    either a 0, if the on/offset has been discarded, or a non-zero positive integer, such that
    each front within the array has a unique ID - for example, all 2s in the array will be the front for on/offset
    front 2, and all the 15s will be the front for on/offset front 15, etc.

    Due to implementation details, there will be no 1 IDs.
Takes an array of onsets or offsets ( shape = [ nfrequencies nsamples ] where a 1 corresponds to an on / offset and samples are 0 otherwise ) and returns a new array of the same shape where each 1 has been replaced by either a 0 if the on / offset has been discarded or a non - zero positive integer such that each front within the array has a unique ID - for example all 2s in the array will be the front for on / offset front 2 and all the 15s will be the front for on / offset front 15 etc .