Skip to content

Commit

Permalink
added multisegment sonification
Browse files Browse the repository at this point in the history
  • Loading branch information
bmcfee committed Aug 30, 2016
1 parent a3dffe7 commit 8591738
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
31 changes: 30 additions & 1 deletion jams/sonify.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
sonify
'''

from itertools import product
from collections import OrderedDict
import six
import numpy as np
import mir_eval.sonify
from mir_eval.util import filter_kwargs
from .eval import coerce_annotation
from .eval import coerce_annotation, hierarchy_flatten
from .exceptions import NamespaceError

__all__ = ['sonify']
Expand Down Expand Up @@ -79,6 +80,29 @@ def downbeat(annotation, sr=22050, length=None, **kwargs):
return y


def multi_segment(annotation, sr=22050, length=None, **kwargs):
'''Sonify multi-level segmentations'''

# Pentatonic scale, because why not
PENT = [1, 32./27, 4./3, 3./2, 16./9]
DURATION = 0.1

h_int, _ = hierarchy_flatten(annotation)

if length is None:
length = int(sr * (max(np.max(_) for _ in h_int) + 1. / DURATION) + 1)

y = 0.0
for ints, (oc, scale) in zip(h_int, product(range(3, 3 + len(h_int)),
PENT)):
click = mkclick(440.0 * scale * oc, sr=sr, duration=DURATION)
y = y + filter_kwargs(mir_eval.sonify.clicks,
np.unique(ints),
fs=sr, length=length,
click=click)
return y


def chord(annotation, sr=22050, length=None, **kwargs):
'''Sonify chords
Expand Down Expand Up @@ -153,6 +177,7 @@ def piano_roll(annotation, sr=22050, length=None, **kwargs):
SONIFY_MAPPING = OrderedDict()
SONIFY_MAPPING['beat_position'] = downbeat
SONIFY_MAPPING['beat'] = clicks
SONIFY_MAPPING['multi_segment'] = multi_segment
SONIFY_MAPPING['segment_open'] = clicks
SONIFY_MAPPING['onset'] = clicks
SONIFY_MAPPING['chord'] = chord
Expand Down Expand Up @@ -189,6 +214,10 @@ def sonify(annotation, sr=22050, duration=None, **kwargs):
'''

length = None

if duration is None:
duration = annotation.duration

if duration is not None:
length = int(duration * sr)

Expand Down
19 changes: 16 additions & 3 deletions jams/tests/sonify_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
# CREATED:2016-02-11 12:07:58 by Brian McFee <[email protected]>
"""Sonification tests"""

import six
import numpy as np

from nose.tools import raises, eq_

from eval_test import create_hierarchy

import jams


Expand Down Expand Up @@ -82,7 +83,6 @@ def test_contour():
'index': 0,
'voiced': (t < 3 or t > 4)})


def __test(ann, duration):
y = jams.sonify.sonify(ann, sr=8000, duration=duration)
if duration is not None:
Expand All @@ -98,7 +98,7 @@ def __test(namespace, value):
ann = jams.Annotation(namespace=namespace)
ann.append(time=0.5, duration=1.0, value=value)
y = jams.sonify.sonify(ann, sr=8000, duration=2.0)

eq_(len(y), 8000 * 2)

yield __test, 'chord', 'C:maj/5'
Expand Down Expand Up @@ -136,3 +136,16 @@ def __test(ann, sr, duration):

for length in [None, 5, 15]:
yield __test, ann, 8000, length


def test_multi_segment():
ann = create_hierarchy(values=['AB', 'abac', 'xxyyxxzz'], duration=30)
sr = 8000

def __test(ann, duration):
y = jams.sonify.sonify(ann, sr=sr, duration=duration)
if duration:
eq_(len(y), duration * sr)

for duration in [None, 15, 30]:
yield __test, ann, duration

0 comments on commit 8591738

Please sign in to comment.