Warped Audio Sample












7














I was asked this question and got no feedback, so I'd like to ask you for any feedback on my solution, Thanks!



Think of an audio sample as a rubber-band that you want to pin to a musical time ruler. The pins are called Warp Markers. A Warp Marker locks a specific point in the sample (in sample time) to a specific place in a measure (in beat time). You can use any number of Warp Markers to create an arbitrary mapping of the sample’s inherent rhythm to a musical meter. For the sake of this task, please assume the following behavior:




  1. An audio clip contains a reference to a sample and a collection of Warp Markers.

  2. There is at least one Warp Marker in the clip.

  3. Between two Warp Markers, the tempo is constant.

  4. The tempo before the first Warp Marker is the same as the tempo after the first Warp
    Marker.

  5. The tempo after the last Warp Marker is specified separately in the input.

  6. Beat time is measured in beats, sample time is measured in seconds, and tempo is
    measured in beats per second.
    Input description


There are 4 kinds of lines in the input:




  1. Warp Marker definition

  2. Definition of the tempo after the last marker

  3. Sample time to beat time conversion

  4. Beat time to sample time conversion


At least one Warp Marker and the tempo after the last Warp Marker should be defined before the first conversion; otherwise, these can appear in any order.
Each line consists of a keyword followed by numeric arguments. All numeric values are entered as doubles without units. Warp Marker and tempo definitions affect only the conversions that come later in the input.



marker <beat time> <sample time>
end_tempo <value>
s2b <sample time>
b2s <beat time>


Output description
For each of the s2b and b2s lines, the corresponding output time is printed without unit. Example



Input
marker 0.0 0.0
marker 1.0 5.0
end_tempo 10.0
b2s 0.5
s2b 6.0
Output
2.5 11.0


Here's my solution:



//one.h

#include <vector>
#include <string>
#include <map>

using namespace std;

#ifndef SAMPLER_H
#define SAMPLER_H

class Sampler {
public:
map<double, double> beats = {};
map<double, double> samples = {};
double endTempo;
void addMarker(double beat, double sample);
double b2s(double beat);
double s2b(double sample);
};

#endif


and



// one.cc

#include "one.h"

using namespace std;

void Sampler::addMarker(double beat, double sample) {
beats[beat] = sample;
samples[sample] = beat;
}

