Example #1
0
def test_annotation_trim_no_duration():
    # When ann.duration is not set prior to trim should raise warning
    ann = jams.Annotation('tag_open')
    ann.duration = None

    clean_warning_registry()
    with warnings.catch_warnings(record=True) as out:
        ann_trim = ann.trim(3, 5)

    assert len(out) > 0
    assert out[0].category is UserWarning
    assert 'annotation.duration is not defined' in str(out[0].message).lower()

    # When duration is not defined trim should keep all observations in the
    # user-specified trim range.
    namespace = 'tag_open'
    ann = jams.Annotation(namespace)
    ann.time = 100
    ann.duration = None
    ann.append(time=5, duration=2, value='one')

    clean_warning_registry()
    with warnings.catch_warnings(record=True) as out:
        ann_trim = ann.trim(5, 8)

    assert len(out) > 0
    assert out[0].category is UserWarning
    assert 'annotation.duration is not defined' in str(out[0].message).lower()

    expected_data = dict(time=[5.0],
                         duration=[2.0],
                         value=['one'],
                         confidence=[None])
    expected_ann = jams.Annotation(namespace, data=expected_data, time=5.0,
                                   duration=3.0)

    assert ann_trim.data == expected_ann.data
Example #2
0
File: utils.py Project: marl/milsed
def create_dcase_jam(fid, labelfile, duration=10.0, weak=False):

    # Create jam
    jam = jams.JAMS()

    # Create annotation
    ann = jams.Annotation('tag_open')
    # duration = sox.file_info.duration(audiofile)
    ann.duration = duration

    # Get labels from CSV file
    fid_ = fid[1:]
    labeldf = pd.read_csv(labelfile, header=None, sep='\t')
    labeldf.columns = ['filename', 'start_time', 'end_time', 'label']
    labeldf = labeldf[labeldf['filename'].str.contains(fid_)]
    #    assert len(labeldf) > 0

    # Add tag for each label
    for idx, row in labeldf.iterrows():
        if weak:
            ann.append(time=0,
                       duration=duration,
                       value=row.label,
                       confidence=1.0)
        else:
            if row.end_time <= row.start_time:
                continue
            ann.append(time=row.start_time,
                       duration=(row.end_time - row.start_time),
                       value=row.label,
                       confidence=1.0)

    # Fill file metadata
    jam.file_metadata.title = fid
    jam.file_metadata.release = '1.0'
    jam.file_metadata.duration = duration
    jam.file_metadata.artist = ''

    # Fill annotation metadata
    ann.annotation_metadata.version = '1.0'
    ann.annotation_metadata.corpus = 'DCASE 2017 Task 4'
    ann.annotation_metadata.data_source = 'AudioSet'
    ann.annotation_metadata.annotation_tools = 'reference'

    # Add annotation to jam
    jam.annotations.append(ann)

    # Return jam
    return jam
def run():

    #Capturando os nomes das pastas
    names_folders = glob.glob(path_database + '*')

    for names_ in names_folders:

        #Capturando o caminho completo dos audios
        path_audios = glob.glob(names_ + '/*.' + audio_format)

        for path_ in path_audios:

            #Capturando o nome do arquivo de audio (wav)
            match_obj = re.sub(names_, "", path_)
            audio_name = re.sub(r'/', "", match_obj)

            #Capturando o caminho completo da pasta
            fold_path = re.sub(audio_name, "", path_)

            os.chdir(fold_path)
            #Capturando a duracao do sinal
            y, sr = librosa.load(audio_name, sr=None)
            duration = librosa.get_duration(y=y, sr=sr)

            #Remove os arquivos de audio que possuem duracao inferior a 2.3s
            if duration >= 2.3:

                #Gerando o arquivo de anotacao jam
                jam = jams.JAMS()

                #Setando os parametros do arquivo de notacao
                jam.file_metadata.duration = duration
                ann = jams.Annotation(namespace='beat',
                                      time=0,
                                      duration=jam.file_metadata.duration)
                ann.annotation_metadata = jams.AnnotationMetadata(
                    data_source=data_source)
                ann.annotation_metadata = jams.AnnotationMetadata(
                    validation="")
                ann.annotation_metadata.curator = jams.Curator(name=name,
                                                               email=email)
                jam.annotations.append(ann)

                #Salvando o arquivo de notacao para cada audio
                jam_name = re.sub(r'\.wav', ".jams", audio_name)
                jam.save(jam_name)

            else:
                os.system('rm ' + path_)
