Skip to content

Commit

Permalink
minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesneimog committed Sep 24, 2024
1 parent 0b3b23a commit e278242
Show file tree
Hide file tree
Showing 40 changed files with 599 additions and 174 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# OScofo

**O**pen **SCO**re **FO**llower (OScofo) is a PureData object designed for contemporary music applications. This project aims to encourage collaboration among researchers and musicians for contemporary music. Here's what you need to know:
**O**pen **SCO**re **FO**llower (OScofo) is a PureData object is being designed for contemporary music applications. This project aims to encourage collaboration among researchers and musicians for contemporary music. Here's what you need to know:

## Goal

The goal of *OScofo* is to provide a simple, accessible tool for real-time score following. By keeping the software lightweight, it can be easily run on the web using the [pd4web](https://charlesneimog.github.io/pd4web/) platform, now the we can use PureData on Web Browsers. So finally we have something that can be run for rehearsals one click distance (without externals, OSs incompatibility, etc).
The aim of *OScofo* is to provide a straightforward and accessible tool for real-time score following. By keeping the software lightweight, it can run seamlessly on the web through the [pd4web](https://charlesneimog.github.io/pd4web/) platform, thanks to the ability to use PureData directly in web browsers. With _pd4web_ and _OScofo_ will be possible to use the software in rehearsals with just a single click, eliminating the need for external libraries, compatibility issues, or complex installations -- ultimately facilitating the sharing and performance of contemporary music.

## Collaboration and Contribution

I invite researchers and developers to contribute to the *OScofo* project. By sharing the source code, I am trying to provide access to the theories and mathematical formulas that drive the software. This transparency is inspired by the amazing tools like IEM, SPARTA, and of course, PureData. My main aim is artistic, maybe your research can help me and a lot of others composers.
I invite composers, researchers and developers to contribute to the *OScofo* project. Not just with code, but with theory, math, etc. I am trying to make OScofo acessible via a Python implementation, to test it should be easy. By sharing the source code, I am trying to provide access to the theories and mathematical formulas that drive the software, all this come from the amazing research work of Arshia Cont and Philippe Cuvillier at IRCAM. This transparency is inspired by the amazing tools like IEM, SPARTA, and of course, PureData.

## Technical Foundations

*OScofo* uses several concepts developed by many researches:

* **Score Language**: Based on the `scofo` (by Miller Puckette) and `antescofo~` (by Arshia Cont) language.
* **Pitch Comparison**: Utilizes the Kullback-Leibler (KL) Divergence method for pitch comparison as presented by Arshia Cont in 2008 and 2010.
* **Pitch Comparison**: Utilizes the Kullback-Leibler (KL) Divergence method for pitch comparison as presented by Christopher Raphael (2006), Arshia Cont in 2008 and 2010.
* **Rhythm Synchronization**: Integrates theories of rhythm synchronization developed by Edward Large and Mari Riess Jones (1999) and Edward Large and Caroline Palmer (2002), as presented for Cont (2010).
* **Descriptors**: Employs descriptors from Willian Brent's timbreIDLib project for analyzing and identifying timbral characteristics.
* **Forward Algorithm**: For now, *OScofo* uses the equation presented by Arshia Cont (2010) and developed by Yann Guédon (2005).
* **Score Language**: Based on the `scofo` (by Miller Puckette) and `antescofo~` (by Arshia Cont, Philippe Cuvillier, and others) language.

8 changes: 6 additions & 2 deletions Sources/OScofo/OScofo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ bool OScofo::ScoreIsLoaded() {
// │ Python Research and Test Functions │
// ╰─────────────────────────────────────╯
States OScofo::GetStates() {
return m_States;
if (m_States.size() != 0) {
return m_States;
}
printf("ok\n");
throw std::runtime_error("No states found, please use the ScoreParse first");
}

// ─────────────────────────────────────
Expand Down Expand Up @@ -115,7 +119,7 @@ std::vector<double> OScofo::GaussianProbTimeOnset(int j, double sigma) {
// │ Main Functions │
// ╰─────────────────────────────────────╯
bool OScofo::ParseScore(std::string ScorePath) {
m_Score.Parse(m_States, ScorePath);
m_States = m_Score.Parse(ScorePath);
m_MDP.SetScoreStates(m_States);
return true;
}
Expand Down
12 changes: 6 additions & 6 deletions Sources/OScofo/mdp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ double OScofoMDP::GaussianProbTimeOnset(int j, int T, double Sigma) {
int OScofoMDP::Inference(int CurrentState, int MaxState, int T) {
double MaxValue = -std::numeric_limits<double>::infinity();
int BestState = CurrentState;
m_Nt = 0;

for (int j = CurrentState; j <= MaxState; j++) {
if (j < 0)
Expand All @@ -477,7 +478,6 @@ int OScofoMDP::Inference(int CurrentState, int MaxState, int T) {
if (T == 0) {
StateJ.Forward[bufferIndex] = StateJ.Obs[bufferIndex] * GetSojournTime(StateJ, T + 1) * StateJ.InitProb;
} else {
double GaussianTimeLine = GaussianProbTimeOnset(j, T, 500);
double Obs = StateJ.Obs[bufferIndex];
double MaxAlpha = -std::numeric_limits<double>::infinity();
for (int u = 1; u <= std::min(T, GetMaxUForJ(StateJ)); u++) {
Expand All @@ -488,25 +488,25 @@ int OScofoMDP::Inference(int CurrentState, int MaxState, int T) {
}
double Sur = GetSojournTime(StateJ, u);
double MaxTrans = -std::numeric_limits<double>::infinity();
for (int i = CurrentState; i <= j; i++) { // TODO: Moficar para Current State (no -1)
for (int i = CurrentState; i <= j; i++) {
if (i < 0) {
continue;
}
MacroState &StateI = m_States[i];
if (i != j) {
int PrevIndex = (bufferIndex - u + BUFFER_SIZE) % BUFFER_SIZE;
int PrevIndex = (T - u) % BUFFER_SIZE;
MaxTrans = std::max(MaxTrans, GetTransProbability(i, j) * StateI.Forward[PrevIndex]);
} else {
// TODO: Criar subdescrições do evento atual

// Self transition (this is not compatible with Guedon (2005))
int PrevIndex = (bufferIndex - u + BUFFER_SIZE) % BUFFER_SIZE;
int PrevIndex = (T - u) % BUFFER_SIZE;
MaxTrans = std::max(MaxTrans, StateJ.Forward[PrevIndex]);
}
}
double MaxResult = ProbPrevObs * Sur * MaxTrans;
MaxAlpha = std::max(MaxAlpha, MaxResult);
}
StateJ.Forward[bufferIndex] = Obs * MaxAlpha * GaussianTimeLine;
StateJ.Forward[bufferIndex] = Obs * MaxAlpha;
}
}

Expand Down
1 change: 1 addition & 0 deletions Sources/OScofo/mdp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class OScofoMDP {

// Markov
std::vector<double> m_N;
double m_Nt;
bool m_EventDetected = false;
double GetBestEvent(Description &Desc);
double GetPitchSimilarity(MacroState &NextPossibleState, Description &Desc);
Expand Down
10 changes: 5 additions & 5 deletions Sources/OScofo/mir.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "mir.hpp"

#include <algorithm>
#include <math.h>
#include <vector>

Expand Down Expand Up @@ -54,7 +55,6 @@ OScofoMIR::~OScofoMIR() {
// ╭─────────────────────────────────────╮
// │ Utils │
// ╰─────────────────────────────────────╯
// ─────────────────────────────────────
double OScofoMIR::Mtof(double note, double tunning) {
return tunning * std::pow(2.0, (note - 69) / 12.0);
}
Expand All @@ -65,9 +65,9 @@ double OScofoMIR::Ftom(double freq, double tunning) {
}

// ─────────────────────────────────────
double OScofoMIR::Freq2Bin(double freq, double n, double sr) {
double OScofoMIR::Freq2Bin(double Freq, double n, double sr) {
double bin;
bin = freq * n / sr;
bin = Freq * n / sr;
return round(bin);
}

Expand All @@ -81,8 +81,8 @@ void OScofoMIR::SetdBTreshold(double dB) {
// ╭─────────────────────────────────────╮
// │ Pitch Observation │
// ╰─────────────────────────────────────╯
void OScofoMIR::GetFFTDescriptions(const std::vector<double> &In, Description &Desc) {

void OScofoMIR::GetFFTDescriptions(std::vector<double> &In, Description &Desc) {
int N = In.size();
int NHalf = N / 2;

Expand Down Expand Up @@ -134,7 +134,7 @@ void OScofoMIR::GetFFTDescriptions(const std::vector<double> &In, Description &D
// ╭─────────────────────────────────────╮
// │ RMS │
// ╰─────────────────────────────────────╯
void OScofoMIR::GetRMS(const std::vector<double> &In, Description &Desc) {
void OScofoMIR::GetRMS(std::vector<double> &In, Description &Desc) {
double sumOfSquares = 0.0;
for (double sample : In) {
sumOfSquares += sample * sample;
Expand Down
4 changes: 2 additions & 2 deletions Sources/OScofo/mir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ class OScofoMIR {
double *m_FFTIn;
fftw_complex *m_FFTOut;
fftw_plan m_FFTPlan;
void GetFFTDescriptions(const std::vector<double> &In, Description &Desc);
void GetFFTDescriptions(std::vector<double> &In, Description &Desc);

// Env
double m_dBTreshold = -50;
void GetRMS(const std::vector<double> &In, Description &Desc);
void GetRMS(std::vector<double> &In, Description &Desc);

// Audio
double m_FftSize;
Expand Down
2 changes: 1 addition & 1 deletion Sources/OScofo/score.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

class OScofoScore {
public:
void Parse(States &States, std::string ScoreFile);
States Parse(std::string ScoreFile);
void SetTunning(double Tunning);
bool ScoreIsLoaded();

Expand Down
12 changes: 9 additions & 3 deletions Sources/OScofo/states.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,15 @@ class MacroState {
int Line;

std::string __repr__() const {
std::ostringstream oss;
oss << "State(Index=" << Index << ", ScorePosition=" << ScorePos << ", BPMExpected=" << BPMExpected << ")";
return oss.str();
std::string oss;
oss = "<<State(Index=";
oss += std::to_string(Index);
oss += ", ScorePosition=";
oss += std::to_string(ScorePos);
oss += ", BPMExpected=";
oss += std::to_string(BPMExpected);
oss += ")>>";
return oss;
}
};

Expand Down
Binary file added Tests/BWV-1013/audio.wav
Binary file not shown.
Binary file added Tests/BWV-1013/bwv1013.mscz
Binary file not shown.
81 changes: 81 additions & 0 deletions Tests/BWV-1013/expected.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
0.32,1
0.448,2
0.63,3
0.811,4
0.992,5
1.184,6
1.376,7
1.568,8
1.75,9
1.942,10
2.123,11
2.315,12
2.496,13
2.688,14
2.88,15
3.062,16
3.254,17
3.446,18
3.638,19
3.798,20
3.99,21
4.192,22
4.374,23
4.555,24
4.747,25
4.939,26
5.12,27
5.387,28
5.504,29
5.686,30
5.888,31
6.059,32
6.251,33
6.443,34
6.635,35
6.806,36
6.998,37
7.19,38
7.382,39
7.552,40
7.744,41
7.936,42
8.128,43
8.374,44
8.502,45
8.683,46
8.896,47
9.067,48
9.248,49
9.451,50
9.632,51
9.835,52
10.006,53
10.187,54
10.379,55
10.571,56
10.752,57
10.955,58
11.136,59
11.318,60
11.488,61
11.702,62
11.872,63
12.064,64
12.267,65
12.438,66
12.63,67
12.822,68
13.003,69
13.195,70
13.366,71
13.558,72
13.75,73
13.942,74
14.123,75
14.315,76
14.507,77
14.688,78
14.891,79
15.072,80
15.272,81
19 changes: 19 additions & 0 deletions Tests/BWV-1013/pd.pd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#N canvas 963 23 951 1016 10;
#X obj 13 259 o.scofo~, f 18;
#X msg 68 205 score score.txt;
#X obj 13 283 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0 256;
#X msg 55 175 start;
#X obj 13 77 readsf~;
#X msg 13 30 open audio.wav \, 1;
#X obj 118 284 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0 256;
#X obj 44 119 dac~;
#X obj 13 152 *~ 1;
#X connect 0 0 2 0;
#X connect 0 1 6 0;
#X connect 1 0 0 0;
#X connect 3 0 0 0;
#X connect 4 0 7 0;
#X connect 4 0 7 1;
#X connect 4 0 8 0;
#X connect 5 0 4 0;
#X connect 8 0 0 0;
28 changes: 28 additions & 0 deletions Tests/BWV-1013/result.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
0.202,1,118.0,True
0.351,2,97.0,True
0.415,9,1335.0,False
1.248,10,694.0,False
1.386,11,737.0,False
1.557,12,758.0,False
1.706,13,790.0,False
1.855,14,833.0,False
2.005,15,875.0,False
2.197,16,865.0,False
2.453,17,801.0,False
2.656,19,982.0,False
2.858,28,2529.0,False
2.869,37,4129.0,False
2.933,43,5195.0,False
3.37,44,5004.0,False
3.594,45,4908.0,False
3.733,49,5515.0,False
3.893,50,5558.0,False
3.904,52,5931.0,False
4.074,57,6678.0,False
4.096,58,6859.0,False
4.106,69,8897.0,False
4.554,73,9196.0,False
4.672,77,9835.0,False
4.832,78,9856.0,False
4.896,79,9995.0,False
5.471,81,9801.0,False
Loading

0 comments on commit e278242

Please sign in to comment.