Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
5cc4c1d
Rearranging old code, start of bfclassifier class
jkranabetter Sep 23, 2021
d8255ff
Licence + readme update
jkranabetter Sep 23, 2021
0522483
Update bf_classifier.py
jkranabetter Sep 23, 2021
7ab0802
Start on essentia engine
jkranabetter Sep 23, 2021
97d04b1
Getting Silence Rate
jkranabetter Sep 23, 2021
dfe3148
Get the 10 chosen features manually
jkranabetter Sep 28, 2021
00158c7
Begin work on segmenter
jkranabetter Sep 30, 2021
ec6e265
Create datasets
jkranabetter Oct 1, 2021
ddaa3ac
completed segmenter regionschunk class
jkranabetter Oct 1, 2021
ef3fbe6
Work on engine
jkranabetter Oct 1, 2021
727561a
fix replay gain
jkranabetter Oct 1, 2021
556a2bc
bulk bug fixes
jkranabetter Oct 1, 2021
355014d
Working classifier model
jkranabetter Oct 1, 2021
947c3ec
Running Segmenter
jkranabetter Oct 1, 2021
26cb0b4
Update descriptions, delete unused code
jkranabetter Oct 1, 2021
e212a37
testing
jkranabetter Oct 7, 2021
ce6cc2f
k mean clustering working for fg
jkranabetter Oct 7, 2021
ccd310b
Fix start time bug
jkranabetter Oct 11, 2021
9ba3a65
orginize segmenter
jkranabetter Oct 11, 2021
6915a06
Create teststuff.py
jkranabetter Oct 12, 2021
54d3eda
Create valencearousal_training.csv
jkranabetter Oct 12, 2021
21317cb
Affectror predictor done - still needs accuracy improvements
jkranabetter Oct 13, 2021
ad07697
update training data and ordering
jkranabetter Oct 13, 2021
4d4d422
troubleshooting read arousal data
jkranabetter Oct 13, 2021
36b1365
fix training data for valencearousal
jkranabetter Oct 13, 2021
945de9d
Working affector predictor
jkranabetter Oct 13, 2021
de36dad
add test datasets
jkranabetter Oct 18, 2021
0eacb50
Updating to 150 features
jkranabetter Oct 19, 2021
64c5f89
working bf prediction with 150 feats
jkranabetter Oct 19, 2021
d18c4c7
Create valencearousal_training1.csv
jkranabetter Oct 19, 2021
b6c785d
convert valence model to more feats
jkranabetter Oct 19, 2021
0781e22
Update kernel to linear
jkranabetter Oct 19, 2021
96fffb4
progress on new extractor
jkranabetter Nov 17, 2021
73fc839
further work on new extractor
jkranabetter Nov 17, 2021
32d4d87
Update processing.py
jkranabetter Nov 17, 2021
df08cdf
i think its working
jkranabetter Nov 17, 2021
ce70b0b
working segmenter
jkranabetter Nov 17, 2021
65ae3e6
Update bf_classifier.py
jkranabetter Nov 17, 2021
6674b40
Add testing script
jkranabetter Nov 17, 2021
a5fab4e
update test sounds, delete old data
jkranabetter Nov 18, 2021
9ec769f
Update naming for db + testing update
jkranabetter Nov 18, 2021
31433a2
Merge branch 'main' into update-bf-model
jkranabetter Nov 29, 2021
39c32d5
Merge pull request #2 from jkranabetter/update-bf-model
jkranabetter Nov 29, 2021
376b0c8
implemented models, need to integrate into segmenter now
jkranabetter Nov 29, 2021
29254d0
Update README.md
jkranabetter Nov 30, 2021
4ec49b8
Update README.md
jkranabetter Nov 30, 2021
65d560d
Update README.md
jkranabetter Nov 30, 2021
5c6f9f6
cleanup
jkranabetter Nov 30, 2021
1a1030e
replace bool mask with int for readability
jkranabetter Nov 30, 2021
506b68e
working valence and arousal with final models
jkranabetter Nov 30, 2021
423b608
Merge pull request #3 from jkranabetter/update-emotion-prediction-models
jkranabetter Nov 30, 2021
a65ae20
converting bf classifier
jkranabetter Dec 8, 2021
423a384
Update features_BF200.csv
jkranabetter Dec 8, 2021
22bfc80
Merge branch 'variable-window-sizes' of https://github.com/jkranabett…
jkranabetter Dec 8, 2021
a1e8e4b
update type reverse bug
jkranabetter Dec 8, 2021
98e3d7b
Merge pull request #4 from jkranabetter/variable-window-sizes
jkranabetter Dec 8, 2021
fe8ecb6
add probability smoothing and max posterior
jkranabetter Dec 8, 2021
588d76d
filter window testing, full plots working
jkranabetter Dec 14, 2021
e3c1028
update chart
jkranabetter Dec 15, 2021
9981d70
added margin smoothing
jkranabetter Dec 15, 2021
17a58c0
add more test sound files
jkranabetter Dec 15, 2021
04cb457
remove long files and comments
jkranabetter Dec 15, 2021
b3be7bd
Create 242142-City_street_large_vendors_shouting_voices_traffic_and_a…
jkranabetter Dec 15, 2021
522b072
testing
jkranabetter Dec 15, 2021
a2cc697
add test files
jkranabetter Dec 15, 2021
dd95b9a
Code cleanup + removed residual feats
jkranabetter Dec 21, 2021
6b1a009
Merge pull request #8 from jkranabetter/remove-residual-features-in-d…
jkranabetter Dec 21, 2021
d78f994
Merge pull request #9 from jkranabetter/developement
jkranabetter Dec 21, 2021
d28f39d
update style + formatting
jkranabetter Dec 21, 2021
2626645
Merge pull request #12 from jkranabetter/update-style
jkranabetter Dec 21, 2021
d9067bc
add regressor
jkranabetter Dec 22, 2021
630483f
Testing
jkranabetter Dec 22, 2021
7cbfcd0
Ridge testing
jkranabetter Dec 22, 2021
17a9034
Testing on BF90
jkranabetter Dec 22, 2021
5c41128
testing
jkranabetter Dec 23, 2021
dcbd119
updated clustering
jkranabetter Dec 29, 2021
60bde69
generate text labels
jkranabetter Dec 30, 2021
afe455e
extracting segments
jkranabetter Dec 30, 2021
40ca930
Merge pull request #14 from jkranabetter/BF90-Testing
jkranabetter Jan 1, 2022
3ab80e6
testing
jkranabetter Jan 2, 2022
beba3c7
testing
jkranabetter Jan 4, 2022
866cc57
update model data for emotion prediction
jkranabetter Jan 17, 2022
38e8d4a
Continue update of emo prediction
jkranabetter Jan 17, 2022
fc2a0d5
Update affect_predictor.py
jkranabetter Jan 17, 2022
61d78b6
remove unwanted segmentation algorithms
jkranabetter Jan 17, 2022
7fc3edd
cleanup
jkranabetter Jan 17, 2022
53eca06
Cleanup
jkranabetter Mar 19, 2022
654f45e
Cleanup
jkranabetter Apr 20, 2022
dd54615
Merge pull request #16 from jkranabetter/developement
jkranabetter Apr 20, 2022
f743b5e
create requirements
jkranabetter Apr 20, 2022
0d08b05
testing
jkranabetter May 12, 2022
1a98a09
working on copus create
jkranabetter May 12, 2022
ecbdfb5
Update util_corpus_create.py
jkranabetter May 12, 2022
0ba339c
Update util_corpus_create.py
jkranabetter May 12, 2022
5a678b9
Create r_pepperonijim.wav
jkranabetter May 12, 2022
77d86b4
update from wav
jkranabetter May 12, 2022
db2fe9e
testing
jkranabetter May 12, 2022
cec65d7
working
jkranabetter May 12, 2022
1b0a1dd
testing
jkranabetter May 12, 2022
d4c146e
Readme Updates + Cleanup
jkranabetter Jul 4, 2022
5e2f14e
Update readme
jkranabetter Jul 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 1 addition & 119 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,105 +1,5 @@
# Byte-compiled / optimized / DLL files
# Python Cache
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
Expand All @@ -109,21 +9,3 @@ venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 Miles Thorogood
Copyright (c) 2022 Miles Thorogood, Joshua Kranabetter

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
51 changes: 28 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
# BFsegmenter
# BFSegmenter

