2012-04-11 45 views
6

ho problemi a capire come funziona la parte audio della libreria sdl ora, so che quando lo si inizializza, è necessario specificare la frequenza e una funzione >> callback < < , che penso sia poi chiamato automaticamente alla frequenza data. Chiunque abbia lavorato con la libreria sdl può scrivere un semplice esempio che userebbe sdl_audio per generare un'onda quadrata di 440 hz (poiché è la forma d'onda più semplice) ad una frequenza di campionamento di 44000 Hz?Semplice generatore di onde sonore con SDL in C++

+0

Questa è una bella bell'esempio, imo: http://www.libsdl.org/intro.en/usingsound.html – jrok

+0

@jrok Migliora il tuo commento e renderlo una risposta. Bella referenza – karlphillip

+0

@karlphillip Lì, spero che questo valga come un miglioramento;) – jrok

risposta

13

Il Introduction to SDL ha un chiaro esempio di utilizzo di libreria SDL suono che dovrebbe iniziare: http://www.libsdl.org/intro.en/usingsound.html

EDIT: Ecco un programma di lavoro che fa quello che hai chiesto. Ho modificato un po 'il codice trovato qui: http://www.dgames.org/beep-sound-with-sdl/

#include <SDL/SDL.h> 
#include <SDL/SDL_audio.h> 
#include <queue> 
#include <cmath> 

const int AMPLITUDE = 28000; 
const int FREQUENCY = 44100; 

struct BeepObject 
{ 
    double freq; 
    int samplesLeft; 
}; 

class Beeper 
{ 
private: 
    double v; 
    std::queue<BeepObject> beeps; 
public: 
    Beeper(); 
    ~Beeper(); 
    void beep(double freq, int duration); 
    void generateSamples(Sint16 *stream, int length); 
    void wait(); 
}; 

void audio_callback(void*, Uint8*, int); 

Beeper::Beeper() 
{ 
    SDL_AudioSpec desiredSpec; 

    desiredSpec.freq = FREQUENCY; 
    desiredSpec.format = AUDIO_S16SYS; 
    desiredSpec.channels = 1; 
    desiredSpec.samples = 2048; 
    desiredSpec.callback = audio_callback; 
    desiredSpec.userdata = this; 

    SDL_AudioSpec obtainedSpec; 

    // you might want to look for errors here 
    SDL_OpenAudio(&desiredSpec, &obtainedSpec); 

    // start play audio 
    SDL_PauseAudio(0); 
} 

Beeper::~Beeper() 
{ 
    SDL_CloseAudio(); 
} 

void Beeper::generateSamples(Sint16 *stream, int length) 
{ 
    int i = 0; 
    while (i < length) { 

     if (beeps.empty()) { 
      while (i < length) { 
       stream[i] = 0; 
       i++; 
      } 
      return; 
     } 
     BeepObject& bo = beeps.front(); 

     int samplesToDo = std::min(i + bo.samplesLeft, length); 
     bo.samplesLeft -= samplesToDo - i; 

     while (i < samplesToDo) { 
      stream[i] = AMPLITUDE * std::sin(v * 2 * M_PI/FREQUENCY); 
      i++; 
      v += bo.freq; 
     } 

     if (bo.samplesLeft == 0) { 
      beeps.pop(); 
     } 
    } 
} 

void Beeper::beep(double freq, int duration) 
{ 
    BeepObject bo; 
    bo.freq = freq; 
    bo.samplesLeft = duration * FREQUENCY/1000; 

    SDL_LockAudio(); 
    beeps.push(bo); 
    SDL_UnlockAudio(); 
} 

void Beeper::wait() 
{ 
    int size; 
    do { 
     SDL_Delay(20); 
     SDL_LockAudio(); 
     size = beeps.size(); 
     SDL_UnlockAudio(); 
    } while (size > 0); 

} 

