def audio(self,stripzeros='none',mono=False) : """Returns audio for file Param stripzeros can be 'leading','trailing','both','none' Param mono returns mono if True, otherwise native signal Returns triple [x,fs,svals] x is signal fs is sampling rate svals is a tuple containing [zeros stripped from front, zeros stripped from end] of file see gordon.io.audio.AudioFile for more details.""" audioFile = AudioFile(self.fn_audio,stripzeros=stripzeros,mono=mono) x, fs, sval = audioFile.read() return x, fs, sval
def audio(self, stripzeros='none', mono=False): """Returns audio for file Param stripzeros can be 'leading','trailing','both','none' Param mono returns mono if True, otherwise native signal Returns triple [x,fs,svals] x is signal fs is sampling rate svals is a tuple containing [zeros stripped from front, zeros stripped from end] of file see gordon.io.audio.AudioFile for more details.""" audioFile = AudioFile(self.fn_audio, stripzeros=stripzeros, mono=mono) x, fs, sval = audioFile.read() return x, fs, sval
def update_secs_zsecs(tid_or_track, force=False, fast=False, do_commit=True): """Updates the seconds and optionally zero-stripped seconds (sec,zsec) for a track Takes either a Track object or a track id. If force is False (default) then only computes if values are missing If fast is True we don't decode the file. Instead we read in times from track header. Also we set zsecs to -1 if it is not already... If do_commit is true, we commit this to the database. Otherwise we do not""" #album 6451 does not work for our audioio if isinstance(tid_or_track, Track): track = tid_or_track else: track = Track.query.get(tid_or_track) if track == None: raise ValueError('Track for id %i not found in update_secs_zsecs' % tid_or_track) #fast case we only update the secs #the defaults for these is -1 in the database. There should be no NULL values if track.secs is None: track.secs = -1 if track.zsecs is None: track.zsecs = -1 if force or (fast and track.secs <= 0) or ( (not fast) and (track.secs <= 0 or track.zsecs <= 0)): a = AudioFile(track.fn_audio) if fast: #update secs but not zsecs based on file header (no decoding) zsecs = -1 (fs, chans, secs) = a.read_stats() else: #update both secs and zsecs by decoding file and actually working with audio (more accurate) secs, zsecs = a.get_secs_zsecs() track.secs = secs track.zsecs = zsecs print 'Processed track', track.id, secs, zsecs if do_commit: commit() return (track.secs, track.zsecs)
def update_secs_zsecs(tid_or_track,force=False,fast=False,do_commit=True): """Updates the seconds and optionally zero-stripped seconds (sec,zsec) for a track Takes either a Track object or a track id. If force is False (default) then only computes if values are missing If fast is True we don't decode the file. Instead we read in times from track header. Also we set zsecs to -1 if it is not already... If do_commit is true, we commit this to the database. Otherwise we do not""" #album 6451 does not work for our audioio if isinstance(tid_or_track,Track) : track=tid_or_track else : track = Track.query.get(tid_or_track) if track==None : raise ValueError('Track for id %i not found in update_secs_zsecs' % tid_or_track) #fast case we only update the secs #the defaults for these is -1 in the database. There should be no NULL values if track.secs is None : track.secs=-1 if track.zsecs is None: track.zsecs=-1 if force or (fast and track.secs<=0) or ((not fast) and (track.secs<=0 or track.zsecs <=0)) : a = AudioFile(track.fn_audio) if fast : #update secs but not zsecs based on file header (no decoding) zsecs=-1 (fs,chans,secs)=a.read_stats() else : #update both secs and zsecs by decoding file and actually working with audio (more accurate) secs, zsecs = a.get_secs_zsecs() track.secs=secs track.zsecs=zsecs print 'Processed track',track.id,secs,zsecs if do_commit : commit() return (track.secs,track.zsecs)
def add_track(trackpath, source=str(datetime.date.today()), gordonDir=DEF_GORDON_DIR, tag_dict=None, artist=None, album=None, fast_import=False, import_md=False): """Add track with given filename <trackpath> to database @param source: audio files data source (string) @param gordonDir: main Gordon directory @param tag_dict: dictionary of key,val tag pairs - See add_album(...). @param artist: The artist for this track. An instance of Artist. None if not present @param album: The album for this track. An instance of Album. None if not present @param fast_import: If true, do not calculate strip_zero length. Defaults to False @param import_md: use True to try to extract all metadata tags embedded in the auudio-file. Defaults to False """ (path, filename) = os.path.split(trackpath) (fname, ext) = os.path.splitext(filename) if tag_dict is None: tag_dict = {} log.debug('Adding file "%s" of "%s" album by %s', filename, album, artist) # validations if 'album' not in tag_dict: #todo: currently cannot add singleton files. Need an album which is defined in tag_dict log.error('Cannot add "%s" because it is not part of an album', filename) return -1 # didn't add if not os.path.isfile(trackpath): log.info('Skipping %s because it is not a file', filename) return -1 # not a file # FIXME: 2014-01-10 21:42:48 by Brian McFee <*****@*****.**> # gordon's AudioFile code doesn't handle unicode filenames correctly # try: # AudioFile(trackpath).read(tlen_sec=0.01) # except: # log.error('Skipping "%s" because it is not a valid audio file', filename) # return -1 # not an audio file # required data bytes = os.stat(trackpath)[stat.ST_SIZE] # First look for dupes if track_exists(filename, bytes): log.debug('Skipping "%s" because it has already been indexed', filename) return -1 # Already exists # prepare data if tag_dict[u'compilation'] not in [True, False, 'True', 'False'] : tag_dict[u'compilation'] = False track = Track(title = tag_dict[u'title'], artist = tag_dict[u'artist'], album = tag_dict[u'album'], tracknum = tag_dict[u'tracknum'], compilation = tag_dict[u'compilation'], otitle = tag_dict[u'title'], oartist = tag_dict[u'artist'], oalbum = tag_dict[u'album'], otracknum = tag_dict[u'tracknum'], ofilename = unicode(filename, 'utf-8', errors='ignore'), source = unicode(source), bytes = bytes) # add data add(track) # needed to get a track id commit() #to get our track id we need to write this record log.debug('Wrote track record %s to database', track.id) if fast_import : track.secs = -1 track.zsecs = -1 else : a = AudioFile(trackpath) [track.secs, track.zsecs] = a.get_secs_zsecs() track.path = u'%s' % get_tidfilename(track.id, ext[1:]) # links track to artist & album in DB if artist: log.debug('Linking %s to artist %s', track, artist) track.artist = artist.name track.artists.append(artist) if album: log.debug('Linking %s to album %s', track, album) track.album = album.name track.albums.append(album) log.debug('Wrote album and artist additions to track into database') # copy the file to the Gordon audio/feature data directory tgt = os.path.join(gordonDir, 'audio', 'main', track.path) make_subdirs_and_copy(trackpath, tgt) log.debug('Copied "%s" to %s', trackpath, tgt) # add annotations del(tag_dict[u'title']) del(tag_dict[u'artist']) del(tag_dict[u'album']) del(tag_dict[u'tracknum']) del(tag_dict[u'compilation']) for tagkey, tagval in tag_dict.iteritems(): # create remaining annotations track.annotations.append(Annotation(type='text', name=tagkey, value=tagval)) if import_md: #check if file is mp3. if so: if isValidMP3(trackpath): #extract all ID3 tags, store each tag value as an annotation type id3.[tagname] for tag in getAllTags(trackpath): track.annotations.append(Annotation(type='id3', name=tag[0], value=tag[1])) #todo: work with more metadata formats (use tagpy?) # Link the track to the collection object track.collections.append(get_or_create_collection(source)) commit() # store the annotations log.debug('Added "%s"', trackpath)
def add_track(trackpath, source=str(datetime.date.today()), gordonDir=DEF_GORDON_DIR, tag_dict=dict(), artist=None, album=None, fast_import=False, import_md=False): """Add track with given filename <trackpath> to database @param source: audio files data source (string) @param gordonDir: main Gordon directory @param tag_dict: dictionary of key,val tag pairs - See add_album(...). @param artist: The artist for this track. An instance of Artist. None if not present @param album: The album for this track. An instance of Album. None if not present @param fast_import: If true, do not calculate strip_zero length. Defaults to False @param import_md: use True to try to extract all metadata tags embedded in the auudio-file. Defaults to False """ (path, filename) = os.path.split(trackpath) (fname, ext) = os.path.splitext(filename) log.debug('Adding file "%s" of "%s" album by %s', filename, album, artist) # validations if 'album' not in tag_dict: #todo: currently cannot add singleton files. Need an album which is defined in tag_dict log.error('Cannot add "%s" because it is not part of an album', filename) return -1 # didn't add if not os.path.isfile(trackpath): log.info('Skipping %s because it is not a file', filename) return -1 # not a file try: AudioFile(trackpath).read(tlen_sec=0.01) except: log.error('Skipping "%s" because it is not a valid audio file', filename) return -1 # not an audio file # required data bytes = os.stat(trackpath)[stat.ST_SIZE] # reencode name to latin1 !!! try: fn_recoded = filename.decode('utf-8') except: try: fn_recoded = filename.decode('latin1') except: fn_recoded = 'unknown' # prepare data if tag_dict[u'compilation'] not in [True, False, 'True', 'False']: tag_dict[u'compilation'] = False track = Track(title=tag_dict[u'title'], artist=tag_dict[u'artist'], album=tag_dict[u'album'], tracknum=tag_dict[u'tracknum'], compilation=tag_dict[u'compilation'], otitle=tag_dict[u'title'], oartist=tag_dict[u'artist'], oalbum=tag_dict[u'album'], otracknum=tag_dict[u'tracknum'], ofilename=fn_recoded, source=unicode(source), bytes=bytes) # add data add(track) # needed to get a track id commit() #to get our track id we need to write this record log.debug('Wrote track record %s to database', track.id) if fast_import: track.secs = -1 track.zsecs = -1 else: a = AudioFile(trackpath) [track.secs, track.zsecs] = a.get_secs_zsecs() track.path = u'%s' % get_tidfilename(track.id, ext[1:]) # links track to artist & album in DB if artist: log.debug('Linking %s to artist %s', track, artist) track.artist = artist.name track.artists.append(artist) if album: log.debug('Linking %s to album %s', track, album) track.album = album.name track.albums.append(album) log.debug('Wrote album and artist additions to track into database') # copy the file to the Gordon audio/feature data directory tgt = os.path.join(gordonDir, 'audio', 'main', track.path) make_subdirs_and_copy(trackpath, tgt) log.debug('Copied "%s" to %s', trackpath, tgt) # add annotations del (tag_dict[u'title']) del (tag_dict[u'artist']) del (tag_dict[u'album']) del (tag_dict[u'tracknum']) del (tag_dict[u'compilation']) for tagkey, tagval in tag_dict.iteritems(): # create remaining annotations track.annotations.append( Annotation(type='text', name=tagkey, value=tagval)) if import_md: #check if file is mp3. if so: if isValidMP3(trackpath): #extract all ID3 tags, store each tag value as an annotation type id3.[tagname] for tag in getAllTags(trackpath): track.annotations.append( Annotation(type='id3', name=tag[0], value=tag[1])) #todo: work with more metadata formats (use tagpy?) # Link the track to the collection object track.collections.append(get_or_create_collection(source)) commit() # store the annotations
def add_mp3(mp3, source=str(datetime.date.today()), gordonDir=DEF_GORDON_DIR, id3_dict=dict(), artist=None, album=None, fast_import=False, import_id3=False): '''Add mp3 with filename <mp3> to database @param source: audio files data source @param gordonDir: main Gordon directory @param tag_dict: dictionary of key,val ID3 tags pairs - See add_album(...). @param artist: The artist for this track. An instance of Artist. None if not present @param album: The album for this track. An instance of Album. None if not present @param fast_import: If true, do not calculate strip_zero length. Defaults to False @param import_id3: Specifies if we want to get the id3 tags from the file. Defaults to True ''' (filepath, filename) = os.path.split(mp3) log.debug(' Adding mp3 file "%s" of "%s" album by %s - add_mp3()', filename, album, artist) # validations if len(id3_dict) == 0 : #todo: currently cannot add singleton mp3s. Need an album which is defined in id3_dict log.error(' Cannot add "%s" because it is not part of an album', filename) return -1 # didn't add if not os.path.isfile(mp3) : log.debug(' Skipping %s because it is not a file', filename) return -1 # not a file # required data bytes = os.stat(mp3)[stat.ST_SIZE] # try: #get track length # eyed3_secs = int(id3.mp3_gettime(mp3)) #from mp3_eyed3 # except : # log.error(' Could not read time from mp3 %s', mp3) # eyed3_secs = -1 #we get odd filenames that cannot be easily encoded. This seems to come #from times when a latin-1 filesystem named files and then those filenames #are brought over to a utf filesystem. try: fn_recoded = filename.decode('utf-8') except : try : fn_recoded = filename.decode('latin1') except : fn_recoded = 'unknown' # prepare data if id3_dict['compilation'] not in [True, False, 'True', 'False'] : id3_dict['compilation'] = False track = Track(title = id3_dict[u'title'], artist = id3_dict[u'artist'], album = id3_dict[u'album'], tracknum = id3_dict[u'tracknum'], compilation = id3_dict[u'compilation'], otitle = id3_dict[u'title'], oartist = id3_dict[u'artist'], oalbum = id3_dict[u'album'], otracknum = id3_dict[u'tracknum'], ofilename = os.path.join(filepath,fn_recoded), source = unicode(source), bytes = bytes) # add data add(track) commit() #to get our track id we need to write this record log.debug(' Wrote track record %s to database', track.id) if fast_import : #try to get the seconds from ffmpeg track.zsecs = -1 track.secs= -1 try : a = AudioFile(filename) [ignore_fs,ignore_chans,track.secs] = a.read_stats() except : log.warn(" Could not read stats from", filename) else : a = AudioFile(filename) [track.secs, track.zsecs] = a.get_secs_zsecs() track.path = u"%s" % get_tidfilename(track.id) #This is a bit confusing. For backwards compat #todo: clean up DB relationships if artist: log.debug(' Linking to artist %s', artist) track.artist = artist.name track.artists.append(artist) if album: log.debug(' Linking to album %s', album) track.album = album.name track.albums.append(album) commit() # save (again) the track record (this time) log.debug(' * Wrote album and artist additions to track into database') #copy the file to the Gordon instal audio/feature data directory tgt = os.path.join(gordonDir, 'audio', 'main', track.path) make_subdirs_and_copy(filename, tgt) log.debug(' Copied mp3 "%s" to %s', filename, tgt) #stamp the file ("TID n" as an ID3v2 commment) id3.id3v2_putval(tgt, 'tid', 'T%i' % track.id) # writes on new audio file (the copy) # We update id3 tags in mp3 if necessary (from local MusicBrainz DB, when no info found) #todo: try this when Gordon has no write access to the files, does the script handle the error? (can't roll back saved tracks now) if track.otitle <> track.title or track.oartist <> track.artist or track.oalbum <> track.album or track.otracknum <> track.tracknum : log.debug(' (NOT) Trying to update_mp3_from_db %s %s', track.id, os.path.join(gordonDir, 'audio', 'main')) try: from gordon.db.mbrainz_resolver import GordonResolver gordonResolver = GordonResolver() try: if not gordonResolver.update_mp3_from_db(track.id, audioDir = os.path.join(gordonDir, 'audio', 'main'), doit = True) : pass # if file not found ... except Exception: # except for file access crashes? pass except: log.warning(' MusicBrainz interface is not installed. Refer to Gordon INSTALL notes.') #search for other annotations and store them in the database _store_annotations(mp3, track, import_id3)
def add_uncomp(wav, source=str(datetime.date.today()), gordonDir=DEF_GORDON_DIR, tag_dict=dict(), artist=None, album=None, fast_import=False, import_md=False): """Add uncompressed wav/aif with filename <wav> to database @param source: audio files data source - Collection object @param gordonDir: main Gordon directory @param tag_dict: dictionary of key,val tag pairs - See add_album(...). @param artist: The artist for this track. An instance of Artist. None if not present @param album: The album for this track. An instance of Album. None if not present @param fast_import: If true, do not calculate strip_zero length. Defaults to False @param import_md: Specifies if we want to get the metadata tags from the file. Defaults to True """ (xxx, filename) = os.path.split(wav) (xxx, ext) = os.path.splitext(filename) log.debug(' Adding uncompressed file "%s" of "%s" album by %s - add_uncomp()', filename, album, artist) # validations if len(tag_dict) == 0 : #todo: currently cannot add singleton files. Need an album which is defined in tag_dict log.error(' Cannot add "%s" because it is not part of an album', filename) return -1 # didn't add if not os.path.isfile(wav) : log.debug(' Skipping %s because it is not a file', filename) return -1 # not a file # required data bytes = os.stat(wav)[stat.ST_SIZE] # reencode name to latin1 try: fn_recoded = filename.decode('utf-8') except : try : fn_recoded = filename.decode('latin1') except : fn_recoded = 'unknown' # prepare data if tag_dict['compilation'] not in [True, False, 'True', 'False'] : tag_dict['compilation'] = False track = Track(title = tag_dict[u'title'], artist = tag_dict[u'artist'], album = tag_dict[u'album'], tracknum = tag_dict[u'tracknum'], compilation = tag_dict[u'compilation'], otitle = tag_dict[u'title'], oartist = tag_dict[u'artist'], oalbum = tag_dict[u'album'], otracknum = tag_dict[u'tracknum'], ofilename = fn_recoded, source = unicode(source), bytes = bytes) # add data add(track) # needed to get a track id commit() #to get our track id we need to write this record log.debug(' Wrote track record %s to database', track.id) if fast_import : track.secs = -1 track.zsecs = -1 else : a = AudioFile(filename) [track.secs, track.zsecs] = a.get_secs_zsecs() track.path = u'%s' % get_tidfilename(track.id, ext[1:]) # creates path to insert in track # links track to artist & album in DB if artist: log.debug(' Attaching artist %s', artist) track.artist = artist.name track.artists.append(artist) if album: log.debug(' Attaching album %s', album) track.album = album.name track.albums.append(album) commit() # save (again) the track record (this time having the track id) log.debug(' * Wrote album and artist additions to track into database') #copy the file to the Gordon instal audio/feature data directory tgt = os.path.join(gordonDir, 'audio', 'main', track.path) make_subdirs_and_copy(filename, tgt) log.debug(' Copied uncompressed "%s" to %s', filename, tgt) #search for other annotations and store them in the database _store_annotations(wav, track, import_md)