Example #4
0
def test_annotation(namespace, tag_data, ann_metadata, ann_sandbox):
    ann = jams.Annotation(namespace,
                          data=tag_data,
                          annotation_metadata=ann_metadata,
                          sandbox=ann_sandbox)

    assert namespace == ann.namespace

    assert dict(ann_metadata) == dict(ann.annotation_metadata)

    assert dict(ann_sandbox) == dict(ann.sandbox)

    assert len(ann.data) == len(tag_data)
    for obs1, obs2 in zip(ann.data, tag_data):
        assert obs1._asdict() == obs2
def save_jams(jamsfile, notes, track_duration, orig_filename):

    jam = jams.JAMS()

    jam.file_metadata.duration = track_duration
    jam.file_metadata.title = orig_filename

    midi_an = jams.Annotation(namespace='pitch_midi', duration=track_duration)

    for n in notes:
        midi_an.append(time=n[0], duration=n[1], value=n[2], confidence=0)

    jam.annotations.append(midi_an)

    jam.save(jamsfile)
Example #6
0
def ann_beat():
    ann = jams.Annotation(namespace='beat', duration=10)

    # for n, i in enumerate(np.arange(0, 10, 0.5)):
    #    ann.append(time=i, duration=0, value=1 + (n % 4))

    # Make up two measures of 4/4, plus two pickup beats
    for t, v in [(0, -2), (0.5, -1),
                 (1, 1), (1.5, 2), (2, 3), (3, 4),
                 (3.5, 1), (4, 2), (4.5, 3), (5, 4),
                 (5.5, 1), (6, 2), (6.5, 3), (7, 4)]:

        ann.append(time=t, duration=0, value=v)

    return ann
Example #7
0
 def create_tempo_annotation(tempo1=0.0,
                             tempo2=0.0,
                             confidence1=1.0,
                             confidence2=0.0):
     tempo = jams.Annotation(namespace='tempo')
     tempo.append(time=0.0,
                  duration='nan',
                  value=tempo1,
                  confidence=confidence1)
     if tempo2 != 0.0:
         tempo.append(time=0.0,
                      duration='nan',
                      value=tempo2,
                      confidence=confidence2)
     return tempo
Example #8
0
def test_jams_trim_valid():
    # For a valid scenario, ensure everything behaves as expected
    jam = jams.JAMS()
    jam.file_metadata.duration = 15

    namespace = 'tag_open'
    data = dict(time=[5.0, 5.0, 10.0],
                duration=[2.0, 4.0, 4.0],
                value=['one', 'two', 'three'],
                confidence=[0.9, 0.9, 0.9])
    ann = jams.Annotation(namespace, data=data, time=5.0, duration=10.0)
    for _ in range(5):
        jam.annotations.append(ann)

    ann_copy = jams.Annotation(namespace, data=data, time=5.0, duration=10.0)
    ann_trim = ann_copy.trim(0, 10, strict=False)
    jam_trim = jam.trim(0, 10, strict=False)

    for ann in jam_trim.annotations:
        assert ann.data == ann_trim.data

    assert jam_trim.file_metadata.duration == jam.file_metadata.duration
    assert jam_trim.sandbox.trim == [{'start_time': 0, 'end_time': 10}]

    # Multiple trims
    jam_trim = jam.trim(0, 10).trim(8, 10)
    ann_trim = ann_copy.trim(0, 10).trim(8, 10)

    for ann in jam_trim.annotations:
        assert ann.data == ann_trim.data

    assert jam_trim.sandbox.trim == (
        [{'start_time': 0, 'end_time': 10}, {'start_time': 8, 'end_time': 10}])

    # Make sure file metadata copied over correctly
    assert jam_trim.file_metadata == jam.file_metadata
Example #9
0
def create_hierarchy(values, offset=0.0, duration=20):
    ann = jams.Annotation(namespace='multi_segment')

    for level, labels in enumerate(values):
        times = np.linspace(offset,
                            offset + duration,
                            num=len(labels),
                            endpoint=False)

        durations = list(np.diff(times))
        durations.append(duration + offset - times[-1])

        for t, d, v in zip(times, durations, labels):
            ann.append(time=t, duration=d, value=dict(label=v, level=level))

    return ann