void audio_callback(void *_beeper, Uint8 *_stream, int _length) 
{ 
    Sint16 *stream = (Sint16*) _stream; 
    int length = _length/2; 
    Beeper* beeper = (Beeper*) _beeper; 

    beeper->generateSamples(stream, length); 
} 

int main(int argc, char* argv[]) 
{ 
    SDL_Init(SDL_INIT_AUDIO); 

    int duration = 1000; 
    double Hz = 440; 

    Beeper b; 
    b.beep(Hz, duration); 
    b.wait(); 

    return 0; 
} 

Buona fortuna.

+0

grazie ma non riesco ancora a capirlo. Sono un principiante assoluto con questa libreria. Prima di porre la domanda qui, ho cercato di vedere se qualcuno ha fatto la stessa domanda, ma tutto quello che ho trovato erano solo parti di codice. Sono sicuro che un programma che fa quello che ho chiesto sarebbe davvero breve .. –

+0

@Vlad Aggiornamento della risposta. – jrok

+0

Grazie per quello! nel frattempo, ho provato a scrivere qualcosa e ho ottenuto questo: http: //docpaste.com/show.php? id = 231. L'onda quadra è udibile, ma ha molto rumore sopra e non è un leggero rumore, copre quasi l'intera uscita del suono. Quale può essere il problema? –

2

2.0.2 esempio C

Tratto da: https://codereview.stackexchange.com/questions/41086/play-some-sine-waves-with-sdl2

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <SDL2/SDL.h> 

const double ChromaticRatio = 1.059463094359295264562; 
const double Tao = 6.283185307179586476925; 

Uint32 sampleRate = 48000; 
Uint32 frameRate = 60; 
Uint32 floatStreamLength = 1024; 
Uint32 samplesPerFrame; 
Uint32 msPerFrame; 
double practicallySilent = 0.001; 

Uint32 audioBufferLength = 48000; 
float *audioBuffer; 

SDL_atomic_t audioCallbackLeftOff; 
Sint32 audioMainLeftOff; 
Uint8 audioMainAccumulator; 

SDL_AudioDeviceID AudioDevice; 
SDL_AudioSpec audioSpec; 

SDL_Event event; 
SDL_bool running = SDL_TRUE; 

typedef struct { 
    float *waveform; 
    Uint32 waveformLength; 
    double volume; 
    double pan; 
    double frequency; 
    double phase; 
} voice; 

void speak(voice *v) { 
    float sample; 
    Uint32 sourceIndex; 
    double phaseIncrement = v->frequency/sampleRate; 
    Uint32 i; 
    if (v->volume > practicallySilent) { 
     for (i = 0; (i + 1) < samplesPerFrame; i += 2) { 
      v->phase += phaseIncrement; 
      if (v->phase > 1) 
       v->phase -= 1; 

      sourceIndex = v->phase*v->waveformLength; 
      sample = v->waveform[sourceIndex]*v->volume; 

      audioBuffer[audioMainLeftOff+i] += sample*(1-v->pan); 
      audioBuffer[audioMainLeftOff+i+1] += sample*v->pan; 
     } 
    } 
    else { 
     for (i=0; i<samplesPerFrame; i+=1) 
      audioBuffer[audioMainLeftOff+i] = 0; 
    } 
    audioMainAccumulator++; 
} 

double getFrequency(double pitch) { 
    return pow(ChromaticRatio, pitch-57)*440; 
} 

int getWaveformLength(double pitch) { 
    return sampleRate/getFrequency(pitch)+0.5f; 
} 

void buildSineWave(float *data, Uint32 length) { 
    Uint32 i; 
    for (i=0; i < length; i++) 
     data[i] = sin(i*(Tao/length)); 
} 

void logSpec(SDL_AudioSpec *as) { 
    printf(
     " freq______%5d\n" 
     " format____%5d\n" 
     " channels__%5d\n" 
     " silence___%5d\n" 
     " samples___%5d\n" 
     " size______%5d\n\n", 
     (int) as->freq, 
     (int) as->format, 
     (int) as->channels, 
     (int) as->silence, 
     (int) as->samples, 
     (int) as->size 
    ); 
} 

