{"id":20620559,"url":"https://github.com/blacklight/micmon","last_synced_at":"2025-08-11T20:14:44.313Z","repository":{"id":53608612,"uuid":"307724272","full_name":"blacklight/micmon","owner":"blacklight","description":"A Python library and set of scripts to create labelled audio datasets from raw audio files and use them to train sound detection models.","archived":false,"fork":false,"pushed_at":"2025-03-06T10:24:34.000Z","size":226,"stargazers_count":43,"open_issues_count":5,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-15T12:17:50.488Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blacklight.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-10-27T14:20:44.000Z","updated_at":"2025-03-12T22:48:00.000Z","dependencies_parsed_at":"2025-04-15T12:14:22.122Z","dependency_job_id":"d1108cc4-cbc0-46bf-be5a-c3851991cf98","html_url":"https://github.com/blacklight/micmon","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/blacklight/micmon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fmicmon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fmicmon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fmicmon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fmicmon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blacklight","download_url":"https://codeload.github.com/blacklight/micmon/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fmicmon/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269948892,"owners_count":24501832,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T12:14:52.379Z","updated_at":"2025-08-11T20:14:44.303Z","avatar_url":"https://github.com/blacklight.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"micmon\n======\n\n*micmon* is a ML-powered library to detect sounds in an audio stream,\neither from a file or from an audio input. The use case for its development\nhas been the creation of a self-built baby monitor to detect the cries\nof my new born through a RaspberryPi + USB microphone, but it should be\ngood enough to detect any type of noise or audio if used with a well trained\nmodel.\n\nIt works by splitting an audio stream into short segments, it calculates the\nFFT and spectrum bins for each of these segments, and it uses such spectrum\ndata to train a model to detect the audio. It works well with sounds that are\nloud enough to stand out of the background (it's good at detecting e.g. the\nsound of an alarm clock, not the sound of flying mosquitto), that are long\nenough compared to the size of the chunks (very short sounds will leave a\nvery small trace in the spectrum of an audio chunk) and, even better, if\ntheir frequency bandwidth doesn't overlap a lot with other sounds (it's good\nat detecting the cries of your baby, since his/her voice has a higher pitch\nthan yours, but it may not detect difference in the spectral signature of\nthe voice of two adult men in the same age group). It's not going to perform\nvery well if instead you are trying to use to detect speech - since it operates\non time-agnostic frequency data from chunks of audio it's not granular enough\nfor proper speech-to-text applications, and it wouldn't be robust enough to\ndetect differences in voice pitch, tone or accent.\n\nDependencies\n------------\n\nThe software uses *ffmpeg* to record and decode audio - check instructions for\nyour OS on how to get it installed. It also requires *lame* or any other mp3\nencoder to encode captured audio to mp3.\n\nPython dependencies:\n\n```bash\n# On Debian-based systems\napt-get install libatlas-base-dev\n\n# Install Tensorflow\npip install tensorflow\n\n# Optional, for graphs\npip install matplotlib\n```\n\nInstallation\n------------\n\n```bash\ngit clone https://github.com/BlackLight/micmon\ncd micmon\npython setup.py install\n```\n\nAudio capture\n-------------\n\nOnce the software is installed, you can proceed with recording some audio that\nwill be used for training the model. First create a directory for your audio\nsamples dataset:\n\n```bash\n# This folder will store our audio samples\nmkdir -p ~/datasets/sound-detect/audio\n\n# This folder will store the datasets\n# generated from the labelled audio samples\nmkdir -p ~/datasets/sound-detect/data\n\n# This folder will store the generated\n# Tensorflow models\nmkdir -p ~/models\n\ncd ~/datasets/sound-detect/audio\n```\n\nThen create a new sub-folder for your first audio sample and start recording.\nExample:\n\n```bash\nmkdir sample_1\ncd sample_1\narecord -D plughw:0,1 -f cd | lame - audio.mp3\n```\n\nIn the example above we are using *arecord* to record from the second channel\nof the first audio device (check a list of available recording devices with\n*arecord -l*) in WAV format, and we are then using the *lame* encoder to\nconvert the raw audio to mp3. When done with recording, just Ctrl-C the\napplication and your audio file will be ready.\n\nAudio labelling\n---------------\n\nIn the same directory as your sample (in the example above it will be\n`~/datasets/sound-detect/audio/sample_1`) create a new file named\n`labels.json`. Now open your audio file in Audacity or any audio player\nand identify the audio segments that match your criteria - for example\nwhen your baby is crying, when the alarm starts, when your neighbour\nstarts drilling the wall, or whatever the criteria is. `labels.json`\nshould contain a key-value mapping in the form of `start_time -\u003e label`.\nExample:\n\n```json\n{\n  \"00:00\": \"negative\",\n  \"02:13\": \"positive\",\n  \"04:57\": \"negative\",\n  \"15:41\": \"positive\",\n  \"18:24\": \"negative\"\n}\n```\n\nIn the example above, all the audio segments between 00:00 and 02:12 will\nbe labelled as negative, all the segments between 02:13 and 04:56 as\npositive, and so on.\n\nYou can now use *micmon* to generate a frequency spectrum dataset out of\nyour labelled audio. You can do it either through the `micmon-datagen`\nscript or with your own script.\n\n### micmon-datagen\n\nType `micmon-datagen --help` to get a full list of the available options.\nIn general, `micmon-datagen` requires a directory that contains the labelled\naudio samples sub-directories as input and a directory where the calculated\nnumpy-compressed datasets will be stored. If you want to generate the dataset\nfor the audio samples captured on the previous iteration then the command\nwill be something like this:\n\n```bash\nmicmon-datagen --low 250 --high 7500 --bins 100 --sample-duration 2 --channels 1 \\\n    ~/datasets/sound-detect/audio  ~/datasets/sound-detect/data\n```\n\nThe `--low` and `--high` options respectively identify the lowest and highest\nfrequencies that should be taken into account in the output spectrum. By default\nthese values are 20 Hz and 20 kHz (respectively the lowest and highest frequency\naudible to a healthy and young human ear), but you can narrow down the frequency\nspace to only detect the frequencies that you're interested in and to remove\nhigh-frequency harmonics that may spoil your data. A good way to estimate the\nfrequency space is to use e.g. Audacity or any audio equalizer to select the\nsegments of your audio that contain the sounds that you want to detect and\ncheck their dominant frequencies - you definitely want those frequencies to be\nincluded in your range.\n\n`--bins` specifies in how many segments/buckets the frequency spectrum should\nbe split - 100 bins is the default value. `--sample-duration` specifies the\nduration in seconds for each spectrum data point - 2 seconds is the default\nvalue, i.e. the audio samples will be read in chunks of 2 seconds each and the\nspectrum will be calculated for each of these chunks. If the sounds you want to\ndetect are shorter then you may want to reduce this value.\n\n### Generate the dataset via script\n\nThe other way to generate the dataset from the audio is through the *micmon* API\nitself. This option also enables you to take a peek at the audio data to better\ncalibrate the parameters. For example:\n\n```python\nimport os\n\nfrom micmon.audio import AudioDirectory, AudioPlayer, AudioFile\nfrom micmon.dataset import DatasetWriter\n\nbasedir = os.path.expanduser('~/datasets/sound-detect')\naudio_dir = os.path.join(basedir, 'audio')\ndatasets_dir = os.path.join(basedir, 'data')\ncutoff_frequencies = [250, 7500]\n\n# Scan the base audio_dir for labelled audio samples\naudio_dirs = AudioDirectory.scan(audio_dir)\n\n# Play some audio samples starting from 01:00\nfor audio_dir in audio_dirs:\n    with AudioFile(audio_dir, start='01:00', duration=5) as reader, \\\n            AudioPlayer() as player:\n        for sample in reader:\n            player.play(sample)\n\n# Plot the audio and spectrum of the audio samples in the first 10 seconds\n# of each audio file.\nfor audio_dir in audio_dirs:\n    with AudioFile(audio_dir, start=0, duration=10) as reader:\n        for sample in reader:\n            sample.plot_audio()\n            sample.plot_spectrum(low_freq=cutoff_frequencies[0],\n                                 high_freq=cutoff_frequencies[1])\n\n# Save the spectrum information and labels of the samples to a\n# different compressed file for each audio file.\nfor audio_dir in audio_dirs:\n    dataset_file = os.path.join(datasets_dir, os.path.basename(audio_dir.path) + '.npz')\n    print(f'Processing audio sample {audio_dir.path}')\n\n    with AudioFile(audio_dir) as reader, \\\n            DatasetWriter(dataset_file,\n                          low_freq=cutoff_frequencies[0],\n                          high_freq=cutoff_frequencies[1]) as writer:\n        for sample in reader:\n            writer += sample\n\n```\n\nTraining the model\n------------------\n\nOnce you have some `.npz` datasets saved under `~/datasets/sound-detect/data`, you can\nuse those datasets to train a Tensorflow model to classify an audio segment. A full\nexample is available under `examples/train.py`:\n\n```python\nimport os\nfrom tensorflow.keras import layers\n\nfrom micmon.dataset import Dataset\nfrom micmon.model import Model\n\n# This is a directory that contains the saved .npz dataset files\ndatasets_dir = os.path.expanduser('~/datasets/sound-detect/data')\n\n# This is the output directory where the model will be saved\nmodel_dir = os.path.expanduser('~/models/sound-detect')\n\n# This is the number of training epochs for each dataset sample\nepochs = 2\n\n# Load the datasets from the compressed files.\n# 70% of the data points will be included in the training set,\n# 30% of the data points will be included in the evaluation set\n# and used to evaluate the performance of the model.\ndatasets = Dataset.scan(datasets_dir, validation_split=0.3)\nlabels = ['negative', 'positive']\nfreq_bins = len(datasets[0].samples[0])\n\n# Create a network with 4 layers (one input layer, two intermediate layers and one output layer).\n# The first intermediate layer in this example will have twice the number of units as the number\n# of input units, while the second intermediate layer will have 75% of the number of\n# input units. We also specify the names for the labels and the low and high frequency range\n# used when sampling.\nmodel = Model(\n    [\n        layers.Input(shape=(freq_bins,)),\n        layers.Dense(int(2 * freq_bins), activation='relu'),\n        layers.Dense(int(0.75 * freq_bins), activation='relu'),\n        layers.Dense(len(labels), activation='softmax'),\n    ],\n    labels=labels,\n    low_freq=datasets[0].low_freq,\n    high_freq=datasets[0].high_freq\n)\n\n# Train the model\nfor epoch in range(epochs):\n    for i, dataset in enumerate(datasets):\n        print(f'[epoch {epoch+1}/{epochs}] [audio sample {i+1}/{len(datasets)}]')\n        model.fit(dataset)\n        evaluation = model.evaluate(dataset)\n        print(f'Validation set loss and accuracy: {evaluation}')\n\n# Save the model\nmodel.save(model_dir, overwrite=True)\n```\n\nAt the end of the process you should find your Tensorflow model saved under `~/models/sound-detect`.\nYou can use it in your scripts to classify audio samples from audio sources.\n\nClassifying audio samples\n-------------------------\n\nOne use case is to analyze an audio file and use the model to detect specific sounds. Example:\n\n```python\nimport os\n\nfrom micmon.audio import AudioFile\nfrom micmon.model import Model\n\nmodel_dir = os.path.expanduser('~/models/sound-detect')\nmodel = Model.load(model_dir)\ncur_seconds = 60\nsample_duration = 2\n\nwith AudioFile('/path/to/some/audio.mp3',\n               start=cur_seconds, duration='10:00',\n               sample_duration=sample_duration) as reader:\n    for sample in reader:\n        prediction = model.predict(sample)\n        print(f'Audio segment at {cur_seconds} seconds: {prediction}')\n        cur_seconds += sample_duration\n```\n\nAnother is to analyze live audio samples imported from an audio device - e.g. a USB microphone.\nExample:\n\n```python\nimport os\n\nfrom micmon.audio import AudioDevice\nfrom micmon.model import Model\n\nmodel_dir = os.path.expanduser('~/models/sound-detect')\nmodel = Model.load(model_dir)\naudio_system = 'alsa'        # Supported: alsa and pulse\naudio_device = 'plughw:1,0'  # Get list of recognized input devices with arecord -l\n\nwith AudioDevice(audio_system, device=audio_device) as source:\n    for sample in source:\n        source.pause()  # Pause recording while we process the frame\n        prediction = model.predict(sample)\n        print(prediction)\n        source.resume() # Resume recording\n```\n\nYou can use these two examples as blueprints to set up your own automation routines\nwith sound detection.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblacklight%2Fmicmon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblacklight%2Fmicmon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblacklight%2Fmicmon/lists"}