## Requirements:
The BFSegmenter segments audio files and classifies each segment as background, foreground, or background with foreground. Additionaly, for each segment the affect is predicted on a scale of valence and arousal.

sklearn
![Pipeline](/images/pipeline.png)

numpy
Sound designers and soundscape composers manually segment audio files into building blocks for use in a composition. **Machine learning (ridge regression)** is used to classify segments in an audio file automatically. The model has a **83.0% true positive classification rate**.

matplotlib
Russel’s model
suggests all emotions are distributed in a circular space (https://psycnet.apa.org/record/1981-25062-001).
High levels of valence correspond to pleasant sounds while
low valence levels correspond to unpleasant sounds. Further, high levels of arousal correspond to exciting sounds while low levels correspond to calming sounds. **Levels of valence and arousal are quantified using machine learning for emotion prediction (random forest regression)**. The emotion prediction models use a subset of extracted features to predict valence and arousal on a scale from -1 to 1 for each segment in an audio file.

sqlite3
![Affect Accuracy](/images/affect_accuracy.png)

Python 2.7 (porting to Python 3 is a task)
Example implimentation of the segmenter in *extract_audacity_labels.py*.

YAAFE https://github.com/Yaafe/Yaafe
## Segment format

pydub https://github.com/jiaaro/pydub
bf type
duration
start
end
features
arousal
valence
bf probabilities

## TODO:
## Dependancies
Essentia - an open-source library for tools for audio and music analysis, description and synthesis. https://essentia.upf.edu/

port to Python 3
Scikit-learn - a free software machine learning library for the Python programming language.

corpusAuquireDir.py
For full requirements, check *requirements.txt*.

svnsegmenter.py
## Authors

bf_classifier.py
- Miles Thorogood
- Joshua Kranabetter

affect_predictor.py
## License

yaafeEngine.py

## Running
python corpusAquireDir.py /path/to/audio/files

audio files are aif or wav

segments the files in the directory and puts the segs into SegmentedCorpus
This project is licensed under the MIT License - see the *LICENSE* file for details.
101 changes: 43 additions & 58 deletions affect_predictor.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,51 @@

#!/usr/bin/env python

import numpy as np
import csv
import matplotlib.pyplot as plt
from sklearn import linear_model
import math
from sklearn.ensemble import RandomForestRegressor

class AffectPredict:
"""docstring for AffectPredict"""

'''
Emotion prediction models for valence and arousal.
'''
def __init__(self):
# masks to select features
self.AROUSAL_MASK = [11, 27, 29, 30, 33, 34, 48, 80, 89, 98, 110, 117, 118, 127, 128, 131, 133, 146, 166, 171, 203, 204, 219, 221, 236, 239, 261, 262, 264, 266, 267, 268, 343, 346, 347, 348, 349, 354, 355, 356, 364, 377, 379, 382, 383, 397, 437, 448, 450, 455, 463, 467, 468, 475, 478, 485, 487, 488, 491, 494, 497, 498, 508, 512, 518, 527, 529, 530, 531, 537, 539, 541, 544, 550, 557, 560, 573, 576, 580, 583, 584, 588, 596, 599, 602]
self.VALENCE_MASK = [0, 12, 27, 29, 31, 32, 33, 35, 37, 39, 42, 45, 46, 48, 49, 53, 55, 75, 79, 86, 87, 89, 91, 93, 95, 104, 106, 118, 127, 131, 133, 134, 135, 138, 140, 148, 152, 155, 156, 157, 158, 159, 161, 166, 175, 180, 182, 183, 185, 186, 187, 188, 189, 195, 197, 200, 206, 207, 216, 218, 221, 227, 231, 242, 245, 248, 249, 254, 255, 256, 257, 264, 269, 270, 334, 335, 337, 339, 341, 353, 354, 357, 360, 364, 366, 367, 369, 370, 371, 373, 374, 376, 377, 378, 380, 381, 382, 384, 388, 389, 391, 393, 395, 398, 411, 412, 415, 416, 417, 418, 419, 423, 424, 425, 431, 432, 433, 435, 436, 437, 438, 443, 445, 449, 451, 458, 461, 462, 466, 468, 469, 470, 471, 473, 474, 475, 481, 482, 483, 485, 488, 489, 496, 497, 498, 499, 501, 505, 517, 518, 521, 523, 526, 528, 529, 530, 534, 535, 537, 539, 540, 542, 543, 544, 545, 549, 550, 553, 554, 555, 560, 563, 568, 573, 575, 577, 580, 583, 584, 585, 586, 599, 602]

f = open('studyData_.csv','rb')

self.header = f.readline().split(',')
training_data = np.loadtxt(f,delimiter=",",skiprows=1)

self.Y = training_data[:,0:2] # first two colums are valence and arousal
self.X = training_data[:,2:len(training_data)] # remaining columns are audio features

assert len(self.Y) == len(self.X)

self.valence_model = linear_model.LinearRegression() # Ridge (alpha = .5)
self.valence_model.fit(self.X,self.Y[:,0])

self.arousal_model = linear_model.LinearRegression()
self.arousal_model.fit(self.X,self.Y[:,1])


fa = open('datasets/arousal_data.csv','r')
fv = open('datasets/valence_data.csv','r')

self.arousal_header = fa.readline().split(',')
self.valence_header = fv.readline().split(',')

arousal_data = np.loadtxt(fa,delimiter=",")
valence_data = np.loadtxt(fv,delimiter=",")

self.arousal_y = arousal_data[:,-1:]
self.arousal_X = arousal_data[:,0:-1]
self.valence_y = valence_data[:,-1:]
self.valence_X = valence_data[:,0:-1]

# verify correct training data length
assert len(self.arousal_X) == len(self.arousal_y)
assert len(self.valence_X) == len(self.valence_y)

# apply mask to get select features only
self.arousal_X = [x[self.AROUSAL_MASK] for x in self.arousal_X]
self.valence_X = [x[self.VALENCE_MASK] for x in self.valence_X]

# create arousal model
self.arousal_model = RandomForestRegressor(max_depth=20, min_samples_split=5, oob_score=True)
self.arousal_model.fit(self.arousal_X, self.arousal_y.ravel())

# create valence model
self.valence_model = RandomForestRegressor(max_depth=30, min_samples_leaf=2, min_samples_split=5, oob_score=True)
self.valence_model.fit(self.valence_X, self.valence_y.ravel())

def predict_valence(self, Z):

return self.valence_model.predict(Z)

def predict_arousal(self, Z):

return self.arousal_model.predict(Z)

def model_stats(self):
return self.valence_model.predict([Z]).item(0)

print("Valence RSS: %.2f"
% np.mean((self.valence_model.predict(self.X) - self.Y[:,0]) ** 2))
print("Arousal RSS: %.2f"
% np.mean((self.arousal_model.predict(self.X) - self.Y[:,1]) ** 2))
print('Valence variance score: %.2f' % self.valence_model.score(self.X, self.Y[:,0]))
print('Arousal variance score: %.2f' % self.arousal_model.score(self.X, self.Y[:,1]))

def visualize_model(self, x, y, m, c):
'''
TODO: needs finxin
'''
w = 2
h = 2#math.floor(len(y)/2)
f, axarr = plt.subplots(w,h)
count = 0
for i in range(w):
for j in range(h):
axarr[i,j].plot(x[:,count], y, 'o', markersize=3) # label='Original data'
axarr[i,j].plot(x[:,count], m[count]*x[:,count]+c, 'r') # label='Fitted line'
axarr[i,j].set_title(self.header[2+count])
#axarr[i,j].set_yscale('exp')
count += 1
def predict_arousal(self, Z):
return self.arousal_model.predict([Z]).item(0)

plt.legend()
plt.show()
def model_stats(self):
print('arousal r-squared score: %.2f' % self.arousal_model.oob_score_)
print('valence r-squared score: %.2f' % self.valence_model.oob_score_)
Loading