void logVoice(voice *v) { 
    printf(
     " waveformLength__%d\n" 
     " volume__________%f\n" 
     " pan_____________%f\n" 
     " frequency_______%f\n" 
     " phase___________%f\n", 
     v->waveformLength, 
     v->volume, 
     v->pan, 
     v->frequency, 
     v->phase 
    ); 
} 

void logWavedata(float *floatStream, Uint32 floatStreamLength, Uint32 increment) { 
    printf("\n\nwaveform data:\n\n"); 
    Uint32 i=0; 
    for (i = 0; i < floatStreamLength; i += increment) 
     printf("%4d:%2.16f\n", i, floatStream[i]); 
    printf("\n\n"); 
} 

void audioCallback(void *unused, Uint8 *byteStream, int byteStreamLength) { 
    float* floatStream = (float*) byteStream; 
    Sint32 localAudioCallbackLeftOff = SDL_AtomicGet(&audioCallbackLeftOff); 
    Uint32 i; 
    for (i = 0; i < floatStreamLength; i++) { 
     floatStream[i] = audioBuffer[localAudioCallbackLeftOff]; 
     localAudioCallbackLeftOff++; 
     if (localAudioCallbackLeftOff == audioBufferLength) 
      localAudioCallbackLeftOff = 0; 
    } 
    SDL_AtomicSet(&audioCallbackLeftOff, localAudioCallbackLeftOff); 
} 

int init(void) { 
    SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER); 
    SDL_AudioSpec want; 
    SDL_zero(want); 

    want.freq = sampleRate; 
    want.format = AUDIO_F32; 
    want.channels = 2; 
    want.samples = floatStreamLength; 
    want.callback = audioCallback; 

    AudioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &audioSpec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); 
    if (AudioDevice == 0) { 
     printf("\nFailed to open audio: %s\n", SDL_GetError()); 
     return 1; 
    } 

    printf("want:\n"); 
    logSpec(&want); 
    printf("audioSpec:\n"); 
    logSpec(&audioSpec); 

    if (audioSpec.format != want.format) { 
     printf("\nCouldn't get Float32 audio format.\n"); 
     return 2; 
    } 

    sampleRate = audioSpec.freq; 
    floatStreamLength = audioSpec.size/4; 
    samplesPerFrame = sampleRate/frameRate; 
    msPerFrame = 1000/frameRate; 
    audioMainLeftOff = samplesPerFrame * 8; 
    SDL_AtomicSet(&audioCallbackLeftOff, 0); 

    if (audioBufferLength % samplesPerFrame) 
     audioBufferLength += samplesPerFrame - (audioBufferLength % samplesPerFrame); 
    audioBuffer = malloc(sizeof(float) * audioBufferLength); 

    return 0; 
} 

int onExit(void) { 
    SDL_CloseAudioDevice(AudioDevice); 
    SDL_Quit(); 
    return 0; 
} 

