Hi everybody, im new on the forum and with the SFML so maybe solution of my problem will be very easy for you. I hope so :)
Im working on application for my own use that will be used to play guitar songs.
My problem:
(inside my class "note")
//SEPARATED BUFFERS
sf::SoundBuffer Buffer_clean[STRINGS];
sf::SoundBuffer Buffer_lead[STRINGS];
sf::SoundBuffer Buffer_pm[STRINGS];
//SEPARATED SOUNDS
sf::Sound Sound_clean[STRINGS][RANGEOFSTRINGS];
sf::Sound Sound_lead[STRINGS][RANGEOFSTRINGS];
sf::Sound Sound_pm[STRINGS][RANGEOFSTRINGS];
float Pitch_Table[RANGEOFSTRINGS + 1] = { 1.0f, 1.06f, 1.123f, 1.19f, 1.264f, 1.336f, 1.415f, 1.5f, 1.59f, 1.69f, 1.79f, 1.89f, 2.0f, 2.13f, 2.25f, 2.39f, 2.53f, 2.68f, 2.84f, 3.0f, 3.174f, 3.355f, 3.56f, 3.77f, 4.0f, 4.1f }; //TABLE OF PITCHES FOR EACH FRET
Where
STRINGS is defined 6
RANGEOFSTRINGS is defined 25
All i want to do is load recorded sounds to buffers, then set every sound with right buffer and pitch that is stored in table.
Here is main part of my "load" function:
(type - determinates what do i load. If 0 then clean, 1 - lead, 2 - palm mute. Function must be launched 3 times to load everything)
//LOAD SOUNDS--------------------------------------------
string namepatch;
if (type == 0)
namepatch = "Properties/Sounds/CX.wav";
else if (type == 1)
namepatch = "Properties/Sounds/DX.wav";
else if (type == 2)
namepatch = "Properties/Sounds/PX.wav";
for (int i = 0; i < STRINGS; i++) {
//CHANGE THE PATCH
namepatch.replace(19, 1, to_string(i)); //CHANGES ONLY X FROM NAMEPATCH
//CLEAN---------------
if (type == 0) {
if (this->Buffer_clean[i].loadFromFile(namepatch) == false)
cout << "LOAD ERROR: " << namepatch << endl;
//PARAMS
for (int j = 0; j < RANGEOFSTRINGS; j++) {
this->Sound_clean[i][j].setBuffer(this->Buffer_clean[i]); //BUFFER
this->Sound_clean[i][j].setPitch(this->Pitch_Table[j]); //PITCH
}
}
//LEAD--------------------
if (type == 1) {
if (this->Buffer_lead[i].loadFromFile(namepatch) == false)
cout << "LOAD ERROR: " << namepatch << endl;
//PARAMS
for (int j = 0; j < RANGEOFSTRINGS; j++) {
this->Sound_lead[i][j].setBuffer(this->Buffer_lead[i]); //BUFFER
this->Sound_lead[i][j].setPitch(this->Pitch_Table[j]); //PITCH
}
}
//PM-----------------------
if (type == 2) {
if (this->Buffer_pm[i].loadFromFile(namepatch) == false)
cout << "LOAD ERROR: " << namepatch << endl;
//PARAMS
for (int j = 0; j < RANGEOFSTRINGS; j++) {
this->Sound_pm[i][j].setBuffer(this->Buffer_pm[i]); //BUFFER
this->Sound_pm[i][j].setPitch(this->Pitch_Table[j]); //PITCH
}
}
}
What is result and this bug ?
While im trying to play sounds for example clean like:
(in class note function)
this->Sound_clean[0][10].play()
Most of table works right but some random elements of table has completely randomized pitch values and buffers.
Sometimes when playing clean single sound has wrong pitch or even plays sound from for example Buffer_lead.
How do i "fixed" that?
(in "play" function of class "note")
//KEYBOARD CLEAN-------------------------
if (type == 0) {
//PITCH CONTROL --------------------
if (this->Sound_clean[string][fret].getPitch() != this->Pitch_Table[fret]) {
this->Sound_clean[string][fret].setPitch(this->Pitch_Table[fret]);
cout << "something were wrong" << endl;
}
//END OF PITCH CONTROL -----------
this->Sound_clean[string][fret].setBuffer(this->Buffer_clean[string]);
this->Sound_clean[string][fret].play();
}
In "play" function before every use of sound i created checking the pitch and set the buffer once again.
How it works now ?
Clean_sound (table) works fine for whole table
Lead_sound (table) works fine almost everywhere. Some single table positions do not play anything
Pm_sount (table) works only in some positions. Most of them dont play anything
Im trying to solve this problem since some days and many times i reorganized whole code that works with sound. It didnt help so i decided to ask more experienced people than me :)
If i delete code that changes buffer and pitch before use of note, some positions plays completely random buffers and pitches, some do nothing.
Thank You in Advance :)
Okay, once again i remaked my code:
Note class:
class Note { //SOUNDS COUNTAINER AND LAUNCHER
public:
sf::SoundBuffer Metronome_buffer; //BUFFER FOR METRONOME SOUND
sf::Sound Metronome_sound; //SOUND OF METRONOME
//SEPARATED BUFFERS
sf::SoundBuffer Buffer_clean[STRINGS];
sf::SoundBuffer Buffer_lead[STRINGS];
sf::SoundBuffer Buffer_pm[STRINGS];
//SEPARATED SOUNDS
sf::Sound Sound_clean[STRINGS][RANGEOFSTRINGS];
sf::Sound Sound_lead[STRINGS][RANGEOFSTRINGS];
sf::Sound Sound_pm[STRINGS][RANGEOFSTRINGS];
float Pitch_Table[RANGEOFSTRINGS + 1] = { 1.0f, 1.06f, 1.123f, 1.19f, 1.264f, 1.336f, 1.415f, 1.5f, 1.59f, 1.69f, 1.79f, 1.89f, 2.0f,
2.13f, 2.25f, 2.39f, 2.53f, 2.68f, 2.84f, 3.0f, 3.174f, 3.355f, 3.56f, 3.77f, 4.0f, 4.1f }; //TABLE OF PITCHES FOR EACH FRET
Note();
void play(short type, struct Tab::Fret_cutaway *fr_cut = NULL, short string = 0, short fret = 0); //PLAY - TYPES: 0\1\2 -C\L\P || 10 FRETCUT
void load(short type, sf::RenderWindow *window, class System *system); //SHITDOESNTWORK
void load_clean();
void load_lead();
void load_pm();
};
Now i have three separated functions for load each kind of sounds, and i made them as simply as it was possible
void Note::load_clean() {
//LOAD SOUND || 0- C | 1- G | 2- C | 5- D
this->Buffer_clean[0].loadFromFile("Properties/Sounds/C0.wav");
this->Buffer_clean[1].loadFromFile("Properties/Sounds/C1.wav");
this->Buffer_clean[2].loadFromFile("Properties/Sounds/C2.wav");
this->Buffer_clean[3].loadFromFile("Properties/Sounds/C3.wav");
this->Buffer_clean[4].loadFromFile("Properties/Sounds/C4.wav");
this->Buffer_clean[5].loadFromFile("Properties/Sounds/C5.wav");
//PARAMS
for (int j = 0; j < RANGEOFSTRINGS; j++) {
this->Sound_clean[0][j].setBuffer(this->Buffer_clean[0]);
this->Sound_clean[0][j].setPitch(this->Pitch_Table[j]);
this->Sound_clean[1][j].setBuffer(this->Buffer_clean[1]);
this->Sound_clean[1][j].setPitch(this->Pitch_Table[j]);
this->Sound_clean[2][j].setBuffer(this->Buffer_clean[2]);
this->Sound_clean[2][j].setPitch(this->Pitch_Table[j]);
this->Sound_clean[3][j].setBuffer(this->Buffer_clean[3]);
this->Sound_clean[3][j].setPitch(this->Pitch_Table[j]);
this->Sound_clean[4][j].setBuffer(this->Buffer_clean[4]);
this->Sound_clean[4][j].setPitch(this->Pitch_Table[j]);
this->Sound_clean[5][j].setBuffer(this->Buffer_clean[5]);
this->Sound_clean[5][j].setPitch(this->Pitch_Table[j]);
//METRONOME
this->Metronome_buffer.loadFromFile("Properties/Sounds/_M1.wav");
this->Metronome_sound.setBuffer(this->Metronome_buffer);
}
}
void Note::load_pm() {
//LOAD SOUND || 0- C | 1- G | 2- C | 5- D
this->Buffer_pm[0].loadFromFile("Properties/Sounds/P0.wav");
this->Buffer_pm[1].loadFromFile("Properties/Sounds/P1.wav");
this->Buffer_pm[2].loadFromFile("Properties/Sounds/P2.wav");
this->Buffer_pm[3].loadFromFile("Properties/Sounds/P3.wav");
this->Buffer_pm[4].loadFromFile("Properties/Sounds/P4.wav");
this->Buffer_pm[5].loadFromFile("Properties/Sounds/P5.wav");
//PARAMS
for (int j = 0; j < RANGEOFSTRINGS; j++) {
this->Sound_pm[0][j].setBuffer(this->Buffer_pm[0]);
this->Sound_pm[0][j].setPitch(this->Pitch_Table[j]);
this->Sound_pm[1][j].setBuffer(this->Buffer_pm[1]);
this->Sound_pm[1][j].setPitch(this->Pitch_Table[j]);
this->Sound_pm[2][j].setBuffer(this->Buffer_pm[2]);
this->Sound_pm[2][j].setPitch(this->Pitch_Table[j]);
this->Sound_pm[3][j].setBuffer(this->Buffer_pm[3]);
this->Sound_pm[3][j].setPitch(this->Pitch_Table[j]);
this->Sound_pm[4][j].setBuffer(this->Buffer_pm[4]);
this->Sound_pm[4][j].setPitch(this->Pitch_Table[j]);
this->Sound_pm[5][j].setBuffer(this->Buffer_pm[5]);
this->Sound_pm[5][j].setPitch(this->Pitch_Table[j]);
}
}
And what happens now:
In case i loaded only clean in main():
-every sound works right and have right pitch. Its great isnt it ? :)
In calse i loaded only pm (load_pm() ) in main():
-positions of sound_pm(6)(25)
(0)(8 )
(4)(19)
(4)(8 )
Plays something ....
(i didnt even check pitch becouse it was actually useless)
-rest of table
Sound_pm(6)(25) doesnt play anything
In case i loaded clean and then pm in main():
-Clean works fine (pitch and buffer - type of sound) except:
sound_clean(6)(25) positions:
(1)(18 )
(0)(11)
(0)(3)
On this position buffer is pm. What to say ... :|
-Pm doesnt play any sound except positions
(5)(11) = (2)(14) = (2)(4)
This three plays exactly same sound and pitch, buffer is right
(2)(11)
(1)(3)
(1)(2)
(1)(0)
(5)(12)
(5)(11)
This positions plays something. I didnt check pitch. The rest of table is dead
My play function looks like:
void Note::play(short type, struct Tab::Fret_cutaway *fr_cut, short string, short fret) {
//TYPE 0/1/2 - PLAYING ON KEYBOARD- Clean/Lead/Pm
if (type == 0 || type == 1 || type == 2) {
//KEYBOARD CLEAN-------------------------
if (type == 0) {
this->Sound_clean[string][fret].play();
}
//KEYBOARD LEAD-------------------------
if (type == 1) {
this->Sound_lead[string][fret].play();
}
//KEYBOARD PALM MUTE-------------------------
if (type == 2) {
this->Sound_pm[string][fret].play();
}
}
}
If i run program more times, sometimes different positions works or not.
I completely dont understand what is goin on :)
PS i had to use (2) - brackets instead of [2] becouse there was some problems with right displaying it on forum :)
Oh I see. You have 6 sound buffers (one for each string) and 26 sounds for each string (one for each fret), each being set to the same sound buffer as all of the other sounds on that string. That's 6 x 26 = 156 sounds. This seems excessive considering that you will only ever play a maximum of 6 at a time.
Think of a sound as a "voice". That is, one of the things that plays. Then, think of the pitches as something that the voice changes to match. If you have one sound per string, you can simply "play" the sound representing that string whenever that string is played.
So, have 6 sound buffers and 6 sounds that match them. Then, when playing a note, set the pitch of the sound to match the fret's pitch whenever the sound is played. This has an added advantage too; if you just change the pitch without (re)starting the sound, you get an instant pitch shift and this may help with unpicked/unplucked sounds (hammer-ons, pull-offs and slides, for example).
Another thing to note is that calculating the pitches can be done in real-time when needed rather than using the table.
sound.setPitch(static_cast<float>(std::pow(2, static_cast<double>(fret) / 12.0)));
should do it ;)
fret is the fret number, starting from zero (open).
This might not still fix the problem but I just wanted you to see another approach :)
Try re-ordering the play styles to see if that affects anything.