Example #10
0
def test_annotation_to_samples(confidence):

    ann = jams.Annotation('tag_open')

    ann.append(time=0, duration=0.5, value='one', confidence=0.1)
    ann.append(time=0.25, duration=0.5, value='two', confidence=0.2)
    ann.append(time=0.75, duration=0.5, value='three', confidence=0.3)
    ann.append(time=1.5, duration=0.5, value='four', confidence=0.4)

    values = ann.to_samples([0.2, 0.4, 0.75, 1.25, 1.75, 1.4], confidence=confidence)

    if confidence:
        values, confs = values
        assert confs == [[0.1], [0.1, 0.2], [0.2, 0.3], [0.3], [0.4], []]

    assert values == [['one'], ['one', 'two'], ['two', 'three'], ['three'], ['four'], []]
Example #11
0
    def serializeTrack(path, track: Track, features=[{"namespace": "beat", "data_source": "Madmom", 'feature': "beats"}]):
        """
        Serialize a track in jams format
        """
        jam = jams.JAMS()
        jam.file_metadata.duration = track.getDuration()
        for feature in features:
            annotation = jams.Annotation(namespace=feature["namespace"])
            annotation.annotation_metadata = jams.AnnotationMetadata(data_source=feature["data_source"])

            for t in track.getFeature(feature["feature"]):
                annotation.append(time=t, duration=0.0)

            jam.annotations.append(annotation)

        jam.save(path)
Example #12
0
def test_annotation_array_data():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])
    ann = jams.Annotation('tag_open', data=data)
    arr = jams.AnnotationArray(annotations=[ann, ann])

    eq_(len(arr), 2)
    arr.append(ann)

    eq_(len(arr), 3)

    for t_ann in arr:
        assert ann.data.equals(t_ann.data)
Example #13
0
    def __test(namespace, data, amd, sandbox):
        ann = jams.Annotation(namespace,
                              data=data,
                              annotation_metadata=amd,
                              sandbox=sandbox)

        eq_(namespace, ann.namespace)

        if amd is not None:
            eq_(dict(amd), dict(ann.annotation_metadata))

        if sandbox is not None:
            eq_(dict(sandbox), dict(ann.sandbox))

        if data is not None:
            assert ann.data.equals(jams.JamsFrame.from_dict(data))
Example #14
0
def test_annotation_append():

    data = [
        dict(time=0, duration=0.5, value='one', confidence=0.9),
        dict(time=1.0, duration=0.5, value='two', confidence=0.9)
    ]

    namespace = 'tag_open'

    ann = jams.Annotation(namespace, data=data)

    update = dict(time=2.0, duration=1.0, value='three', confidence=0.8)

    ann.append(**update)

    assert ann.data[-1]._asdict() == update
Example #15
0
def test_annotation_array_serialize():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'
    ann = jams.Annotation(namespace, data=data)

    arr = jams.AnnotationArray(annotations=[ann, ann])

    arr_js = arr.__json__

    arr2 = jams.AnnotationArray(annotations=arr_js)

    eq_(arr, arr2)
def modernize_chord_annotation(annot):
    # fields = ['time', 'duration', 'value', 'confidence']
    data = []
    for item in annot['data']:
        t0 = item['start']['value']
        t1 = item['end']['value']
        label = item['label']['value']
        record = dict(time=t0,
                      duration=t1 - t0,
                      value=str(label),
                      confidence=1.0)
        data.append(record)
    return jams.Annotation(namespace='chord',
                           data=data,
                           sandbox=annot.get('sandbox', dict()),
                           annotation_metadata=annot.get(
                               'annotation_metadata', dict()))
Example #17
0
def test_jamsframe_add_observation_fail():
    @raises(jams.ParameterError)
    def __test(ann, time, duration, value, confidence):
        ann.data.add_observation(time=time,
                                 duration=duration,
                                 value=value,
                                 confidence=confidence)

    ann = jams.Annotation(namespace='tag_open')

    yield __test, ann, None, None, 'foo', 1
    yield __test, ann, 0.0, None, 'foo', 1
    yield __test, ann, None, 1.0, 'foo', 1

    yield __test, ann, -1, -1, 'foo', 1
    yield __test, ann, 0.0, -1, 'foo', 1
    yield __test, ann, -1, 1.0, 'foo', 1