double Sampler::b2s(double beat) {
auto marker2 = beats.upper_bound(beat);

if(marker2 == beats.begin()) marker2 = next(marker2);

auto marker1 = prev(marker2);

auto firstBeat = marker1->first;
auto firstSample = marker1->second;

double tempo;

if(marker2 == beats.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->first;
auto secondSample = marker2->second;

tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstSample + ((beat - firstBeat) / tempo);
}

double Sampler::s2b(double sample) {
auto marker2 = samples.upper_bound(sample);
if(marker2 == samples.begin()) marker2 = next(marker2);
auto marker1 = prev(marker2);

auto firstBeat = marker1->second;
auto firstSample = marker1->first;

double tempo;

if(marker2 == samples.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->second;
auto secondSample = marker2->first;
tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstBeat + ((sample - firstSample) * tempo);
}


and here's main



#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include "one.h"

int main() {
Sampler sampler;
string str;
while(true) {
getline(cin, str);
istringstream ss(str);
string command;
getline(ss, command, ' ');

if(command == "marker") {
string strBeat;
string strSample;
getline(ss, strBeat, ' ');
getline(ss, strSample, ' ');
double beat = stod(strBeat);
double sample = stod(strSample);
sampler.addMarker(beat, sample);
} else if(command == "end_tempo") {
string strTempo;
getline(ss, strTempo, ' ');
sampler.endTempo = stod(strTempo);
} else if(command == "s2b") {
string s;
getline(ss, s, ' ');
cout << sampler.s2b(stod(s)) << endl;
} else if(command == "b2s") {
string b;
getline(ss, b, ' ');
cout << sampler.b2s(stod(b)) << endl;
} else {
break;
}
}
}


and heres my tests



#include "one.h"
#include "gtest/gtest.h"
namespace {

class OneMarker : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(3, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(OneMarker, Before) {
EXPECT_EQ(4.6, sampler->b2s(-1));
EXPECT_EQ(-57, sampler->s2b(-1));
}

TEST_F(OneMarker, After) {
EXPECT_EQ(5.7, sampler->b2s(10));
EXPECT_EQ(53, sampler->s2b(10));
}

class TwoMarkers : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(0, 0);
sampler->addMarker(1, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(TwoMarkers, Before) {
EXPECT_EQ(-5.0, sampler->b2s(-1));
EXPECT_EQ(-0.2, sampler->s2b(-1));
}

TEST_F(TwoMarkers, Between) {
EXPECT_EQ(2.5, sampler->b2s(0.5));
EXPECT_EQ(11.0, sampler->s2b(6.0));
}

TEST_F(TwoMarkers, After) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
}

TEST_F(TwoMarkers, Mutation) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
sampler->addMarker(3,6);
EXPECT_EQ(6.7, sampler->b2s(10));
EXPECT_EQ(43, sampler->s2b(10));
}
}









share|improve this question


















  • 1




    FYI, I considered reviewing your earlier question but could not understand what it was supposed to do. This explanation is much clearer to me.
    – Edward
    Dec 16 at 17:43
















7














I was asked this question and got no feedback, so I'd like to ask you for any feedback on my solution, Thanks!



Think of an audio sample as a rubber-band that you want to pin to a musical time ruler. The pins are called Warp Markers. A Warp Marker locks a specific point in the sample (in sample time) to a specific place in a measure (in beat time). You can use any number of Warp Markers to create an arbitrary mapping of the sample’s inherent rhythm to a musical meter. For the sake of this task, please assume the following behavior:




  1. An audio clip contains a reference to a sample and a collection of Warp Markers.

  2. There is at least one Warp Marker in the clip.

  3. Between two Warp Markers, the tempo is constant.

  4. The tempo before the first Warp Marker is the same as the tempo after the first Warp
    Marker.

  5. The tempo after the last Warp Marker is specified separately in the input.

  6. Beat time is measured in beats, sample time is measured in seconds, and tempo is
    measured in beats per second.
    Input description


There are 4 kinds of lines in the input:




  1. Warp Marker definition

  2. Definition of the tempo after the last marker

  3. Sample time to beat time conversion

  4. Beat time to sample time conversion


At least one Warp Marker and the tempo after the last Warp Marker should be defined before the first conversion; otherwise, these can appear in any order.
Each line consists of a keyword followed by numeric arguments. All numeric values are entered as doubles without units. Warp Marker and tempo definitions affect only the conversions that come later in the input.



marker <beat time> <sample time>
end_tempo <value>
s2b <sample time>
b2s <beat time>


Output description
For each of the s2b and b2s lines, the corresponding output time is printed without unit. Example



Input
marker 0.0 0.0
marker 1.0 5.0
end_tempo 10.0
b2s 0.5
s2b 6.0
Output
2.5 11.0


Here's my solution:



//one.h

#include <vector>
#include <string>
#include <map>

using namespace std;

#ifndef SAMPLER_H
#define SAMPLER_H

class Sampler {
public:
map<double, double> beats = {};
map<double, double> samples = {};
double endTempo;
void addMarker(double beat, double sample);
double b2s(double beat);
double s2b(double sample);
};

#endif


and



// one.cc

#include "one.h"

using namespace std;

void Sampler::addMarker(double beat, double sample) {
beats[beat] = sample;
samples[sample] = beat;
}

double Sampler::b2s(double beat) {
auto marker2 = beats.upper_bound(beat);

if(marker2 == beats.begin()) marker2 = next(marker2);

auto marker1 = prev(marker2);

auto firstBeat = marker1->first;
auto firstSample = marker1->second;

double tempo;

if(marker2 == beats.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->first;
auto secondSample = marker2->second;

tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstSample + ((beat - firstBeat) / tempo);
}

double Sampler::s2b(double sample) {
auto marker2 = samples.upper_bound(sample);
if(marker2 == samples.begin()) marker2 = next(marker2);
auto marker1 = prev(marker2);

auto firstBeat = marker1->second;
auto firstSample = marker1->first;

double tempo;

if(marker2 == samples.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->second;
auto secondSample = marker2->first;
tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstBeat + ((sample - firstSample) * tempo);
}


and here's main



#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include "one.h"

int main() {
Sampler sampler;
string str;
while(true) {
getline(cin, str);
istringstream ss(str);
string command;
getline(ss, command, ' ');

if(command == "marker") {
string strBeat;
string strSample;
getline(ss, strBeat, ' ');
getline(ss, strSample, ' ');
double beat = stod(strBeat);
double sample = stod(strSample);
sampler.addMarker(beat, sample);
} else if(command == "end_tempo") {
string strTempo;
getline(ss, strTempo, ' ');
sampler.endTempo = stod(strTempo);
} else if(command == "s2b") {
string s;
getline(ss, s, ' ');
cout << sampler.s2b(stod(s)) << endl;
} else if(command == "b2s") {
string b;
getline(ss, b, ' ');
cout << sampler.b2s(stod(b)) << endl;
} else {
break;
}
}
}


and heres my tests



#include "one.h"
#include "gtest/gtest.h"
namespace {

class OneMarker : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(3, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(OneMarker, Before) {
EXPECT_EQ(4.6, sampler->b2s(-1));
EXPECT_EQ(-57, sampler->s2b(-1));
}

TEST_F(OneMarker, After) {
EXPECT_EQ(5.7, sampler->b2s(10));
EXPECT_EQ(53, sampler->s2b(10));
}

class TwoMarkers : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(0, 0);
sampler->addMarker(1, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(TwoMarkers, Before) {
EXPECT_EQ(-5.0, sampler->b2s(-1));
EXPECT_EQ(-0.2, sampler->s2b(-1));
}

TEST_F(TwoMarkers, Between) {
EXPECT_EQ(2.5, sampler->b2s(0.5));
EXPECT_EQ(11.0, sampler->s2b(6.0));
}

TEST_F(TwoMarkers, After) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
}

TEST_F(TwoMarkers, Mutation) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
sampler->addMarker(3,6);
EXPECT_EQ(6.7, sampler->b2s(10));
EXPECT_EQ(43, sampler->s2b(10));
}
}









share|improve this question


















  • 1




    FYI, I considered reviewing your earlier question but could not understand what it was supposed to do. This explanation is much clearer to me.
    – Edward
    Dec 16 at 17:43














7












7








7


1





I was asked this question and got no feedback, so I'd like to ask you for any feedback on my solution, Thanks!



Think of an audio sample as a rubber-band that you want to pin to a musical time ruler. The pins are called Warp Markers. A Warp Marker locks a specific point in the sample (in sample time) to a specific place in a measure (in beat time). You can use any number of Warp Markers to create an arbitrary mapping of the sample’s inherent rhythm to a musical meter. For the sake of this task, please assume the following behavior:




  1. An audio clip contains a reference to a sample and a collection of Warp Markers.

  2. There is at least one Warp Marker in the clip.

  3. Between two Warp Markers, the tempo is constant.

  4. The tempo before the first Warp Marker is the same as the tempo after the first Warp
    Marker.

  5. The tempo after the last Warp Marker is specified separately in the input.

  6. Beat time is measured in beats, sample time is measured in seconds, and tempo is
    measured in beats per second.
    Input description


There are 4 kinds of lines in the input:




  1. Warp Marker definition

  2. Definition of the tempo after the last marker

  3. Sample time to beat time conversion

  4. Beat time to sample time conversion


At least one Warp Marker and the tempo after the last Warp Marker should be defined before the first conversion; otherwise, these can appear in any order.
Each line consists of a keyword followed by numeric arguments. All numeric values are entered as doubles without units. Warp Marker and tempo definitions affect only the conversions that come later in the input.



marker <beat time> <sample time>
end_tempo <value>
s2b <sample time>
b2s <beat time>


Output description
For each of the s2b and b2s lines, the corresponding output time is printed without unit. Example



Input
marker 0.0 0.0
marker 1.0 5.0
end_tempo 10.0
b2s 0.5
s2b 6.0
Output
2.5 11.0


Here's my solution:



//one.h

#include <vector>
#include <string>
#include <map>

using namespace std;

#ifndef SAMPLER_H
#define SAMPLER_H

class Sampler {
public:
map<double, double> beats = {};
map<double, double> samples = {};
double endTempo;
void addMarker(double beat, double sample);
double b2s(double beat);
double s2b(double sample);
};

#endif


and



// one.cc

#include "one.h"

using namespace std;

void Sampler::addMarker(double beat, double sample) {
beats[beat] = sample;
samples[sample] = beat;
}

double Sampler::b2s(double beat) {
auto marker2 = beats.upper_bound(beat);

if(marker2 == beats.begin()) marker2 = next(marker2);

auto marker1 = prev(marker2);

auto firstBeat = marker1->first;
auto firstSample = marker1->second;

double tempo;

if(marker2 == beats.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->first;
auto secondSample = marker2->second;

tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstSample + ((beat - firstBeat) / tempo);
}

double Sampler::s2b(double sample) {
auto marker2 = samples.upper_bound(sample);
if(marker2 == samples.begin()) marker2 = next(marker2);
auto marker1 = prev(marker2);

auto firstBeat = marker1->second;
auto firstSample = marker1->first;

double tempo;

if(marker2 == samples.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->second;
auto secondSample = marker2->first;
tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstBeat + ((sample - firstSample) * tempo);
}


and here's main



#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include "one.h"

int main() {
Sampler sampler;
string str;
while(true) {
getline(cin, str);
istringstream ss(str);
string command;
getline(ss, command, ' ');

if(command == "marker") {
string strBeat;
string strSample;
getline(ss, strBeat, ' ');
getline(ss, strSample, ' ');
double beat = stod(strBeat);
double sample = stod(strSample);
sampler.addMarker(beat, sample);
} else if(command == "end_tempo") {
string strTempo;
getline(ss, strTempo, ' ');
sampler.endTempo = stod(strTempo);
} else if(command == "s2b") {
string s;
getline(ss, s, ' ');
cout << sampler.s2b(stod(s)) << endl;
} else if(command == "b2s") {
string b;
getline(ss, b, ' ');
cout << sampler.b2s(stod(b)) << endl;
} else {
break;
}
}
}


and heres my tests



#include "one.h"
#include "gtest/gtest.h"
namespace {

class OneMarker : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(3, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(OneMarker, Before) {
EXPECT_EQ(4.6, sampler->b2s(-1));
EXPECT_EQ(-57, sampler->s2b(-1));
}

TEST_F(OneMarker, After) {
EXPECT_EQ(5.7, sampler->b2s(10));
EXPECT_EQ(53, sampler->s2b(10));
}

class TwoMarkers : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(0, 0);
sampler->addMarker(1, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(TwoMarkers, Before) {
EXPECT_EQ(-5.0, sampler->b2s(-1));
EXPECT_EQ(-0.2, sampler->s2b(-1));
}

TEST_F(TwoMarkers, Between) {
EXPECT_EQ(2.5, sampler->b2s(0.5));
EXPECT_EQ(11.0, sampler->s2b(6.0));
}

TEST_F(TwoMarkers, After) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
}

TEST_F(TwoMarkers, Mutation) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
sampler->addMarker(3,6);
EXPECT_EQ(6.7, sampler->b2s(10));
EXPECT_EQ(43, sampler->s2b(10));
}
}









share|improve this question













I was asked this question and got no feedback, so I'd like to ask you for any feedback on my solution, Thanks!



Think of an audio sample as a rubber-band that you want to pin to a musical time ruler. The pins are called Warp Markers. A Warp Marker locks a specific point in the sample (in sample time) to a specific place in a measure (in beat time). You can use any number of Warp Markers to create an arbitrary mapping of the sample’s inherent rhythm to a musical meter. For the sake of this task, please assume the following behavior:




  1. An audio clip contains a reference to a sample and a collection of Warp Markers.

  2. There is at least one Warp Marker in the clip.

  3. Between two Warp Markers, the tempo is constant.

  4. The tempo before the first Warp Marker is the same as the tempo after the first Warp
    Marker.

  5. The tempo after the last Warp Marker is specified separately in the input.

  6. Beat time is measured in beats, sample time is measured in seconds, and tempo is
    measured in beats per second.
    Input description


There are 4 kinds of lines in the input:




  1. Warp Marker definition

  2. Definition of the tempo after the last marker

  3. Sample time to beat time conversion

  4. Beat time to sample time conversion


At least one Warp Marker and the tempo after the last Warp Marker should be defined before the first conversion; otherwise, these can appear in any order.
Each line consists of a keyword followed by numeric arguments. All numeric values are entered as doubles without units. Warp Marker and tempo definitions affect only the conversions that come later in the input.



marker <beat time> <sample time>
end_tempo <value>
s2b <sample time>
b2s <beat time>


Output description
For each of the s2b and b2s lines, the corresponding output time is printed without unit. Example



Input
marker 0.0 0.0
marker 1.0 5.0
end_tempo 10.0
b2s 0.5
s2b 6.0
Output
2.5 11.0


Here's my solution:



//one.h

#include <vector>
#include <string>
#include <map>

using namespace std;

#ifndef SAMPLER_H
#define SAMPLER_H

class Sampler {
public:
map<double, double> beats = {};
map<double, double> samples = {};
double endTempo;
void addMarker(double beat, double sample);
double b2s(double beat);
double s2b(double sample);
};

#endif


and



// one.cc

#include "one.h"

using namespace std;

void Sampler::addMarker(double beat, double sample) {
beats[beat] = sample;
samples[sample] = beat;
}

double Sampler::b2s(double beat) {
auto marker2 = beats.upper_bound(beat);

if(marker2 == beats.begin()) marker2 = next(marker2);

auto marker1 = prev(marker2);

auto firstBeat = marker1->first;
auto firstSample = marker1->second;

double tempo;

if(marker2 == beats.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->first;
auto secondSample = marker2->second;

tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstSample + ((beat - firstBeat) / tempo);
}

double Sampler::s2b(double sample) {
auto marker2 = samples.upper_bound(sample);
if(marker2 == samples.begin()) marker2 = next(marker2);
auto marker1 = prev(marker2);

auto firstBeat = marker1->second;
auto firstSample = marker1->first;

double tempo;

if(marker2 == samples.end()) {
tempo = endTempo;
} else {
auto secondBeat = marker2->second;
auto secondSample = marker2->first;
tempo = (secondBeat - firstBeat) / (secondSample - firstSample);
}

return firstBeat + ((sample - firstSample) * tempo);
}


and here's main



#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include "one.h"

int main() {
Sampler sampler;
string str;
while(true) {
getline(cin, str);
istringstream ss(str);
string command;
getline(ss, command, ' ');

if(command == "marker") {
string strBeat;
string strSample;
getline(ss, strBeat, ' ');
getline(ss, strSample, ' ');
double beat = stod(strBeat);
double sample = stod(strSample);
sampler.addMarker(beat, sample);
} else if(command == "end_tempo") {
string strTempo;
getline(ss, strTempo, ' ');
sampler.endTempo = stod(strTempo);
} else if(command == "s2b") {
string s;
getline(ss, s, ' ');
cout << sampler.s2b(stod(s)) << endl;
} else if(command == "b2s") {
string b;
getline(ss, b, ' ');
cout << sampler.b2s(stod(b)) << endl;
} else {
break;
}
}
}


and heres my tests



#include "one.h"
#include "gtest/gtest.h"
namespace {

class OneMarker : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(3, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(OneMarker, Before) {
EXPECT_EQ(4.6, sampler->b2s(-1));
EXPECT_EQ(-57, sampler->s2b(-1));
}

TEST_F(OneMarker, After) {
EXPECT_EQ(5.7, sampler->b2s(10));
EXPECT_EQ(53, sampler->s2b(10));
}

class TwoMarkers : public ::testing::Test {
protected:
Sampler * sampler;
virtual void SetUp() {
sampler = new Sampler();
sampler->addMarker(0, 0);
sampler->addMarker(1, 5);
sampler->endTempo = 10;
}

virtual void TearDown() {
delete sampler;
}
};

TEST_F(TwoMarkers, Before) {
EXPECT_EQ(-5.0, sampler->b2s(-1));
EXPECT_EQ(-0.2, sampler->s2b(-1));
}

TEST_F(TwoMarkers, Between) {
EXPECT_EQ(2.5, sampler->b2s(0.5));
EXPECT_EQ(11.0, sampler->s2b(6.0));
}

TEST_F(TwoMarkers, After) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
}

TEST_F(TwoMarkers, Mutation) {
EXPECT_EQ(5.9, sampler->b2s(10));
EXPECT_EQ(51, sampler->s2b(10));
sampler->addMarker(3,6);
EXPECT_EQ(6.7, sampler->b2s(10));
EXPECT_EQ(43, sampler->s2b(10));
}
}






c++ algorithm audio music






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 15 at 3:55









Andrew Gallasch

1485




1485








  • 1




    FYI, I considered reviewing your earlier question but could not understand what it was supposed to do. This explanation is much clearer to me.
    – Edward
    Dec 16 at 17:43














  • 1




    FYI, I considered reviewing your earlier question but could not understand what it was supposed to do. This explanation is much clearer to me.
    – Edward
    Dec 16 at 17:43








1




1




FYI, I considered reviewing your earlier question but could not understand what it was supposed to do. This explanation is much clearer to me.
– Edward
Dec 16 at 17:43




FYI, I considered reviewing your earlier question but could not understand what it was supposed to do. This explanation is much clearer to me.
– Edward
Dec 16 at 17:43










1 Answer
1






active

oldest

votes


















3














Don't abuse using namespace std



Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. It's particularly bad to put that into a header file because it pollutes the global namespace.



Use appropriate #includes



The header file contains these two lines:



#include <vector>
#include <string>


However, neither is actually required for the interface. Also main does not need <fstream> but needs <string> but that is not included.



Use better naming



The file named one.h is not well named. The include guard name suggests that it is actually named sampler.h which is indeed a better name.



Prefer private to public where practical



The Sampler class has data members beats and samples as public members. Rather than do it that way, it would be better to keep it private because the class relies on an invariant -- namely that each entry in beats has a corresponding entry in samples. Such invariants cannot easily be enforced if the data members are public.



Use include guards correctly



The one.h file does have an include guard, which is good, but doesn't have it as the first thing in the file. This can waste preprocessing time as contrasted with the usual (and recommended) method of putting the include guard as the very first non-comment line in the header.



Use const where practical



The b2s and s2b functions don't alter the underlying object and so should be declared const.



Reconsider the structures



It's unclear to me what, if anything, you intend to do with the beats and samples stored in the Sampler class, but the current method of having parallel std::map structures seems less than optimal. If, as I infer, the context is music, both the sample and beat are increasing functions. This suggests that they could easily be contained in a single std::set<BeatTime> where BeatTime is a simple private struct containing both doubles.



With those changes, here's what the class declaration looks like:



class Sampler {
struct BeatTime {
double beat, sample;
bool operator<(const BeatTime& rhs) const {
return beat < rhs.beat;
}
};
std::set<BeatTime> beats;
std::set<BeatTime>::iterator sample_upper_bound(double sample) const;
public:
double endTempo;
void addMarker(double beat, double sample);
double b2s(double beat) const;
double s2b(double sample) const;
};


Now the addMarker function is very simple:



void Sampler::addMarker(double beat, double sample) {
beats.emplace(BeatTime{beat, sample});
}


And the b2s code is simplified:



double Sampler::b2s(double beat) const {
auto marker2 = beats.upper_bound(BeatTime{beat, 0});
double tempo{endTempo};
if(marker2 == beats.begin()) {
marker2 = next(marker2);
}
auto marker1 = prev(marker2);
if(marker2 != beats.end()) {
tempo = (marker2->beat - marker1->beat) / (marker2->sample - marker1->sample);
}
return marker1->sample + ((beat - marker1->beat) / tempo);
}


The s2b code is almost identical except that, of course, we can't use upper_bound directly. Instead, it uses this:



std::set<Sampler::BeatTime>::iterator Sampler::sample_upper_bound(double sample) const {
auto ret{beats.begin()};
for ( ; ret != beats.end() && ret->sample <= sample; ++ret)
{}
return ret;
}


This makes the search linear rather than logarithmic, but it's unlikely to make a huge practical difference until the set becomes very large.






share|improve this answer





















    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209707%2fwarped-audio-sample%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    Don't abuse using namespace std



    Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. It's particularly bad to put that into a header file because it pollutes the global namespace.



    Use appropriate #includes



    The header file contains these two lines:



    #include <vector>
    #include <string>


    However, neither is actually required for the interface. Also main does not need <fstream> but needs <string> but that is not included.



    Use better naming



    The file named one.h is not well named. The include guard name suggests that it is actually named sampler.h which is indeed a better name.



    Prefer private to public where practical



    The Sampler class has data members beats and samples as public members. Rather than do it that way, it would be better to keep it private because the class relies on an invariant -- namely that each entry in beats has a corresponding entry in samples. Such invariants cannot easily be enforced if the data members are public.



    Use include guards correctly



    The one.h file does have an include guard, which is good, but doesn't have it as the first thing in the file. This can waste preprocessing time as contrasted with the usual (and recommended) method of putting the include guard as the very first non-comment line in the header.



    Use const where practical



    The b2s and s2b functions don't alter the underlying object and so should be declared const.



    Reconsider the structures



    It's unclear to me what, if anything, you intend to do with the beats and samples stored in the Sampler class, but the current method of having parallel std::map structures seems less than optimal. If, as I infer, the context is music, both the sample and beat are increasing functions. This suggests that they could easily be contained in a single std::set<BeatTime> where BeatTime is a simple private struct containing both doubles.



    With those changes, here's what the class declaration looks like:



    class Sampler {
    struct BeatTime {
    double beat, sample;
    bool operator<(const BeatTime& rhs) const {
    return beat < rhs.beat;
    }
    };
    std::set<BeatTime> beats;
    std::set<BeatTime>::iterator sample_upper_bound(double sample) const;
    public:
    double endTempo;
    void addMarker(double beat, double sample);
    double b2s(double beat) const;
    double s2b(double sample) const;
    };


    Now the addMarker function is very simple:



    void Sampler::addMarker(double beat, double sample) {
    beats.emplace(BeatTime{beat, sample});
    }


    And the b2s code is simplified:



    double Sampler::b2s(double beat) const {
    auto marker2 = beats.upper_bound(BeatTime{beat, 0});
    double tempo{endTempo};
    if(marker2 == beats.begin()) {
    marker2 = next(marker2);
    }
    auto marker1 = prev(marker2);
    if(marker2 != beats.end()) {
    tempo = (marker2->beat - marker1->beat) / (marker2->sample - marker1->sample);
    }
    return marker1->sample + ((beat - marker1->beat) / tempo);
    }


    The s2b code is almost identical except that, of course, we can't use upper_bound directly. Instead, it uses this:



    std::set<Sampler::BeatTime>::iterator Sampler::sample_upper_bound(double sample) const {
    auto ret{beats.begin()};
    for ( ; ret != beats.end() && ret->sample <= sample; ++ret)
    {}
    return ret;
    }


    This makes the search linear rather than logarithmic, but it's unlikely to make a huge practical difference until the set becomes very large.






    share|improve this answer


























      3














      Don't abuse using namespace std



      Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. It's particularly bad to put that into a header file because it pollutes the global namespace.



      Use appropriate #includes



      The header file contains these two lines:



      #include <vector>
      #include <string>


      However, neither is actually required for the interface. Also main does not need <fstream> but needs <string> but that is not included.



      Use better naming



      The file named one.h is not well named. The include guard name suggests that it is actually named sampler.h which is indeed a better name.



      Prefer private to public where practical



      The Sampler class has data members beats and samples as public members. Rather than do it that way, it would be better to keep it private because the class relies on an invariant -- namely that each entry in beats has a corresponding entry in samples. Such invariants cannot easily be enforced if the data members are public.



      Use include guards correctly



      The one.h file does have an include guard, which is good, but doesn't have it as the first thing in the file. This can waste preprocessing time as contrasted with the usual (and recommended) method of putting the include guard as the very first non-comment line in the header.



      Use const where practical



      The b2s and s2b functions don't alter the underlying object and so should be declared const.



      Reconsider the structures



      It's unclear to me what, if anything, you intend to do with the beats and samples stored in the Sampler class, but the current method of having parallel std::map structures seems less than optimal. If, as I infer, the context is music, both the sample and beat are increasing functions. This suggests that they could easily be contained in a single std::set<BeatTime> where BeatTime is a simple private struct containing both doubles.



      With those changes, here's what the class declaration looks like:



      class Sampler {
      struct BeatTime {
      double beat, sample;
      bool operator<(const BeatTime& rhs) const {
      return beat < rhs.beat;
      }
      };
      std::set<BeatTime> beats;
      std::set<BeatTime>::iterator sample_upper_bound(double sample) const;
      public:
      double endTempo;
      void addMarker(double beat, double sample);
      double b2s(double beat) const;
      double s2b(double sample) const;
      };


      Now the addMarker function is very simple:



      void Sampler::addMarker(double beat, double sample) {
      beats.emplace(BeatTime{beat, sample});
      }


      And the b2s code is simplified:



      double Sampler::b2s(double beat) const {
      auto marker2 = beats.upper_bound(BeatTime{beat, 0});
      double tempo{endTempo};
      if(marker2 == beats.begin()) {
      marker2 = next(marker2);
      }
      auto marker1 = prev(marker2);
      if(marker2 != beats.end()) {
      tempo = (marker2->beat - marker1->beat) / (marker2->sample - marker1->sample);
      }
      return marker1->sample + ((beat - marker1->beat) / tempo);
      }


      The s2b code is almost identical except that, of course, we can't use upper_bound directly. Instead, it uses this:



      std::set<Sampler::BeatTime>::iterator Sampler::sample_upper_bound(double sample) const {
      auto ret{beats.begin()};
      for ( ; ret != beats.end() && ret->sample <= sample; ++ret)
      {}
      return ret;
      }


      This makes the search linear rather than logarithmic, but it's unlikely to make a huge practical difference until the set becomes very large.






      share|improve this answer
























        3












        3








        3






        Don't abuse using namespace std



        Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. It's particularly bad to put that into a header file because it pollutes the global namespace.



        Use appropriate #includes



        The header file contains these two lines:



        #include <vector>
        #include <string>


        However, neither is actually required for the interface. Also main does not need <fstream> but needs <string> but that is not included.



        Use better naming



        The file named one.h is not well named. The include guard name suggests that it is actually named sampler.h which is indeed a better name.



        Prefer private to public where practical



        The Sampler class has data members beats and samples as public members. Rather than do it that way, it would be better to keep it private because the class relies on an invariant -- namely that each entry in beats has a corresponding entry in samples. Such invariants cannot easily be enforced if the data members are public.



        Use include guards correctly



        The one.h file does have an include guard, which is good, but doesn't have it as the first thing in the file. This can waste preprocessing time as contrasted with the usual (and recommended) method of putting the include guard as the very first non-comment line in the header.



        Use const where practical



        The b2s and s2b functions don't alter the underlying object and so should be declared const.



        Reconsider the structures



        It's unclear to me what, if anything, you intend to do with the beats and samples stored in the Sampler class, but the current method of having parallel std::map structures seems less than optimal. If, as I infer, the context is music, both the sample and beat are increasing functions. This suggests that they could easily be contained in a single std::set<BeatTime> where BeatTime is a simple private struct containing both doubles.



        With those changes, here's what the class declaration looks like:



        class Sampler {
        struct BeatTime {
        double beat, sample;
        bool operator<(const BeatTime& rhs) const {
        return beat < rhs.beat;
        }
        };
        std::set<BeatTime> beats;
        std::set<BeatTime>::iterator sample_upper_bound(double sample) const;
        public:
        double endTempo;
        void addMarker(double beat, double sample);
        double b2s(double beat) const;
        double s2b(double sample) const;
        };


        Now the addMarker function is very simple:



        void Sampler::addMarker(double beat, double sample) {
        beats.emplace(BeatTime{beat, sample});
        }


        And the b2s code is simplified:



        double Sampler::b2s(double beat) const {
        auto marker2 = beats.upper_bound(BeatTime{beat, 0});
        double tempo{endTempo};
        if(marker2 == beats.begin()) {
        marker2 = next(marker2);
        }
        auto marker1 = prev(marker2);
        if(marker2 != beats.end()) {
        tempo = (marker2->beat - marker1->beat) / (marker2->sample - marker1->sample);
        }
        return marker1->sample + ((beat - marker1->beat) / tempo);
        }


        The s2b code is almost identical except that, of course, we can't use upper_bound directly. Instead, it uses this:



        std::set<Sampler::BeatTime>::iterator Sampler::sample_upper_bound(double sample) const {
        auto ret{beats.begin()};
        for ( ; ret != beats.end() && ret->sample <= sample; ++ret)
        {}
        return ret;
        }


        This makes the search linear rather than logarithmic, but it's unlikely to make a huge practical difference until the set becomes very large.






        share|improve this answer












        Don't abuse using namespace std



        Putting using namespace std at the top of every program is a bad habit that you'd do well to avoid. It's particularly bad to put that into a header file because it pollutes the global namespace.



        Use appropriate #includes



        The header file contains these two lines:



        #include <vector>
        #include <string>


        However, neither is actually required for the interface. Also main does not need <fstream> but needs <string> but that is not included.



        Use better naming



        The file named one.h is not well named. The include guard name suggests that it is actually named sampler.h which is indeed a better name.



        Prefer private to public where practical



        The Sampler class has data members beats and samples as public members. Rather than do it that way, it would be better to keep it private because the class relies on an invariant -- namely that each entry in beats has a corresponding entry in samples. Such invariants cannot easily be enforced if the data members are public.



        Use include guards correctly



        The one.h file does have an include guard, which is good, but doesn't have it as the first thing in the file. This can waste preprocessing time as contrasted with the usual (and recommended) method of putting the include guard as the very first non-comment line in the header.



        Use const where practical



        The b2s and s2b functions don't alter the underlying object and so should be declared const.



        Reconsider the structures



        It's unclear to me what, if anything, you intend to do with the beats and samples stored in the Sampler class, but the current method of having parallel std::map structures seems less than optimal. If, as I infer, the context is music, both the sample and beat are increasing functions. This suggests that they could easily be contained in a single std::set<BeatTime> where BeatTime is a simple private struct containing both doubles.



        With those changes, here's what the class declaration looks like:



        class Sampler {
        struct BeatTime {
        double beat, sample;
        bool operator<(const BeatTime& rhs) const {
        return beat < rhs.beat;
        }
        };
        std::set<BeatTime> beats;
        std::set<BeatTime>::iterator sample_upper_bound(double sample) const;
        public:
        double endTempo;
        void addMarker(double beat, double sample);
        double b2s(double beat) const;
        double s2b(double sample) const;
        };


        Now the addMarker function is very simple:



        void Sampler::addMarker(double beat, double sample) {
        beats.emplace(BeatTime{beat, sample});
        }


        And the b2s code is simplified:



        double Sampler::b2s(double beat) const {
        auto marker2 = beats.upper_bound(BeatTime{beat, 0});
        double tempo{endTempo};
        if(marker2 == beats.begin()) {
        marker2 = next(marker2);
        }
        auto marker1 = prev(marker2);
        if(marker2 != beats.end()) {
        tempo = (marker2->beat - marker1->beat) / (marker2->sample - marker1->sample);
        }
        return marker1->sample + ((beat - marker1->beat) / tempo);
        }


        The s2b code is almost identical except that, of course, we can't use upper_bound directly. Instead, it uses this:



        std::set<Sampler::BeatTime>::iterator Sampler::sample_upper_bound(double sample) const {
        auto ret{beats.begin()};
        for ( ; ret != beats.end() && ret->sample <= sample; ++ret)
        {}
        return ret;
        }


        This makes the search linear rather than logarithmic, but it's unlikely to make a huge practical difference until the set becomes very large.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 16 at 17:40









        Edward

        45.8k377208




        45.8k377208






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209707%2fwarped-audio-sample%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Сан-Квентин

            Алькесар

            Josef Freinademetz