def save_history(request): """ Save a copy of all ExtraAttrValue (labels, notes, ...) in a HistoryEntry :param request: must specify a comment to store with this copy :return: name of the zip file created :version: 2.0.0 """ version = 4 user = request.user comment = get_or_error(request.POST, 'comment') database_id = get_or_error(request.POST, 'database') backup_type = get_or_error(request.POST, 'type') database = get_or_error(Database, dict(id=database_id)) assert_permission(user, database, DatabasePermission.VIEW) assert_values(backup_type, ['labels', 'segmentation']) meta = dict(database=database_id, user=user.id, time=timezone.now(), version=version, note=comment, type=backup_type) zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_BZIP2, False) as zip_file: zip_file.writestr('meta.json', json.dumps(meta)) zip_file.writestr('root.extraattrvalue.json', 'here for checking purpose') if backup_type == 'labels': save_label_history(database, user, zip_file) else: save_segmentation_history(database, user, zip_file) binary_content = zip_buffer.getvalue() he = HistoryEntry.objects.create(user=user, time=timezone.now(), database=database, version=version, note=comment, type=backup_type) filename = he.filename filepath = history_path(filename) ensure_parent_folder_exists(filepath) with open(filepath, 'wb') as f: f.write(binary_content) tz_offset = request.session['detected_tz'] tz = offset_to_timezone(tz_offset) _, rows = bulk_get_history_entries([he], DotMap(user=user, database=database_id, tz=tz)) return rows[0]
def handle(self, *args, **options): tensor_to_dm = {} for tensor in FullTensorData.objects.all(): sids_path = tensor.get_sids_path() bytes_path = tensor.get_bytes_path() cols_path = tensor.get_cols_path() sids = bytes_to_ndarray(sids_path, np.int32) data = get_rawdata_from_binary(bytes_path, len(sids)) dm = DataMatrix.objects.filter(name=tensor.name).first() if dm is None: dm = DataMatrix.objects.create( database=tensor.database, name=tensor.name, features_hash=tensor.features_hash, aggregations_hash=tensor.aggregations_hash, ndims=data.shape[1]) dm_sids_path = dm.get_sids_path() dm_bytes_path = dm.get_bytes_path() dm_cols_path = dm.get_cols_path() ensure_parent_folder_exists(dm_sids_path) shutil.copy(sids_path, dm_sids_path) shutil.copy(bytes_path, dm_bytes_path) shutil.copy(cols_path, dm_cols_path) tensor_to_dm[tensor] = dm for tensor in DerivedTensorData.objects.exclude(dimreduce='none'): dm = tensor_to_dm[tensor.full_tensor] sids_path = tensor.full_tensor.get_sids_path() bytes_path = tensor.get_bytes_path() if not os.path.exists(bytes_path): bytes_path = tensor.full_tensor.get_bytes_path() method = tensor.dimreduce ndims = tensor.ndims if method.startswith('tsne'): ndims = int(method[4:]) method = 'tsne' ord = Ordination.objects.filter(dm=dm, method=method, ndims=ndims).first() if ord is None: ord = Ordination.objects.create(dm=dm, method=method, ndims=ndims) ord_sids_path = ord.get_sids_path() ord_bytes_path = ord.get_bytes_path() ensure_parent_folder_exists(ord_sids_path) shutil.copy(sids_path, ord_sids_path) shutil.copy(bytes_path, ord_bytes_path)
def rearrange_spectrogram(apps, schema_editor): """ """ current_spect_dir = os.path.join(settings.MEDIA_URL, 'spect', 'fft', 'syllable')[1:] current_abs_spect_dir = os.path.join(settings.BASE_DIR, current_spect_dir) if os.path.isdir(current_abs_spect_dir): spect_files = os.listdir(current_abs_spect_dir) sys.stdout.write('\n') sys.stdout.write('\tFound {} spectrograms'.format(len(spect_files))) sys.stdout.flush() for spect_file in spect_files: try: tid = int(spect_file[:-4]) except ValueError: warning('\tFile {} is not named correctly and will be deleted'. format(spect_file)) continue current_path = current_abs_spect_dir + '/' + str(tid) + '.png' new_path = get_abs_spect_path(tid) try: shutil.move(current_path, new_path) except FileNotFoundError: ensure_parent_folder_exists(new_path) shutil.move(current_path, new_path) shutil.rmtree(current_abs_spect_dir)
def convert(conversion_scheme, print_stats=True): wav_file_path = conversion_scheme['wav'] if not os.path.isfile(wav_file_path): warning('File {} does not exist, skip.'.format(wav_file_path)) return fmt, filepath = conversion_scheme['other'] wav_audio = None if not os.path.isfile(filepath): ensure_parent_folder_exists(filepath) wav_audio = pydub.AudioSegment.from_file(wav_file_path) wav_audio.export(filepath, format=fmt) if print_stats: if wav_audio is None: wav_audio = pydub.AudioSegment.from_file(wav_file_path) wav_size = os.path.getsize(wav_file_path) / 1024 / 1024 wav_length = len(wav_audio.raw_data) // wav_audio.frame_width wav_fs = wav_audio.frame_rate file_size = os.path.getsize(filepath) / 1024 / 1024 converted_file = pydub.AudioSegment.from_file(filepath) file_length = len( converted_file.raw_data) // converted_file.frame_width file_fs = converted_file.frame_rate print('Wav size: {:6.2f}, {} size: {:6.2f}'.format( wav_size, fmt, file_size)) print('Wav length: {:6.2f}, {} length: {:6.2f}'.format( wav_length, fmt, file_length)) print('Wav fs: {:6.2f}, {} fs: {:6.2f}'.format(wav_fs, fmt, file_fs))
def extract_spectrogram(audio_file_id): """ Extract raw sepectrograms for all segments (Not the masked spectrogram from Luscinia) of an audio file :param audio_file: :return: """ audio_file = AudioFile.objects.get(id=audio_file_id) segs_info = Segment.objects.filter(audio_file=audio_file).values_list( 'tid', 'start_time_ms', 'end_time_ms') missing_segs_info = [] for tid, start, end in segs_info: seg_spect_path = spect_fft_path(tid, 'syllable') ensure_parent_folder_exists(seg_spect_path) if not os.path.isfile(seg_spect_path): missing_segs_info.append((seg_spect_path, start, end)) if len(missing_segs_info) > 0: filepath = wav_path(audio_file) fs, sig = wav_2_mono(filepath) duration_ms = len(sig) * 1000 / fs _, _, s = signal.stft(sig, fs=fs, window=window, noverlap=noverlap, nfft=window_size, return_onesided=True) file_spect = np.abs(s * scale) height, width = np.shape(file_spect) file_spect = np.flipud(file_spect) file_spect = np.log10(file_spect) file_spect = ((file_spect - global_min_spect_pixel) / interval64) file_spect[np.isinf(file_spect)] = 0 file_spect = file_spect.astype(np.int) file_spect = file_spect.reshape((width * height, ), order='C') file_spect[file_spect >= 64] = 63 file_spect_rgb = np.empty((height, width, 3), dtype=np.uint8) file_spect_rgb[:, :, 0] = cm_red[file_spect].reshape( (height, width)) * 255 file_spect_rgb[:, :, 1] = cm_green[file_spect].reshape( (height, width)) * 255 file_spect_rgb[:, :, 2] = cm_blue[file_spect].reshape( (height, width)) * 255 for path, start, end in missing_segs_info: roi_start = int(start / duration_ms * width) roi_end = int(np.ceil(end / duration_ms * width)) seg_spect_rgb = file_spect_rgb[:, roi_start:roi_end, :] seg_spect_img = Image.fromarray(seg_spect_rgb) seg_spect_img.save(path, format='PNG')
def store_feature_values(ids, feature, values_arr): index_filename = data_path('binary/features', '{}.idx'.format(feature.name), for_url=False) value_filename = data_path('binary/features', '{}.val'.format(feature.name), for_url=False) ensure_parent_folder_exists(index_filename) binstorage.store(ids, values_arr, index_filename, value_filename)
def extract_spectrogram(audio_file, segs_info): """ Extract raw sepectrograms for all segments (Not the masked spectrogram from Luscinia) of an audio file :param audio_file: :return: """ filepath = wav_path(audio_file) fs, duration = get_wav_info(filepath) if not os.path.isfile(filepath): raise CustomAssertionError("File {} not found".format(audio_file.name)) for tid, start, end in segs_info: seg_spect_path = get_abs_spect_path(tid) ensure_parent_folder_exists(seg_spect_path) sig = read_segment(filepath, beg_ms=start, end_ms=end, mono=True, normalised=True, return_fs=False, retype=True, winlen=window_size) _, _, s = signal.stft(sig, fs=fs, window=window, noverlap=noverlap, nfft=window_size, return_onesided=True) spect = np.abs(s * scale) height, width = np.shape(spect) spect = np.flipud(spect) spect = np.log10(spect) spect = ((spect - global_min_spect_pixel) / interval64) spect[np.isinf(spect)] = 0 spect = spect.astype(np.int) spect = spect.reshape((width * height, ), order='C') spect[spect >= 64] = 63 spect_rgb = np.empty((height, width, 3), dtype=np.uint8) spect_rgb[:, :, 0] = cm_red[spect].reshape((height, width)) * 255 spect_rgb[:, :, 1] = cm_green[spect].reshape((height, width)) * 255 spect_rgb[:, :, 2] = cm_blue[spect].reshape((height, width)) * 255 # roi_start = int(start / duration_ms * width) # roi_end = int(np.ceil(end / duration_ms * width)) # seg_spect_rgb = file_spect_rgb[:, roi_start:roi_end, :] seg_spect_img = Image.fromarray(spect_rgb) seg_spect_img.save(seg_spect_path, format='PNG') celerylogger.info('spectrogram {} created'.format(seg_spect_path))
def import_pcm(song, cur, audio_file, wav_file_path=None, compressed_url=None): if wav_file_path is None: wav_file_path = wav_path(audio_file) if compressed_url is None: compressed_url = audio_path(audio_file, settings.AUDIO_COMPRESSED_FORMAT) if not os.path.isfile(wav_file_path): # print('Importing {}'.format(song_name)) song_id = song['songid'] cur.execute('select wav from wavs where songid={};'.format(song_id)) data = cur.fetchone() raw_pcm = str_to_bytes(data[0]) nchannels = song['stereo'] bitrate = int(song['ssizeinbits']) fs = int(song['samplerate']) byte_per_frame = int(bitrate / 8) nframes_all_channel = int(len(raw_pcm) / byte_per_frame) nframes_per_channel = int(nframes_all_channel / nchannels) length = nframes_per_channel ensure_parent_folder_exists(wav_file_path) if bitrate == 24: array1 = np.frombuffer(raw_pcm, dtype=np.ubyte) array2 = array1.reshape((nframes_per_channel, nchannels, byte_per_frame)).astype(np.uint8) wf.write_24b(wav_file_path, fs, array2) else: data = array.array('i', raw_pcm) sound = pydub.AudioSegment(data=data, sample_width=byte_per_frame, frame_rate=fs, channels=nchannels) sound.export(wav_file_path, 'wav') else: fs, length = get_wav_info(wav_file_path) if not os.path.isfile(compressed_url): ensure_parent_folder_exists(compressed_url) sound = pydub.AudioSegment.from_wav(wav_file_path) sound.export(compressed_url, format=settings.AUDIO_COMPRESSED_FORMAT) return fs, length
def write_metadata(metadata, sids, headers, filename=None): if filename: ensure_parent_folder_exists(filename) output_stream = open(filename, 'w', encoding='utf-8') else: output_stream = io.StringIO() output_stream.write('\t'.join(headers)) output_stream.write('\n') for sid in sids: row = metadata[sid] output_stream.write('\n') output_stream.write('\t'.join(row)) if not filename: content = output_stream.getvalue() output_stream.close() return content
def save(self, *args, **kwargs): """ Save the object and then use its ID to store a pickle file contaning all the attrs as declared Pickle file will be stored in user_data/pickle/<class name>/ :param args: :param kwargs: :return: None """ super(PicklePersistedModel, self).save(*args, **kwargs) fpath = pickle_path(self.id, self.__class__.__name__) ensure_parent_folder_exists(fpath) mdict = {} for attr in self._meta.attrs: mdict[attr] = getattr(self, attr) with open(fpath, 'wb') as f: pickle.dump(mdict, f, pickle.HIGHEST_PROTOCOL)
def import_signal_mask(conn): """ Export pictures of the syllable with fundamentals :param conn: :return: """ cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) cur.execute('SELECT id, name, maxfreq, dy FROM songdata s') songs_data = cur.fetchall() song_info = {} for song in songs_data: song_name = song['name'] song_info[song_name] = (song['id'], song['maxfreq'], song['dy']) segments_info = Segment.objects \ .filter(audio_file__name__in=song_info.keys()) \ .values_list('id', 'audio_file__name', 'start_time_ms', 'end_time_ms') n = len(segments_info) bar = Bar('Importing segments ...', max=n) for seg_id, song_name, start, end in segments_info: if song_name not in song_info: continue song_id, nyquist, fbin = song_info[song_name] cur.execute( 'select starttime, endtime, songid from syllable where songid={} and starttime<={} and endtime>={}' ' order by starttime'.format(song_id, start, end)) syl_rows = cur.fetchall() if len(syl_rows) == 0: warning('Song #{} {} doesn\'t have a syllable at position {}:{}'. format(song_id, song_name, start, end)) continue if len(syl_rows) > 1: warning( 'Song #{} {} has more than one syllable at position {}:{}. Db Syllable #{}' .format(song_id, song_name, start, end, seg_id)) for syl_idx, syl_row in enumerate(syl_rows): syl_starttime = syl_row['starttime'] syl_endtime = syl_row['endtime'] cur.execute( 'select starttime, timelength, fundfreq, gapbefore, gapafter, maxf, dy,' 'overallpeakfreq1, overallpeakfreq2 ' 'from element where songid={} and starttime >= {} and (starttime + timelength) <= {}' .format(song_id, syl_starttime, syl_endtime)) el_rows = cur.fetchall() if len(el_rows) == 0: warning( 'Syllable #{} starttime={} endtime={} of song: "{}" doesn\'t enclose any syllable.' .format(1, syl_starttime, syl_endtime, song_name)) continue syl_starttime = el_rows[0]['starttime'] syl_endtime = get_syllable_end_time(el_rows) if nyquist == 0: nyquist = el_rows[0]['maxf'] if fbin == 0: fbin = el_rows[0]['dy'] width = int(syl_endtime - syl_starttime) + 1 height = int(nyquist / fbin) img_data_rgb = np.ones((height, width, 3), dtype=np.uint8) * 255 syl_max_ff = 0 syl_min_ff = 999999 syl_combined_ff = None for el_idx, el in enumerate(el_rows): # signal = list(map(int, el['signal'].strip().split(' '))) fundfreq = np.array(el['fundfreq'].strip().split(' '), dtype='|S32').astype(np.float) el_max_ff = fundfreq[0] el_min_ff = fundfreq[1] # the first 4 numbers of fundfreq are: max, min, ? (no idea) and ? (no idea), so we ignore them fundfreq = fundfreq[4:] if el_idx == 0: syl_combined_ff = fundfreq else: syl_combined_ff = np.concatenate( (syl_combined_ff, fundfreq)) fundfreq = (fundfreq / nyquist * height).astype(np.int) i = 0 ff_row_idx = 0 while i < len(signal): num_data = signal[i] img_col_idx = signal[i + 1] - syl_starttime # Draw the mask for j in range(2, num_data, 2): _signal_segment_end = signal[i + j] _signal_segment_start = signal[i + j + 1] img_data_rgb[_signal_segment_start:_signal_segment_end, img_col_idx, :] \ = COLOURS[el_idx % len(COLOURS)] # Add the fundamental (red lines) if ff_row_idx < len(fundfreq): img_row_idx = height - fundfreq[ff_row_idx] - 1 img_row_idx_padded_low = max(0, img_row_idx - 2) img_row_idx_padded_high = img_row_idx + 4 - ( img_row_idx - img_row_idx_padded_low) img_data_rgb[ img_row_idx_padded_low:img_row_idx_padded_high, img_col_idx, :] = FF_COLOUR ff_row_idx += 1 i += (num_data + 1) syl_max_ff = max(syl_max_ff, el_max_ff) syl_min_ff = min(syl_min_ff, el_min_ff) syl_mean_ff = np.mean(syl_combined_ff) Segment.objects.filter(id=seg_id).update(mean_ff=syl_mean_ff) Segment.objects.filter(id=seg_id).update(max_ff=syl_max_ff) Segment.objects.filter(id=seg_id).update(min_ff=syl_min_ff) img = Image.fromarray(img_data_rgb) thumbnail_width = int(img.size[0]) thumbnail_height = int(img.size[1] * 0.3) img = img.resize((thumbnail_width, thumbnail_height)) if syl_idx > 0: warning('Syl_idx > 0') file_path = spect_mask_path('{}_{}'.format(seg_id, syl_idx)) else: file_path = spect_mask_path(seg_id) ensure_parent_folder_exists(file_path) img.save(file_path, format='PNG') bar.next() bar.finish()
def create_database(request): user = request.user name = get_or_error(request.POST, 'new-database-name') nfft = int(get_or_error(request.POST, 'new-database-fft')) noverlap = int(get_or_error(request.POST, 'new-database-overlap')) hpf = int(get_or_error(request.POST, 'new-database-hpf')) lpf = request.POST.get('new-database-lpf') errors = {} if not re.match('^[a-zA-Z0-9_-]+$', name): errors[ 'new-database-name-error'] = 'Name can only contain alphabets, numbers, dashes and underscores' if Database.objects.filter(name__iexact=name).exists(): errors[ 'new-database-name-error'] = 'Database with name {} already exists.'.format( name) if lpf: lpf = int(lpf) if lpf <= hpf: errors[ 'new-database-lpf-error'] = 'Low pass filter value must be > high pass value' else: lpf = None has_errors = len(errors) > 0 if not has_errors: database = Database(name=name, nfft=nfft, noverlap=noverlap, hpf=hpf, lpf=lpf) database.save() dbid = database.id media_dir = settings.MEDIA_URL[1:] new_wav_dir = os.path.join(settings.BASE_DIR, media_dir, 'audio', 'wav', str(dbid)) new_compressed_dir = os.path.join(settings.BASE_DIR, media_dir, 'audio', settings.AUDIO_COMPRESSED_FORMAT, str(database.id)) ensure_parent_folder_exists(new_wav_dir) ensure_parent_folder_exists(new_compressed_dir) os.mkdir(new_wav_dir) os.mkdir(new_compressed_dir) # Now assign this database to this user, and switch the working database to this new one da = DatabaseAssignment(user=user, database=database, permission=DatabasePermission.ASSIGN_USER) da.save() permission_str = DatabasePermission.get_name( DatabasePermission.ASSIGN_USER) noverlap = nfft * noverlap // 100 payload = dict(id=dbid, name=name, permission=permission_str, nfft=nfft, overlap=noverlap, hpf=hpf, lpf=lpf) else: payload = errors return dict(origin='create_database', success=not has_errors, warning=None, payload=payload)
def handle(self, *args, **options): database_name = options['database_name'] annotator_name = options['annotator_name'] label_level = options['label_level'] save_to = options['save_to'] format = options['format'] min_occur = options['min_occur'] num_instances = options['num_instances'] normalised = options['normalised'] if num_instances is not None: assert num_instances >= min_occur, 'num_instances must be >= min_occur' database = get_or_error(Database, dict(name__iexact=database_name)) annotator = get_or_error(User, dict(username__iexact=annotator_name)) segments = Segment.objects.filter(audio_file__database=database) sids = np.array(list(segments.order_by('id').values_list('id', flat=True))) labels, no_label_ids = get_labels_by_sids(sids, label_level, annotator, min_occur) if len(no_label_ids) > 0: sids, _, labels = exclude_no_labels(sids, None, labels, no_label_ids) if num_instances: sids, _, labels = select_instances(sids, None, labels, num_instances) unique_labels, enum_labels = np.unique(labels, return_inverse=True) fold_indices = get_kfold_indices(enum_labels, min_occur) segments_info = {sid: (label, label_enum, fold_ind) for sid, label, label_enum, fold_ind in zip(sids, labels, enum_labels, fold_indices)} segs = Segment.objects.filter(id__in=sids) audio_file_dict = {} for seg in segs: af = seg.audio_file if af in audio_file_dict: info = audio_file_dict[af] else: info = [] audio_file_dict[af] = info info.append((seg.id, seg.start_time_ms, seg.end_time_ms)) audio_info = [] bar = Bar('Exporting segments ...', max=len(segs)) metadata_file_path = os.path.join(save_to, 'metadata.tsv') extractor = extractors.get(format, None) for af, info in audio_file_dict.items(): wav_file_path = wav_path(af) fullwav = pydub.AudioSegment.from_wav(wav_file_path) for id, start, end in info: label, label_enum, fold_ind = segments_info[id] audio_segment = fullwav[start: end] filename = '{}.{}'.format(id, format) filepath = os.path.join(save_to, filename) ensure_parent_folder_exists(filepath) if not os.path.isfile(filepath): if extractor is not None: extractor(wav_file_path, af.fs, start, end, filepath) else: with open(filepath, 'wb') as f: audio_segment.export(f, format=format) audio_info.append( (id, filename, label, label_enum, fold_ind) ) bar.next() with open(metadata_file_path, 'w') as f: f.write('id\tfilename\tlabel\tlabel_enum\tfold\n') for id, filename, label, label_enum, fold_ind in audio_info: f.write('{}\t{}\t{}\t{}\t{}\n'.format(id, filename, label, label_enum, fold_ind)) bar.finish() if normalised: norm_folder = os.path.join(save_to, 'normalised') mkdirp(norm_folder) global_min, global_max = extract_global_min_max(save_to, format) save_global_min_max(norm_folder, global_min, global_max) normalise_all(save_to, norm_folder, format, global_min, global_max)
def _import_and_convert_audio_file(database, file, max_fs, real_fs=None, audio_file=None, track=None, start=None, end=None): file_already_exists = False if isinstance(file, BufferedWriter): file_already_exists = True name_ext = os.path.basename(file.name) else: name_ext = file.name if name_ext.lower().endswith('.wav'): name_no_ext = name_ext[:-4] else: name_no_ext = name_ext # Need a unique name (database-wide) for new file if audio_file is None: is_unique = not AudioFile.objects.filter(database=database, name=name_no_ext).exists() if not is_unique: raise CustomAssertionError( 'File {} already exists'.format(name_no_ext)) elif audio_file.name != name_no_ext: raise CustomAssertionError( 'Impossible! File name in your table and in the database don\'t match' ) wav_name = data_path('audio/wav/{}'.format(database.id), '{}.wav'.format(name_no_ext)) name_compressed = data_path( 'audio/{}/{}'.format(settings.AUDIO_COMPRESSED_FORMAT, database.id), '{}.{}'.format(name_no_ext, settings.AUDIO_COMPRESSED_FORMAT)) fake_wav_name = wav_name + '.bak' if not file_already_exists: with open(wav_name, 'wb') as wav_file: wav_file.write(file.read()) _fs, length, noc = get_wav_info(wav_name, return_noc=True) # If real_fs is provided, it is absolute -- otherwise it is what we can really read from the file if real_fs is None: real_fs = _fs fake_fs = None # If real_fs is not what we read from the file, then the file is fake, and we must restore the original file # to do that we rename the wav file that we just stored (which is fake) to .bak, then change the sample rate # back to the original and store the original file as .wav if real_fs != _fs: os.rename(wav_name, fake_wav_name) change_fs_without_resampling(fake_wav_name, real_fs, wav_name) audio = pydub.AudioSegment.from_file(fake_wav_name) os.remove(fake_wav_name) # Otherwise, if real_fs is more than max_fs, we must create a fake file for the sake of converting to mp3: elif real_fs > max_fs: fake_fs = max_fs change_fs_without_resampling(wav_name, fake_fs, fake_wav_name) audio = pydub.AudioSegment.from_file(fake_wav_name) os.remove(fake_wav_name) # Otherwise the file is ordinary - no need to fake it else: audio = pydub.AudioSegment.from_file(wav_name) ensure_parent_folder_exists(name_compressed) audio.export(name_compressed, format=settings.AUDIO_COMPRESSED_FORMAT) if audio_file is None: if track is None: track = AudioTrack.objects.get_or_create(name='TBD')[0] individual = Individual.objects.get_or_create(name='TBD')[0] audio_file = AudioFile(name=name_no_ext, length=length, fs=real_fs, database=database, track=track, start=start, end=end, fake_fs=fake_fs, added=timezone.now(), noc=noc, individual=individual) audio_file.save() if track.name == 'TBD': track.name = str(audio_file.id) track.save() individual.name = str(audio_file.id) individual.save() else: audio_file.start = start audio_file.end = end audio_file.length = length audio_file.save() return audio_file
def write_config(config, config_file): ensure_parent_folder_exists(config_file) with open(config_file, 'w+') as f: json.dump(config, f, ensure_ascii=False, indent=4)
def ndarray_to_bytes(arr, filename): assert isinstance(arr, np.ndarray) ensure_parent_folder_exists(filename) with open(filename, 'wb') as f: arr.tofile(f)
def extract_spectrogram(): """ Extract raw sepectrograms for all segments (Not the masked spectrogram from Luscinia) :return: """ audio_to_segs = {} for segment in Segment.objects.all(): audio_file = segment.audio_file if audio_file not in audio_to_segs: audio_to_segs[audio_file] = [(segment.id, segment.start_time_ms, segment.end_time_ms)] else: audio_to_segs[audio_file].append( (segment.id, segment.start_time_ms, segment.end_time_ms)) n = len(audio_to_segs) bar = Bar('Exporting spects ...', max=n) for audio_file, seg_list in audio_to_segs.items(): count = 0 for seg_id, start, end in seg_list: seg_spect_path = spect_fft_path(seg_id, 'syllable') if os.path.isfile(seg_spect_path): count += 1 if count == len(seg_list): bar.next() continue filepath = wav_path(audio_file) fs, sig = wav_2_mono(filepath) duration_ms = len(sig) * 1000 / fs _, _, s = signal.stft(sig, fs=fs, window=window, noverlap=noverlap, nfft=window_size, return_onesided=True) file_spect = np.abs(s * scale) height, width = np.shape(file_spect) file_spect = np.flipud(file_spect) try: file_spect = np.log10(file_spect) file_spect = ((file_spect - global_min_spect_pixel) / interval64) file_spect[np.isinf(file_spect)] = 0 file_spect = file_spect.astype(np.int) file_spect = file_spect.reshape((width * height, ), order='C') file_spect[file_spect >= 64] = 63 file_spect_rgb = np.empty((height, width, 3), dtype=np.uint8) file_spect_rgb[:, :, 0] = cm_red[file_spect].reshape( (height, width)) * 255 file_spect_rgb[:, :, 1] = cm_green[file_spect].reshape( (height, width)) * 255 file_spect_rgb[:, :, 2] = cm_blue[file_spect].reshape( (height, width)) * 255 file_spect_img = Image.fromarray(file_spect_rgb) file_spect_path = spect_fft_path(audio_file.id, 'song') ensure_parent_folder_exists(file_spect_path) if not os.path.isfile(file_spect_path): file_spect_img.save(file_spect_path, format='PNG') for seg_id, start, end in seg_list: roi_start = int(start / duration_ms * width) roi_end = int(np.ceil(end / duration_ms * width)) seg_spect_rgb = file_spect_rgb[:, roi_start:roi_end, :] seg_spect_img = Image.fromarray(seg_spect_rgb) seg_spect_path = spect_fft_path(seg_id, 'syllable') ensure_parent_folder_exists(seg_spect_path) if not os.path.isfile(seg_spect_path): seg_spect_img.save(seg_spect_path, format='PNG') except Exception as e: warning('Error occured at song id: {}'.format(audio_file.id)) raise e bar.next() bar.finish()
def extract_database_measurements(arg=None, force=False): if isinstance(arg, int): task = get_or_wait(arg) else: task = arg runner = TaskRunner(task) try: runner.preparing() if isinstance(task, Task): cls, dm_id = task.target.split(':') dm_id = int(dm_id) assert cls == DataMatrix.__name__ dm = DataMatrix.objects.get(id=dm_id) if dm.database: segments = Segment.objects.filter( audio_file__database=dm.database) sids = segments.values_list('id', flat=True) else: sids = dm.tmpdb.ids features_hash = dm.features_hash aggregations_hash = dm.aggregations_hash else: sids = task.sids features_hash = task.features_hash aggregations_hash = task.aggregations_hash features = Feature.objects.filter(id__in=features_hash.split('-')) aggregations = Aggregation.objects.filter( id__in=aggregations_hash.split('-')) aggregators = [aggregator_map[x.name] for x in aggregations] # feature to binstorage's files f2bs = {} # feature+aggregation to binstorage's files fa2bs = {} for feature in features: feature_name = feature.name index_filename = data_path('binary/features', '{}.idx'.format(feature_name), for_url=False) value_filename = data_path('binary/features', '{}.val'.format(feature_name), for_url=False) f2bs[feature] = (index_filename, value_filename) if feature not in fa2bs: fa2bs[feature] = {} for aggregator in aggregators: aggregator_name = aggregator.get_name() folder = os.path.join('binary', 'features', feature_name) mkdirp(os.path.join(settings.MEDIA_URL, folder)[1:]) index_filename = data_path(folder, '{}.idx'.format(aggregator_name), for_url=False) value_filename = data_path(folder, '{}.val'.format(aggregator_name), for_url=False) fa2bs[feature][aggregator] = (index_filename, value_filename) tids, f2tid2fvals = extract_segment_features_for_segments( runner, sids, features, f2bs, force) for feature, (index_filename, value_filename) in f2bs.items(): _tids, _fvals = f2tid2fvals.get(feature, (None, None)) if _tids: _tids = np.array(_tids, dtype=np.int32) ensure_parent_folder_exists(index_filename) binstorage.store(_tids, _fvals, index_filename, value_filename) runner.wrapping_up() child_task = task.__class__(user=task.user, parent=task) child_task.save() child_runner = TaskRunner(child_task) child_runner.preparing() aggregate_feature_values(child_runner, sids, f2bs, fa2bs, features, aggregators) child_runner.complete() if isinstance(task, Task): full_sids_path = dm.get_sids_path() full_bytes_path = dm.get_bytes_path() full_cols_path = dm.get_cols_path() data, col_inds = extract_rawdata(f2bs, fa2bs, tids, features, aggregators) ndarray_to_bytes(data, full_bytes_path) ndarray_to_bytes(np.array(sids, dtype=np.int32), full_sids_path) with open(full_cols_path, 'w', encoding='utf-8') as f: json.dump(col_inds, f) dm.ndims = data.shape[1] dm.save() runner.complete() except Exception as e: runner.error(e)
def import_audio_file(request): """ Store uploaded file (only wav is accepted) :param request: must contain a list of files and the id of the database to be stored against :return: """ user = request.user f = request.FILES['file'] database_id = get_or_error(request.POST, 'database-id') item = json.loads(get_or_error(request.POST, 'item')) track_id = get_or_error(request.POST, 'track-id') database = get_or_error(Database, dict(id=database_id)) track = get_or_error(AudioTrack, dict(id=track_id)) assert_permission(user, database, DatabasePermission.ADD_FILES) start = item['start'] end = item['end'] song_id = item['id'] file = File(file=f) name = file.name if name.lower().endswith('.wav'): name = name[:-4] audio_file = None need_unique_name = True if not isinstance(song_id, str) or not song_id.startswith('new:'): audio_file = AudioFile.objects.filter(id=song_id).first() if audio_file and audio_file.name == name: need_unique_name = False if need_unique_name: is_unique = not AudioFile.objects.filter(database=database, name=name).exists() if not is_unique: raise CustomAssertionError('File {} already exists'.format(name)) name_wav = data_path('audio/wav/{}'.format(database.id), '{}.wav'.format(name)) name_compressed = data_path( 'audio/{}/{}'.format(settings.AUDIO_COMPRESSED_FORMAT, database.id), '{}.{}'.format(name, settings.AUDIO_COMPRESSED_FORMAT)) with open(name_wav, 'wb') as wav_file: wav_file.write(file.read()) audio = pydub.AudioSegment.from_file(name_wav) ensure_parent_folder_exists(name_compressed) audio.export(name_compressed, format=settings.AUDIO_COMPRESSED_FORMAT) fs = audio.frame_rate length = audio.raw_data.__len__() // audio.frame_width if audio_file is None: audio_file = AudioFile(name=name, length=length, fs=fs, database=database, track=track, start=start, end=end) else: if audio_file.name != name: AudioFile.set_name([audio_file], name) audio_file.start = start audio_file.end = end audio_file.length = length audio_file.save() quality = item.get('quality', None) individual_name = item.get('individual', None) note = item.get('note', None) type = item.get('type', None) sex = item.get('sex', None) if individual_name is not None: individual = Individual.objects.filter(name=individual_name).first() if individual is None: individual = Individual.objects.create(name=individual_name, gender=sex) elif sex is not None: individual.gender = sex individual.save() audio_file.individual = individual if quality: audio_file.quality = quality audio_file.save() audio_file_attrs = settings.ATTRS.audio_file if note: extra_attr_value = ExtraAttrValue.objects.filter( user=user, owner_id=audio_file.id, attr=audio_file_attrs.note) extra_attr_value.value = note if type: extra_attr_value = ExtraAttrValue.objects.create( user=user, owner_id=audio_file.id, attr=audio_file_attrs.type) extra_attr_value.value = type return dict(id=audio_file.id, name=audio_file.name)
def import_audio_files(request): """ Store uploaded files (only wav is accepted) :param request: must contain a list of files and the id of the database to be stored against :return: """ user = request.user files = request.FILES.values() database_id = get_or_error(request.POST, 'database') database = get_or_error(Database, dict(id=database_id)) assert_permission(user, database, DatabasePermission.ADD_FILES) added_files = [] not_importable_filenames = [] importable_files = [] for f in files: file = File(file=f) name = file.name if name.lower().endswith('.wav'): name = name[:-4] is_unique = not AudioFile.objects.filter(database=database, name=name).exists() if not is_unique: not_importable_filenames.append(name) else: importable_files.append(file) if len(not_importable_filenames) > 0: raise CustomAssertionError( 'Error: No files were imported because the following files already exist: {}' .format(', '.join(not_importable_filenames))) else: for file in importable_files: name = file.name if name.lower().endswith('.wav'): name = name[:-4] name_wav = data_path('audio/wav/{}'.format(database.id), '{}.wav'.format(name)) name_compressed = data_path( 'audio/{}/{}'.format(settings.AUDIO_COMPRESSED_FORMAT, database.id), '{}.{}'.format(name, settings.AUDIO_COMPRESSED_FORMAT)) with open(name_wav, 'wb') as wav_file: wav_file.write(file.read()) audio = pydub.AudioSegment.from_file(name_wav) ensure_parent_folder_exists(name_compressed) audio.export(name_compressed, format=settings.AUDIO_COMPRESSED_FORMAT) fs = audio.frame_rate length = audio.raw_data.__len__() // audio.frame_width audio_file = AudioFile(name=name, length=length, fs=fs, database=database) added_files.append(audio_file) AudioFile.objects.bulk_create(added_files) added_files = AudioFile.objects.filter( database=database, name__in=[x.name for x in added_files]) _, rows = get_sequence_info_empty_songs(added_files) return rows