Example #18
0
    def inverse(self, encoded, duration=None):
        '''Inverse static tag transformation'''

        ann = jams.Annotation(namespace=self.namespace, duration=duration)

        if np.isrealobj(encoded):
            detected = (encoded >= 0.5)
        else:
            detected = encoded

        for vd in self.encoder.inverse_transform(np.atleast_2d(detected))[0]:
            vid = np.flatnonzero(self.encoder.transform(np.atleast_2d(vd)))
            ann.append(time=0,
                       duration=duration,
                       value=vd,
                       confidence=encoded[vid])
        return ann
Example #19
0
def test_pitch_hz_to_midi():

    ann = jams.Annotation(namespace='pitch_hz')
    ann.append(time=0, duration=1, value=440.0, confidence=0.5)
    ann2 = jams.convert(ann, 'pitch_midi')
    ann.validate()
    ann2.validate()

    # Check the namespace
    eq_(ann2.namespace, 'pitch_midi')
    # midi 69 = 440.0 Hz
    eq_(ann2.data.value.loc[0], 69)

    # Check all else is equal
    pdt.assert_series_equal(ann.data.time, ann2.data.time)
    pdt.assert_series_equal(ann.data.duration, ann2.data.duration)
    pdt.assert_series_equal(ann.data.confidence, ann2.data.confidence)
Example #20
0
def test_annotation_data_frame():
    namespace = 'tag_open'
    data = dict(time=[5.0, 5.0, 10.0],
                duration=[2.0, 4.0, 4.0],
                value=['one', 'two', 'three'],
                confidence=[0.9, 0.9, 0.9])
    ann = jams.Annotation(namespace, data=data, time=5.0, duration=10.0)

    df = ann.to_dataframe()

    assert list(df.columns) == ['time', 'duration', 'value', 'confidence']

    for i, row in df.iterrows():
        assert row.time == data['time'][i]
        assert row.duration == data['duration'][i]
        assert row.value == data['value'][i]
        assert row.confidence == data['confidence'][i]
Example #21
0
def test_annotation_append():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'

    ann = jams.Annotation(namespace, data=data)

    update = dict(time=2.0, duration=1.0, value='three', confidence=0.8)

    ann.append(**update)

    jf = jams.JamsFrame.from_dict(data)
    jf.add_observation(**update)

    assert ann.data.equals(jf)
Example #22
0
def test_jams_add(tag_data):

    fn = 'tests/fixtures/valid.jams'

    # The original jam
    jam_orig = jams.load(fn)
    jam = jams.load(fn)

    # Make a new jam with the same metadata and different data
    jam2 = jams.load(fn)
    ann = jams.Annotation('tag_open', data=tag_data)
    jam2.annotations = jams.AnnotationArray(annotations=[ann])

    # Add the two
    jam.add(jam2)

    assert len(jam.annotations) == 3
    assert jam.annotations[:-1] == jam_orig.annotations
    assert jam.annotations[-1] == jam2.annotations[0]
Example #23
0
def tags_to_jams(tags, duration=0, namespace="tag_open", description=None):
    """Convert tags annotations into jams format.

    Args:
        tags (annotations.Tags): tags annotation object
        namespace (str): the jams-compatible tag namespace
        description (str): annotation description

    Returns:
        jams.Annotation: jams annotation object.

    """
    ann = jams.Annotation(namespace=namespace)
    ann.annotation_metadata = jams.AnnotationMetadata(data_source="soundata")
    for t, c in zip(tags.labels, tags.confidence):
        ann.append(time=0.0, duration=duration, value=t, confidence=c)
    if description is not None:
        ann.sandbox = jams.Sandbox(name=description)
    return ann
