Source code for zounds.soundfile.audio_metadata

from featureflow import Node, Aggregator
import os
from soundfile import SoundFile
import requests
import json
import io
from urllib.parse import urlparse
import featureflow as ff


[docs]class AudioMetaData(object): """ Encapsulates metadata about a source audio file, including things like text descriptions and licensing information. Args: uri (requests.Request or str): uri may be either a string representing a network resource or a local file, or a :class:`requests.Request` instance samplerate (int): the samplerate of the source audio channels (int): the number of channels of the source audio licensing (str): The licensing agreement (if any) that applies to the source audio description (str): a text description of the source audio tags (str): text tags that apply to the source audio kwargs (dict): other arbitrary properties about the source audio Raises: ValueError: when `uri` is not provided See Also: :class:`zounds.datasets.FreeSoundSearch` :class:`zounds.datasets.InternetArchive` :class:`zounds.datasets.PhatDrumLoops` """ def __init__( self, uri=None, samplerate=None, channels=None, licensing=None, description=None, tags=None, **kwargs): super(AudioMetaData, self).__init__() if not uri: raise ValueError('You must at least supply a uri') self.uri = uri self.samplerate = samplerate self.channels = channels self.licensing = licensing self.description = description self.tags = tags for k, v in kwargs.items(): setattr(self, k, v) @property def request(self): if hasattr(self.uri, 'url'): return self.uri def __eq__(self, other): return self.uri == other.uri \ and self.samplerate == other.samplerate \ and self.channels == other.channels \ and self.licensing == other.licensing \ and self.description == other.description \ and self.tags == other.tags def __repr__(self): return self.__dict__.__str__() def __str__(self): return self.__repr__()
class AudioMetaDataEncoder(Aggregator, Node): content_type = 'application/json' def __init__(self, needs=None): super(AudioMetaDataEncoder, self).__init__(needs=needs) def _uri(self, uri): if isinstance(uri, requests.Request): return uri.url elif isinstance(uri, io.BytesIO) or isinstance(uri, ff.ZipWrapper): return None else: return uri def _process(self, data): d = dict(data.__dict__) d['uri'] = self._uri(data.uri) yield json.dumps(d) class MetaData(Node): def __init__(self, needs=None): super(MetaData, self).__init__(needs=needs) @staticmethod def _is_url(s): if not isinstance(s, str): return False parsed = urlparse(s) return parsed.scheme and parsed.netloc @staticmethod def _is_local_file(s): try: return os.path.exists(s) except TypeError: return False @staticmethod def _is_file(s): try: s.tell() return True except AttributeError: return False def _process(self, data): if isinstance(data, AudioMetaData): yield data elif self._is_url(data): req = requests.Request( method='GET', url=data, headers={'Range': 'bytes=0-'}) yield AudioMetaData(uri=req) elif isinstance(data, requests.Request): if 'range' not in data.headers: data.headers['range'] = 'bytes=0-' yield AudioMetaData(uri=data) elif self._is_local_file(data) or self._is_file(data): sf = SoundFile(data) yield AudioMetaData( uri=data, samplerate=sf.samplerate, channels=sf.channels) else: yield AudioMetaData(uri=data)