{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "wav_read_frame_librosa.py\n",
    "Author: M A Rohit\n",
    "This program is tested on Ubuntu 18.04 with Python 3.6.9, Numpy 1.19.2, and Librosa 0.8.0.\n",
    "It requires the installation of the additional package 'librosa' (which can be installed using 'pip install librosa'). The particular function to use is 'librosa.stream()'.\n",
    "\n",
    "Program flow:\n",
    "1. open a wav file for reading\n",
    "2. Next, read audio sequentially in smaller chunks from the wav file, one frame* at a time, in a loop:\n",
    "     3. load hop_len number of samples of audio\n",
    "     4. do some processing\n",
    "     5. write the feature values to a text file\n",
    "\n",
    "* A \"frame\" is a chunk of 'hop_len' number of samples, loaded in each iteration. This is distinct from a \"window\", which is the set of frames stored in the buffer and available for processing in each iteration. The loaded hop_len #samples are appended to the window (on the right side), and hop_len #samples at the start of the window are discarded (akin to the hop between overlapping windows in STFT).\n",
    "\n",
    "NOTE 1: The naming convention in librosa.stream() is different. The 'frame_length' parameter refers to the window size, and the 'hop_length' refers to the number of loaded samples. \n",
    "Additionally, there is a 'block_length' parameter, which sets the number of frames loaded in each iteration, i.e., 'block_length' x 'hop_length' number of samples are loaded. Setting this parameter to 1 gives us the implementation in 'wav_read_write_frame.py'.\n",
    "\n",
    "NOTE 2: Writing input audio back to another output file is not implemented in this code - librosa has no function for this. But another package 'soundfile' can be used for this, which is similar to the package 'wavefile' used in 'wav_read_write_frame.py'."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import numpy as np\n",
    "import librosa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Parameters\n",
    "hop_size=10e-3 #10 ms\n",
    "win_size=50e-3 #50 ms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Specify input wav file and output features file (to save extracted features)\n",
    "in_file = '\\path\\to\\input\\wav\\file'\n",
    "feat_file = '\\path\\to\\output\\features\\file'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#an empty list to store computed feature values, e.g., short-time energy\n",
    "feat_vals=[]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#get samplerate\n",
    "samplerate =  librosa.get_samplerate(in_file)\n",
    "\n",
    "#get window and hop sizes in samples, set block_length value\n",
    "win_len=int(samplerate*win_size)\n",
    "hop_len=int(samplerate*hop_size)\n",
    "block_len=1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#define the generator object, which will yield chunks\n",
    "stream = librosa.stream(in_file, block_length=block_len, frame_length=win_len, hop_length=hop_len)\n",
    "\n",
    "#iterate over chunks\n",
    "for data in stream:\n",
    "\t#do some processing - e.g., compute short-time energy, and store values\n",
    "\tfeat_vals.append((data**2).sum())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Writing the feature values to a text file\t\n",
    "times = np.arange(0, hop_size*len(feat_vals), hop_size)\n",
    "feats = np.array((times, feat_vals)).T\n",
    "np.savetxt(feat_file, feats, fmt=\"%.3f\", delimiter='\\t', header='Time\\tFeature', comments='')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