Example #24
0
def test_task_key_present(SR, HOP_LENGTH, SPARSE):
    # Create jams with key annotation
    jam = jams.JAMS(file_metadata=dict(duration=12.0))

    ann = jams.Annotation(namespace='key_mode')

    ann.append(time=0, duration=2.0, value='C:minor')
    ann.append(time=2, duration=2.0, value='N')
    ann.append(time=4, duration=2.0, value='Eb')
    ann.append(time=8, duration=2.0, value='D:major')
    ann.append(time=10, duration=2.0, value='D:lydian')

    jam.annotations.append(ann)

    trans = pumpp.task.KeyTransformer(name='key',
                                      sr=SR,
                                      hop_length=HOP_LENGTH,
                                      sparse=SPARSE)

    output = trans.transform(jam)

    # Make sure we have the mask
    assert np.all(
        output['key/_valid'] == [0, 12 * trans.sr // trans.hop_length])

    # Ideal vectors:
    # pcp = Cmin, N, Eb, N, D, D_lyd
    pcp_true = np.array([
        _encode_key_str('C:minor', SPARSE)[0],
        _encode_key_str('N', SPARSE)[0],
        _encode_key_str('Eb:major', SPARSE)[0],
        _encode_key_str('N', SPARSE)[0],
        _encode_key_str('D', SPARSE)[0],
        _encode_key_str('D:lydian', SPARSE)[0]
    ])

    assert np.all(output['key/pitch_profile'] == np.repeat(
        pcp_true, (SR * 2 // HOP_LENGTH), axis=0))

    for key in trans.fields:
        assert shape_match(output[key].shape[1:], trans.fields[key].shape)
        assert type_match(output[key].dtype, trans.fields[key].dtype)
Example #25
0
def test_task_beat_present(SR, HOP_LENGTH):

    # Construct a jam
    jam = jams.JAMS(file_metadata=dict(duration=4.0))

    ann = jams.Annotation(namespace='beat')

    ann.append(time=0, duration=0.0, value=1)
    ann.append(time=1, duration=0.0, value=2)
    ann.append(time=2, duration=0.0, value=3)
    ann.append(time=3, duration=0.0, value=1)

    jam.annotations.append(ann)

    trans = pumpp.task.BeatTransformer(name='beat')

    output = trans.transform(jam)

    # Make sure we have the masks
    assert np.all(
        output['beat/_valid'] == [0, 4 * trans.sr // trans.hop_length])
    assert output['beat/mask_downbeat']

    # The first channel measures beats
    # The second channel measures downbeats
    assert output['beat/beat'].shape == (1, 4 * (SR // HOP_LENGTH), 1)
    assert output['beat/downbeat'].shape == (1, 4 * (SR // HOP_LENGTH), 1)

    # Ideal vectors:
    #   a beat every second (two samples)
    #   a downbeat every three seconds (6 samples)

    beat_true = np.asarray([[1, 1, 1, 1]]).T
    downbeat_true = np.asarray([[1, 0, 0, 1]]).T

    assert np.all(output['beat/beat'][0, ::(SR // HOP_LENGTH)] == beat_true)
    assert np.all(output['beat/downbeat'][0, ::(SR //
                                                HOP_LENGTH)] == downbeat_true)

    for key in trans.fields:
        assert shape_match(output[key].shape[1:], trans.fields[key].shape)
        assert type_match(output[key].dtype, trans.fields[key].dtype)
Example #26
0
File: beat.py Project: tomxi/pumpp
    def inverse(self, encoded, downbeat=None, duration=None):
        '''Inverse transformation for beats and optional downbeats'''

        ann = jams.Annotation(namespace=self.namespace, duration=duration)

        beat_times = np.asarray([
            t for t, _ in self.decode_events(encoded,
                                             transition=self.beat_transition,
                                             p_init=self.beat_p_init,
                                             p_state=self.beat_p_state) if _
        ])
        beat_frames = time_to_frames(beat_times,
                                     sr=self.sr,
                                     hop_length=self.hop_length)

        if downbeat is not None:
            downbeat_times = set([
                t
                for t, _ in self.decode_events(downbeat,
                                               transition=self.down_transition,
                                               p_init=self.down_p_init,
                                               p_state=self.down_p_state) if _
            ])
            pickup_beats = len(
                [t for t in beat_times if t < min(downbeat_times)])
        else:
            downbeat_times = set()
            pickup_beats = 0

        value = -pickup_beats - 1
        for beat_t, beat_f in zip(beat_times, beat_frames):
            if beat_t in downbeat_times:
                value = 1
            else:
                value += 1
            confidence = encoded[beat_f]
            ann.append(time=beat_t,
                       duration=0,
                       value=value,
                       confidence=confidence)

        return ann
Example #27
0
    def inverse(self, encoded, duration=None):
        '''Inverse transformation'''

        ann = jams.Annotation(self.namespace, duration=duration)

        for start, end, value in self.decode_intervals(
                encoded,
                duration=duration,
                multi=False,
                sparse=self.sparse,
                transition=self.transition,
                p_init=self.p_init,
                p_state=self.p_state):

            # Map start:end to frames
            f_start, f_end = time_to_frames([start, end],
                                            sr=self.sr,
                                            hop_length=self.hop_length)

            # Reverse the index
            if self.sparse:
                # Compute the confidence
                if encoded.shape[1] == 1:
                    # This case is for full-confidence prediction (just the index)
                    confidence = 1.
                else:
                    confidence = np.mean(encoded[f_start:f_end + 1, value])

                value_dec = self.encoder.inverse_transform(value)
            else:
                confidence = np.mean(encoded[f_start:f_end + 1,
                                             np.argmax(value)])
                value_dec = self.encoder.inverse_transform(
                    np.atleast_2d(value))

            for vd in value_dec:
                ann.append(time=start,
                           duration=end - start,
                           value=vd,
                           confidence=float(confidence))

        return ann
Example #28
0
def test_task_beat_nometer(SR, HOP_LENGTH):

    # Construct a jam
    jam = jams.JAMS(file_metadata=dict(duration=4.0))

    ann = jams.Annotation(namespace='beat')

    ann.append(time=0, duration=0.0)
    ann.append(time=1, duration=0.0)
    ann.append(time=2, duration=0.0)
    ann.append(time=3, duration=0.0)

    jam.annotations.append(ann)

    # One second = one frame
    trans = pumpp.task.BeatTransformer(name='beat')

    output = trans.transform(jam)

    # Make sure we have the mask
    assert np.all(
        output['beat/_valid'] == [0, 4 * trans.sr // trans.hop_length])
    assert not output['beat/mask_downbeat']

    # Check the shape: 4 seconds at 2 samples per second
    assert output['beat/beat'].shape == (1, 4 * (SR // HOP_LENGTH), 1)
    assert output['beat/downbeat'].shape == (1, 4 * (SR // HOP_LENGTH), 1)

    # Ideal vectors:
    #   a beat every second (two samples)
    #   no downbeats

    beat_true = np.asarray([1, 1, 1, 1])
    downbeat_true = np.asarray([0, 0, 0, 0])

    assert np.all(output['beat/beat'][0, ::(SR // HOP_LENGTH)] == beat_true)
    assert np.all(output['beat/downbeat'][0, ::(SR //
                                                HOP_LENGTH)] == downbeat_true)

    for key in trans.fields:
        assert shape_match(output[key].shape[1:], trans.fields[key].shape)
        assert type_match(output[key].dtype, trans.fields[key].dtype)
Example #29
0
def test_pitch_midi_to_hz():

    ann = jams.Annotation(namespace='pitch_midi')
    ann.append(time=0, duration=1, value=69, confidence=0.5)
    ann2 = jams.convert(ann, 'pitch_hz')
    ann.validate()
    ann2.validate()

    # Check the namespace
    assert ann2.namespace == 'pitch_hz'
    # midi 69 = 440.0 Hz
    assert ann2.data[0].value == 440.0

    # Check all else is equal
    assert len(ann.data) == len(ann2.data)

    for obs1, obs2 in zip(ann.data, ann2.data):
        assert obs1.time == obs2.time
        assert obs1.duration == obs2.duration
        assert obs1.confidence == obs2.confidence
Example #30
0
def create_annotation(values,
                      namespace='beat',
                      offset=0.0,
                      duration=1,
                      confidence=1):
    ann = jams.Annotation(namespace=namespace)

    time = np.arange(offset, offset + len(values))

    if np.isscalar(duration):
        time = time * duration
        duration = [duration] * len(time)

    if np.isscalar(confidence):
        confidence = [confidence] * len(time)

    for t, d, v, c in zip(time, duration, values, confidence):
        ann.append(time=t, duration=d, value=v, confidence=c)

    return ann