2012-04-11 6 views
6

Ich habe Probleme zu verstehen, wie der Audio-Teil der SDL-Bibliothek funktioniert jetzt weiß ich, dass, wenn Sie es initialisieren, müssen Sie die Frequenz und einen >> Rückruf < < Funktion angeben , was ich dann automatisch bei der angegebenen Frequenz anrufe. kann jemand, der mit der SDL-Bibliothek arbeitete, ein einfaches Beispiel schreiben, das sdl_audio verwenden würde, um eine 440 Hz-Rechteckwelle (da es die einfachste Wellenform ist) mit einer Abtastfrequenz von 44000 Hz zu erzeugen?Einfache Schallwellengenerator mit SDL in C++

+0

Das ist ein ziemlich schönes Beispiel, imo: http://www.libsdl.org/intro.en/usingsound.html – jrok

+0

@jrok Ihren Kommentar verbessern und eine Antwort zu machen. Schöne Referenz. – karlphillip

+0

@karlphillip Dort hoffe ich, dass dies als Verbesserung gilt;) – jrok

Antwort

13

The Introduction to SDL hat ein schönes Beispiel der Verwendung von SDL Sound-Bibliothek bekam, die Ihnen den Einstieg sollten: http://www.libsdl.org/intro.en/usingsound.html

EDIT: Hier ist ein Arbeitsprogramm, das tut, was für Sie gefragt. Ich änderte ein wenig den Code hier: 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; 
} 

Viel Glück.

+0

danke aber ich kann es immer noch nicht verstehen. Ich bin ein absoluter Anfänger mit dieser Bibliothek. Bevor ich die Frage hier gestellt habe, habe ich gesucht, ob jemand dieselbe Frage gestellt hat, aber alles, was ich gefunden habe, waren nur Teile des Codes. Ich bin sicher, dass ein Programm, das tut, was ich gefragt habe, wirklich kurz sein würde. –

+0

@Vlad Die Antwort wurde aktualisiert. – jrok

+0

Danke dafür! in der Zwischenzeit habe ich versucht, etwas zu schreiben, und ich habe das: http: //docpaste.com/show.php?id=231 .Die Rechteckwelle ist hörbar, aber es hat eine Menge Lärm drüber.und es ist kein leichtes Rauschen, es deckt fast die gesamte Tonausgabe ab. Was kann das Problem sein? –

2

2.0.2 C Beispiel

von Genommen: 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; 
} 

15,10 auf Ubuntu getestet.

Sollte einfach diese in ein einfaches Klavier machen mit: https://github.com/cirosantilli/cpp-cheat/blob/f734a2e76fbcfc67f707ae06be7a2a2ef5db47d1/c/interactive/audio_gen.c#L44

Für wav Manipulation, überprüfen Sie auch die offiziellen Beispiele:

0

Ein gekochtes Variante des Beeper-Beispiels, reduziert auf das Minimum (mit Fehlerbehandlung).

#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; 
}