Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Modifying length of a sound sample?  (Read 4725 times)

0 Members and 1 Guest are viewing this topic.

GarrickW

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
Modifying length of a sound sample?
« on: June 25, 2013, 03:00:22 am »
I am currently writing a program in which the user can play a simple virtual piano.  I load a sample representing a middle C, and I change the pitch of that sound to get the other notes the user requests.  However, I also want the player to be able to play notes of different lengths - quarter notes, half notes, etc.

Is there a way to dynamically alter the length of the sample?  I've been mucking around in Audacity trying to change the sample length to have multiple samples (I only really want five - staccato, quarter, half, three-quarter and full), but doing so makes the sample sound very scratchy.

If there is no way to do this, does anybody know what other approaches I may try?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Modifying length of a sound sample?
« Reply #1 on: June 25, 2013, 07:54:01 am »
I'd generate the sounds myself programmatically. Since each of your sounds is made of a unique frequency, the corresponding audio samples are basically just a regular sine. This way you can control the frequency and the length very easily.
Laurent Gomila - SFML developer

GarrickW

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
Re: Modifying length of a sound sample?
« Reply #2 on: June 25, 2013, 03:54:21 pm »
That's an interesting suggestion.  I assume I would be making use of sf::SoundBuffer::loadFromSamples(), after creating my own array of samples, right?

I suppose I'll have to read up about the structure of audio samples, but this may be even better than using sample files.  Is there anything special I should know about the structure of the sample array to be fed into the SoundBuffer?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Modifying length of a sound sample?
« Reply #3 on: June 25, 2013, 04:31:39 pm »
Quote
That's an interesting suggestion.  I assume I would be making use of sf::SoundBuffer::loadFromSamples(), after creating my own array of samples, right?
Right.

Quote
Is there anything special I should know about the structure of the sample array to be fed into the SoundBuffer?
No, it's very simple.

You must generate a sine wave with the following characteristics:
- its frequency must match the desired sound's frequency (for example, ~262 Hz for a middle C)
- its amplitude will be the sound's volume, so this parameter is entirely up to you -- but you should use maximum amplitude and then use SFML functions to lower it in real-time if needed

You must fill your array of audio samples with values from this sine function ; the number of points depend on the desired sound length and sampling rate. For example, if you want 10 seconds at 44100 Hz, you must generate 44100 points in total.
Laurent Gomila - SFML developer

cpolymeris

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
    • Email
Re: Modifying length of a sound sample?
« Reply #4 on: June 28, 2013, 01:43:22 pm »
If there is no way to do this, does anybody know what other approaches I may try?

This is a very interesting topic. One way sample based synths do this is having 2 or more samples for each sound. E.g.
  • One attack sample of a few millisecons, i.e. the initial louder burst of sound, which usuually also contains more noise, like the sound of the piano's keys and hammer, or a flute's initial "wind" noise
  • One sustain sample, which is cleaner (only harmonics) and is looped after that. Make sure this sound is perfectly loopable
  • One decay sample, which is appended at the end (from the point the piano's muffler takes effect)

Then, by varying the time the sustain part is looped, you can vary the overall playing time of the note. You might be able to do without the decay, just fading the sustain out.
Also keep in mind there is only so much you can do with one sampleset. For lower or higher tones the whole timbre of the note changes. So you might want a sample set for bass notes and one for treble notes in addition to your middle C. This is known as "multisampling".

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Modifying length of a sound sample?
« Reply #5 on: June 28, 2013, 03:09:30 pm »
I was also considering suggesting that, but it can get very complex very quickly. Hauptwerk is a well known virtual pipe organ program that uses this method. Take a look here for some more information.

In simplest terms you need to loop predefined parts of a sample over and over until you want to stop playing that sound.
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

GarrickW

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
Re: Modifying length of a sound sample?
« Reply #6 on: June 28, 2013, 09:08:00 pm »
Thanks for the extra information!  This might come in handy.

In getting the basics down pat, though, I'm having some trouble.  I'm trying to figure out the basic construction of a decent sample array, and I'm getting scratchy sounds.  Here is what I have right now, trying to obtain a 1-second sound:

//For storing the samples
sf::Int16 Samples[44100];

//I want 44100 samples, since I want 44100 per second and one second of sound
for (int sample = 0; sample < 44100; ++sample)
{
    //This is essentially the time into the sound
    double Position = (double)sample / 44100.0;

    //Frequency of the curve is 262 Hz
    sf::Int16 Sample = sin(262*Position);
}

sf::SoundBugger CodeNote;
CodeNote.loadFromSamples(Samples, 44100, 1, 44100);

Given the scratchy, glitchy-sounding result, that's clearly not quite what I should be doing.  What am I misunderstanding?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Modifying length of a sound sample?
« Reply #7 on: June 28, 2013, 10:20:04 pm »
Two mistakes:

1. The frequency of sin(x) is 2*pi, so if you want 262 the formula would be
sin(262 * Position * 2 * pi)

2. The amplitude of sin(x) is [-1, 1], whereas the range of sf::Int16 is [-32768, 32767]. With [-1, 1] you will hardly hear something.
Laurent Gomila - SFML developer

GarrickW

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
Re: Modifying length of a sound sample?
« Reply #8 on: June 28, 2013, 11:51:37 pm »
Ah, okay, so something more like this?

//Create a note from code
sf::Int16 Samples[44100];
//Frequency, in herz
for (int sample = 0; sample < 44100; ++sample)
{
    //This is essentially the value of X
    double Position = (double)sample / 44100.0;
    sf::Int16 Sample = 32767 * sin(262 * Position * 2 * PI);
}

CodeNote.loadFromSamples(Samples, 44100, 1, 44100);

This still gives me scratchy stuff, though it is different-sounding scratchy stuff. 

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: Modifying length of a sound sample?
« Reply #9 on: June 29, 2013, 12:25:50 am »
You should increase compilation warning level because you're not using `Sample` (capitale S and no S at the end... not the two others `sample` & `Samples` variables..). Your array's elements are not initialised.

I admit it's hard to find good variable names but here it's too confusing.  ;)
SFML / OS X developer

GarrickW

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
Re: Modifying length of a sound sample?
« Reply #10 on: June 29, 2013, 01:59:13 am »
@Hiura

D'oh!  Of course you're right.  I was making all those samples and not putting them in the array.  :o

Now it works.  Thanks!