text: """
  Module: libfmp.b.b_annotation
  Author: Frank Zalkow, Meinard Mueller
  License: The MIT license, https://opensource.org/licenses/MIT
  
  This file is part of the FMP Notebooks (https://www.audiolabs-erlangen.de/FMP)
  """
  
  import numpy as np
  import pandas as pd
  import librosa
  
  from . import write_audio
  
  
  def read_csv(fn, header=True, add_label=False):
      """Reads a CSV file
  
      Args:
          fn: Filename
          header: Boolean
          add_label: Add column with constant value of `add_label`
  
      Returns:
          df: Pandas DataFrame
      """
      df = pd.read_csv(fn, sep=';', keep_default_na=False, header=0 if header else None)
      if add_label:
          assert 'label' not in df.columns, 'Label column must not exist if `add_label` is True'
          df = df.assign(label=[add_label] * len(df.index))
      return df
  
  
  def write_csv(df, fn, header=True):
      """Writes a CSV file
  
      Args:
          df: Pandas DataFrame
          fn: Filename
          header: Boolean
      """
      df.to_csv(fn, sep=';', index=False, quoting=2, header=header)
  
  
  def cut_audio(fn_in, fn_out, start_sec, end_sec, normalize=True, write=True, Fs=22050):
      """Cuts an audio file
  
      Notebook: B/B_Annotations_cut.ipynb
  
      Args:
          fn_in: Filename and path for input audio file
          fn_out: Filename and path for input audio file
          start_sec: Start time position (in seconds) of cut
          end_sec: End time position (in seconds) of cut
          normalize: If True, then normalize audio (with max norm)
          write: If True, then write audio
          Fs: Sampling rate of audio
  
      Returns:
          x_cut: Cut audio
      """
      x_cut, Fs = librosa.load(fn_in, sr=Fs, offset=start_sec, duration=end_sec-start_sec)
      if normalize is True:
          x_cut = x_cut / np.max(np.abs(x_cut))
      if write is True:
          write_audio(fn_out, x_cut, Fs)
      return x_cut
  
  
  def cut_csv_file(fn_in, fn_out, start_sec, end_sec, write=True):
      """Cuts csv annotation file
  
      Notebook: B/B_Annotations_cut.ipynb
  
      Args:
          fn_in: Filename and path for input audio file
          fn_out: Filename and path for input audio file
          start_sec: Start time position (in seconds) of cut
          end_sec: End time position (in seconds) of cut
          write: If True, then write audio
  
      Returns:
          ann_cut: Cut annotation file
      """
      df = pd.read_csv(fn_in, sep=',', keep_default_na=False, header=None)
      ann_cut = []
      for i, (start, end, pitch, label) in df.iterrows():
          if (start > start_sec) and (start < end_sec):
              ann_cut.append([start-start_sec, min(end, end_sec)-start, int(pitch), 100, str(int(label))])
      columns = ['Start', 'Duration', 'Pitch', 'Velocity', 'Instrument']
      df_out = pd.DataFrame(ann_cut, columns=columns)
      df_out['Start'] = df_out['Start'].map('{:,.3f}'.format)
      df_out['Duration'] = df_out['Duration'].map('{:,.3f}'.format)
      df_out.to_csv(fn_out, sep=';', index=False)
      return ann_cut
  