44*
55* Example complexity rating: [★★★☆] 3/4
66*
7- * Example originally created with raylib 1.6, last time updated with raylib 4.2
7+ * Example originally created with raylib 1.6, last time updated with raylib 6.0
88*
99* Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
1010*
1919
2020#include <stdlib.h> // Required for: malloc(), free()
2121#include <math.h> // Required for: sinf()
22- #include <string.h> // Required for: memcpy()
22+
23+ enum Flags { FLAG_CHANNEL_MONO = 1u <<0 , FLAG_SAMPLESIZE_SHORT = 1u <<1 };
24+ static unsigned int gflags = FLAG_CHANNEL_MONO | FLAG_SAMPLESIZE_SHORT ; // mono + 16-bit to match initial stream specs
25+ #define CHANNEL_MONO () ((gflags & FLAG_CHANNEL_MONO) != 0)
26+ #define SAMPLESIZE_SHORT () ((gflags & FLAG_SAMPLESIZE_SHORT) != 0)
27+ #define TOGGLE (K , F ) do { if (IsKeyPressed(K)) { gflags ^= (F); } } while (0)
2328
2429#define MAX_SAMPLES 512
2530#define MAX_SAMPLES_PER_UPDATE 4096
@@ -37,7 +42,7 @@ float oldFrequency = 1.0f;
3742float sineIdx = 0.0f ;
3843
3944// Audio input processing callback
40- void AudioInputCallback (void * buffer , unsigned int frames )
45+ void AudioInputCallbackMonoShort (void * buffer , unsigned int frames )
4146{
4247 audioFrequency = frequency + (audioFrequency - frequency )* 0.95f ;
4348
@@ -52,6 +57,54 @@ void AudioInputCallback(void *buffer, unsigned int frames)
5257 }
5358}
5459
60+ void AudioInputCallbackStereoShort (void * buffer , unsigned int frames )
61+ {
62+ audioFrequency = frequency + (audioFrequency - frequency )* 0.95f ;
63+
64+ float incr = audioFrequency /44100.0f ;
65+ short * d = (short * )buffer ;
66+
67+ for (unsigned int i = 0 ; i < frames ; i ++ )
68+ {
69+ short s = (short )(32000.0f * sinf (2 * PI * sineIdx ));
70+ d [2 * i + 0 ] = s ; // L
71+ d [2 * i + 1 ] = s ; // R
72+ sineIdx += incr ;
73+ if (sineIdx > 1.0f ) sineIdx -= 1.0f ;
74+ }
75+ }
76+
77+ void AudioInputCallbackMonoFloat (void * buffer , unsigned int frames )
78+ {
79+ audioFrequency = frequency + (audioFrequency - frequency )* 0.95f ;
80+
81+ float incr = audioFrequency /44100.0f ;
82+ float * d = (float * )buffer ;
83+
84+ for (unsigned int i = 0 ; i < frames ; i ++ )
85+ {
86+ d [i ] = sinf (2 * PI * sineIdx );
87+ sineIdx += incr ;
88+ if (sineIdx > 1.0f ) sineIdx -= 1.0f ;
89+ }
90+ }
91+
92+ void AudioInputCallbackStereoFloat (void * buffer , unsigned int frames )
93+ {
94+ audioFrequency = frequency + (audioFrequency - frequency )* 0.95f ;
95+ float incr = audioFrequency /44100.0f ;
96+ float * d = (float * )buffer ;
97+ for (unsigned int i = 0 ; i < frames ; i ++ )
98+ {
99+ float s = sinf (2 * PI * sineIdx );
100+ d [2 * i + 0 ] = s ;
101+ d [2 * i + 1 ] = s ;
102+
103+ sineIdx += incr ;
104+ if (sineIdx > 1.0f ) sineIdx -= 1.0f ;
105+ }
106+ }
107+
55108//------------------------------------------------------------------------------------
56109// Program main entry point
57110//------------------------------------------------------------------------------------
@@ -62,7 +115,7 @@ int main(void)
62115 const int screenWidth = 800 ;
63116 const int screenHeight = 450 ;
64117
65- InitWindow (screenWidth , screenHeight , "raylib [audio] example - raw stream" );
118+ InitWindow (screenWidth , screenHeight , "raylib [audio] example - raw stream with callbacks " );
66119
67120 InitAudioDevice (); // Initialize audio device
68121
@@ -71,7 +124,9 @@ int main(void)
71124 // Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
72125 AudioStream stream = LoadAudioStream (44100 , 16 , 1 );
73126
74- SetAudioStreamCallback (stream , AudioInputCallback );
127+ SetAudioStreamCallback (stream , AudioInputCallbackMonoShort );
128+ unsigned int previousSampleSize = stream .sampleSize ;
129+ unsigned int previousChannels = stream .channels ;
75130
76131 // Buffer for the single cycle waveform we are synthesizing
77132 short * data = (short * )malloc (sizeof (short )* MAX_SAMPLES );
@@ -84,17 +139,6 @@ int main(void)
84139 // Position read in to determine next frequency
85140 Vector2 mousePosition = { -100.0f , -100.0f };
86141
87- /*
88- // Cycles per second (hz)
89- float frequency = 440.0f;
90-
91- // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
92- float oldFrequency = 1.0f;
93-
94- // Cursor to read and copy the samples of the sine wave buffer
95- int readCursor = 0;
96- */
97-
98142 // Computed size in samples of the sine wave
99143 int waveLength = 1 ;
100144
@@ -106,6 +150,32 @@ int main(void)
106150 // Main game loop
107151 while (!WindowShouldClose ()) // Detect window close button or ESC key
108152 {
153+ TOGGLE (KEY_M , FLAG_CHANNEL_MONO );
154+ TOGGLE (KEY_F , FLAG_SAMPLESIZE_SHORT );
155+ unsigned int nextSampleSize = (SAMPLESIZE_SHORT ())? 16u : 32u ;
156+ unsigned int nextChannels = (CHANNEL_MONO ())? 1u : 2u ;
157+ if (nextSampleSize != previousSampleSize || nextChannels != previousChannels )
158+ {
159+ StopAudioStream (stream );
160+ UnloadAudioStream (stream );
161+ stream = LoadAudioStream (44100 , nextSampleSize , nextChannels );
162+ // CORRECT ALIGNMENT
163+ if (nextChannels == 1 && nextSampleSize == 16 ) SetAudioStreamCallback (stream , AudioInputCallbackMonoShort );
164+ if (nextChannels == 2 && nextSampleSize == 16 ) SetAudioStreamCallback (stream , AudioInputCallbackStereoShort );
165+ if (nextChannels == 1 && nextSampleSize == 32 ) SetAudioStreamCallback (stream , AudioInputCallbackMonoFloat );
166+ if (nextChannels == 2 && nextSampleSize == 32 ) SetAudioStreamCallback (stream , AudioInputCallbackStereoFloat );
167+
168+ // INCORRECT ALIGNMENT TESTS: comment and uncomment or add your own to observe common misconfigurations
169+ // if (nextChannels == 1 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackStereoShort);
170+ // if (nextChannels == 1 && nextSampleSize == 32) SetAudioStreamCallback(stream, AudioInputCallbackMonoShort);
171+ // if (nextChannels == 2 && nextSampleSize == 32) SetAudioStreamCallback(stream, AudioInputCallbackMonoShort);
172+ // if (nextChannels == 2 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackMonoFloat);
173+ // if (nextChannels == 2 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackStereoFloat);
174+
175+ PlayAudioStream (stream );
176+ previousSampleSize = nextSampleSize ;
177+ previousChannels = nextChannels ;
178+ }
109179 // Update
110180 //----------------------------------------------------------------------------------
111181 mousePosition = GetMousePosition ();
@@ -124,7 +194,6 @@ int main(void)
124194 if (frequency != oldFrequency )
125195 {
126196 // Compute wavelength. Limit size in both directions
127- //int oldWavelength = waveLength;
128197 waveLength = (int )(22050 /frequency );
129198 if (waveLength > MAX_SAMPLES /2 ) waveLength = MAX_SAMPLES /2 ;
130199 if (waveLength < 1 ) waveLength = 1 ;
@@ -140,41 +209,9 @@ int main(void)
140209 data [j ] = (short )0 ;
141210 }
142211
143- // Scale read cursor's position to minimize transition artifacts
144- //readCursor = (int)(readCursor*((float)waveLength/(float)oldWavelength));
145212 oldFrequency = frequency ;
146213 }
147214
148- /*
149- // Refill audio stream if required
150- if (IsAudioStreamProcessed(stream))
151- {
152- // Synthesize a buffer that is exactly the requested size
153- int writeCursor = 0;
154-
155- while (writeCursor < MAX_SAMPLES_PER_UPDATE)
156- {
157- // Start by trying to write the whole chunk at once
158- int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor;
159-
160- // Limit to the maximum readable size
161- int readLength = waveLength-readCursor;
162-
163- if (writeLength > readLength) writeLength = readLength;
164-
165- // Write the slice
166- memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));
167-
168- // Update cursors and loop audio
169- readCursor = (readCursor + writeLength) % waveLength;
170-
171- writeCursor += writeLength;
172- }
173-
174- // Copy finished frame to audio stream
175- UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE);
176- }
177- */
178215 //----------------------------------------------------------------------------------
179216
180217 // Draw
@@ -185,6 +222,10 @@ int main(void)
185222
186223 DrawText (TextFormat ("sine frequency: %i" ,(int )frequency ), GetScreenWidth () - 220 , 10 , 20 , RED );
187224 DrawText ("click mouse button to change frequency or pan" , 10 , 10 , 20 , DARKGRAY );
225+ DrawText ("press M to SWAP channels [ M ]:" , 250 , 366 , 20 , BLUE );
226+ DrawText ((CHANNEL_MONO ())? "MONO" : "STEREO" , 600 , 366 , 20 , (CHANNEL_MONO ())? GREEN : RED );
227+ DrawText ("press F to SWAP Sample Size [ F ]:" , 250 , 400 , 20 , BLUE );
228+ DrawText ((SAMPLESIZE_SHORT ())? "16" : "32" , 620 , 400 , 20 , (SAMPLESIZE_SHORT ())? GREEN : RED );
188229
189230 // Draw the current buffer state proportionate to the screen
190231 for (int i = 0 ; i < screenWidth ; i ++ )
0 commit comments