int main(int argc, char *argv[]) { 
    float syncCompensationFactor = 0.0016; 
    Sint32 mainAudioLead; 
    Uint32 i; 

    voice testVoiceA; 
    voice testVoiceB; 
    voice testVoiceC; 
    testVoiceA.volume = 1; 
    testVoiceB.volume = 1; 
    testVoiceC.volume = 1; 
    testVoiceA.pan = 0.5; 
    testVoiceB.pan = 0; 
    testVoiceC.pan = 1; 
    testVoiceA.phase = 0; 
    testVoiceB.phase = 0; 
    testVoiceC.phase = 0; 
    testVoiceA.frequency = getFrequency(45); 
    testVoiceB.frequency = getFrequency(49); 
    testVoiceC.frequency = getFrequency(52); 
    Uint16 C0waveformLength = getWaveformLength(0); 
    testVoiceA.waveformLength = C0waveformLength; 
    testVoiceB.waveformLength = C0waveformLength; 
    testVoiceC.waveformLength = C0waveformLength; 
    float sineWave[C0waveformLength]; 
    buildSineWave(sineWave, C0waveformLength); 
    testVoiceA.waveform = sineWave; 
    testVoiceB.waveform = sineWave; 
    testVoiceC.waveform = sineWave; 

    if (init()) 
     return 1; 

    SDL_Delay(42); 
    SDL_PauseAudioDevice(AudioDevice, 0); 
    while (running) { 
     while (SDL_PollEvent(&event) != 0) { 
      if (event.type == SDL_QUIT) { 
       running = SDL_FALSE; 
      } 
     } 
     for (i = 0; i < samplesPerFrame; i++) 
      audioBuffer[audioMainLeftOff+i] = 0; 
     speak(&testVoiceA); 
     speak(&testVoiceB); 
     speak(&testVoiceC); 
     if (audioMainAccumulator > 1) { 
      for (i=0; i<samplesPerFrame; i++) { 
       audioBuffer[audioMainLeftOff+i] /= audioMainAccumulator; 
      } 
     } 
     audioMainAccumulator = 0; 
     audioMainLeftOff += samplesPerFrame; 
     if (audioMainLeftOff == audioBufferLength) 
      audioMainLeftOff = 0; 
     mainAudioLead = audioMainLeftOff - SDL_AtomicGet(&audioCallbackLeftOff); 
     if (mainAudioLead < 0) 
      mainAudioLead += audioBufferLength; 
     if (mainAudioLead < floatStreamLength) 
      printf("An audio collision may have occured!\n"); 
     SDL_Delay(mainAudioLead * syncCompensationFactor); 
    } 
    onExit(); 
    return 0; 
} 

testato su Ubuntu 15.10.

dovrebbe essere facile da trasformare questo in un semplice pianoforte con: https://github.com/cirosantilli/cpp-cheat/blob/f734a2e76fbcfc67f707ae06be7a2a2ef5db47d1/c/interactive/audio_gen.c#L44

Per la manipolazione wav, controllare anche gli esempi ufficiali:

0

A BOLLITO -la variante del cicalino-esempio, ridotta al minimo (con gestione degli errori).

#include <math.h> 
#include <SDL.h> 
#include <SDL_audio.h> 

const int AMPLITUDE = 28000; 
const int SAMPLE_RATE = 44100; 

void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes) 
{ 
    Sint16 *buffer = (Sint16*)raw_buffer; 
    int length = bytes/2; // 2 bytes per sample for AUDIO_S16SYS 
    int &sample_nr(*(int*)user_data); 

    for(int i = 0; i < length; i++, sample_nr++) 
    { 
     double time = (double)sample_nr/(double)SAMPLE_RATE; 
     buffer[i] = (Sint16)(AMPLITUDE * sin(2.0f * M_PI * 441.0f * time)); // render 441 HZ sine wave 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    if(SDL_Init(SDL_INIT_AUDIO) != 0) SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); 

    int sample_nr = 0; 

    SDL_AudioSpec want; 
    want.freq = SAMPLE_RATE; // number of samples per second 
    want.format = AUDIO_S16SYS; // sample type (here: signed short i.e. 16 bit) 
    want.channels = 1; // only one channel 
    want.samples = 2048; // buffer-size 
    want.callback = audio_callback; // function SDL calls periodically to refill the buffer 
    want.userdata = &sample_nr; // counter, keeping track of current sample number 

    SDL_AudioSpec have; 
    if(SDL_OpenAudio(&want, &have) != 0) SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to open audio: %s", SDL_GetError()); 
    if(want.format != have.format) SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to get the desired AudioSpec"); 

    SDL_PauseAudio(0); // start playing sound 
    SDL_Delay(1000); // wait while sound is playing 
    SDL_PauseAudio(1); // stop playing sound 

    SDL_CloseAudio(); 

    return 0; 
}