Overview
I am experimenting with SFML and audio in a project I am working on.
Essentially I am attempting to implement a sort of digital synthesizer as a kind of artistic scientific experiment.
What I want to do is play two different frequency tones, one after the other, to check I can get this to work as I intend.
Work so far
So far I have implemented some stuff... I'm not really sure what I'm doing yet, so this is all a bit rough.
I have 2 std::vector
s which I will fill with data to play. I think I need a sf::Mutex
to prevent data races or something because I have more than one thread working with the same data.
In my int main
I have some stuff, the below section works and plays 1 second of audio, single 440 Hz tone.
sf::Mutex mutex;
std::vector<int16_t> samples_buffer_0;
std::vector<int16_t> samples_buffer_1;
int samples_buffer_switch = 0;
size_t samples_buffer_0_offset = 0; // flag do not need data
size_t samples_buffer_1_offset = -1; // flag need data
samples_buffer_0.resize(44100);
samples_buffer_1.resize(44100);
int hz_flag_0 = 0; // intend to use later
int hz_flag_1 = 1; // default to play this tone after 1 s of 440 Hz
double hz_freq_0 = 440; // tones to play
double hz_freq_1 = 880;
double time = 0.0;
double time_step = 1.0/44100.0;
sf::SoundBuffer soundbuffer;
sf::Sound sound;
// initialize a buffer
for(size_t i = 0; i < samples_buffer_0.size(); ++ i)
{
samples_buffer_0[i] = 0;
samples_buffer_0[i] += 10000.0 * std::sin(2.0 * 3.14159 * hz_freq_0 * time);
time += time_step;
}
// load buffer to soundbuffer object
soundbuffer.loadFromSamples(samples_buffer_0.data(), samples_buffer_0.size(), 1, 44100);
// play from this soundbuffer object
sound.setBuffer(soundbuffer);
sound.play();
The code which follows does not appear to be working. After 1 second, the tone stops, and nothing further happens...
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
if(event.type == sf::Event::KeyPressed)
{
if(event.key.code == sf::Keyboard::Key::Escape)
window.close();
if(event.key.code == sf::Keyboard::Key::Z)
{
if(hz_flag_0 == 0)
{
hz_flag_0 = 1;
}
else
{
hz_flag_0 = 0;
}
}
if(event.key.code == sf::Keyboard::Key::X)
{
if(hz_flag_1 == 0)
{
hz_flag_1 = 1;
}
else
{
hz_flag_1 = 0;
}
}
}
if(event.type == sf::Event::KeyReleased)
{
}
}
if(samples_buffer_switch == 0)
{
// if need next data
if(samples_buffer_1_offset != 0)
{
for(size_t i = 0; i < samples_buffer_1.size(); ++ i)
{
samples_buffer_1[i] = 0;
if(hz_flag_0 == 1)
{
samples_buffer_1[i] += 10000.0 * std::sin(2.0 * 3.14159 * hz_freq_0 * time);
}
if(hz_flag_1 == 1)
{
samples_buffer_1[i] += 5000.0 * std::sin(2.0 * 3.14159 * hz_freq_1 * time);
}
time += time_step;
}
samples_buffer_1_offset = 0;
}
}
else if(samples_buffer_switch == 1)
{
// if need next data
if(samples_buffer_0_offset != 0)
{
for(size_t i = 0; i < samples_buffer_0.size(); ++ i)
{
samples_buffer_0[i] = 0;
if(hz_flag_0 == 1)
{
samples_buffer_0[i] += 10000.0 * std::sin(2.0 * 3.14159 * hz_freq_0 * time);
}
if(hz_flag_1 == 1)
{
samples_buffer_0[i] += 5000.0 * std::sin(2.0 * 3.14159 * hz_freq_1 * time);
}
time += time_step;
}
samples_buffer_0_offset = 0;
}
}
// very unsure of what to do here...
// tried using the code which is now commented out but
// computer just made a horrific noise
// didn't really expect this to work, as it will continually
// restart playing of the buffer from the start...
//
// What should I do?
if(samples_buffer_switch == 0)
{
//sf::Lock lock(mutex);
//soundbuffer.loadFromSamples(&samples_buffer_0[0], samples_buffer_0.size(), 1, 44100);
//sound.play();
//samples_buffer_switch = 1;
}
else if(samples_buffer_switch == 1)
{
//sf::Lock lock(mutex);
//soundbuffer.loadFromSamples(&samples_buffer_1[0], samples_buffer_1.size(), 1, 44100);
//sound.play();
//samples_buffer_switch = 0;
}
window.clear();
keyboard.Draw(window);
window.display();
}
Additional
So far my understanding is as follows:
sf::Sound
can launch a new thread via theplay()
function, which then plays some audio samples, which are stored in asf::SoundBuffer
, in an independent thread.I think I may need to use a
sf::Soundstream
object to accomplish what I am trying to do? I think I need to create my own class which inherits fromsf::Soundstream
, overloading theonGetData()
andonSeek()
functions? (But I am not sure about this.)
Questions I have include:
What happens when the
sf::Sound
runs out of data to play? Do I have to callplay()
again when I fill a soundbuffer with new samples to play?How can I tell when I need to fill the next buffer with data? How can I tell when the
sf::Sound
object is about to run out of data to play?Should I be doing something with a
sf::Soundbuffer
instead of what I am attempting?
Aucun commentaire:
Enregistrer un commentaire