1+ /*******************************************************************************************
2+ *
3+ * raylib [audio] example - raw stream
4+ *
5+ * Example complexity rating: [★★★☆] 3/4
6+ *
7+ * Example originally created with raylib 1.6, last time updated with raylib 4.2
8+ *
9+ * Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
10+ *
11+ * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
12+ * BSD-like license that allows static linking with closed source software
13+ *
14+ * Copyright (c) 2015-2025 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
15+ *
16+ ********************************************************************************************/
17+
18+ #include "raylib.h"
19+
20+ #include <stdlib.h> // Required for: malloc(), free()
21+ #include <math.h> // Required for: sinf()
22+ #include <string.h> // Required for: memcpy()
23+
24+ #define MAX_SAMPLES 512
25+ #define MAX_SAMPLES_PER_UPDATE 4096
26+
27+ // Cycles per second (hz)
28+ float frequency = 440.0f ;
29+
30+ // Audio frequency, for smoothing
31+ float audioFrequency = 440.0f ;
32+
33+ // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
34+ float oldFrequency = 1.0f ;
35+
36+ // Index for audio rendering
37+ float sineIdx = 0.0f ;
38+
39+ // Audio input processing callback
40+ void AudioInputCallback (void * buffer , unsigned int frames )
41+ {
42+ audioFrequency = frequency + (audioFrequency - frequency )* 0.95f ;
43+
44+ float incr = audioFrequency /44100.0f ;
45+ short * d = (short * )buffer ;
46+
47+ for (unsigned int i = 0 ; i < frames ; i ++ )
48+ {
49+ d [i ] = (short )(32000.0f * sinf (2 * PI * sineIdx ));
50+ sineIdx += incr ;
51+ if (sineIdx > 1.0f ) sineIdx -= 1.0f ;
52+ }
53+ }
54+
55+ //------------------------------------------------------------------------------------
56+ // Program main entry point
57+ //------------------------------------------------------------------------------------
58+ int main (void )
59+ {
60+ // Initialization
61+ //--------------------------------------------------------------------------------------
62+ const int screenWidth = 800 ;
63+ const int screenHeight = 450 ;
64+
65+ InitWindow (screenWidth , screenHeight , "raylib [audio] example - raw stream" );
66+
67+ InitAudioDevice (); // Initialize audio device
68+
69+ SetAudioStreamBufferSizeDefault (MAX_SAMPLES_PER_UPDATE );
70+
71+ // Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
72+ AudioStream stream = LoadAudioStream (44100 , 16 , 1 );
73+
74+ SetAudioStreamCallback (stream , AudioInputCallback );
75+
76+ // Buffer for the single cycle waveform we are synthesizing
77+ short * data = (short * )malloc (sizeof (short )* MAX_SAMPLES );
78+
79+ // Frame buffer, describing the waveform when repeated over the course of a frame
80+ short * writeBuf = (short * )malloc (sizeof (short )* MAX_SAMPLES_PER_UPDATE );
81+
82+ PlayAudioStream (stream ); // Start processing stream buffer (no data loaded currently)
83+
84+ // Position read in to determine next frequency
85+ Vector2 mousePosition = { -100.0f , -100.0f };
86+
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+
98+ // Computed size in samples of the sine wave
99+ int waveLength = 1 ;
100+
101+ Vector2 position = { 0 , 0 };
102+
103+ SetTargetFPS (30 ); // Set our game to run at 30 frames-per-second
104+ //--------------------------------------------------------------------------------------
105+
106+ // Main game loop
107+ while (!WindowShouldClose ()) // Detect window close button or ESC key
108+ {
109+ // Update
110+ //----------------------------------------------------------------------------------
111+ mousePosition = GetMousePosition ();
112+
113+ if (IsMouseButtonDown (MOUSE_BUTTON_LEFT ))
114+ {
115+ float fp = (float )(mousePosition .y );
116+ frequency = 40.0f + (float )(fp );
117+
118+ float pan = (float )(mousePosition .x )/(float )screenWidth ;
119+ SetAudioStreamPan (stream , pan );
120+ }
121+
122+ // Rewrite the sine wave
123+ // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
124+ if (frequency != oldFrequency )
125+ {
126+ // Compute wavelength. Limit size in both directions
127+ //int oldWavelength = waveLength;
128+ waveLength = (int )(22050 /frequency );
129+ if (waveLength > MAX_SAMPLES /2 ) waveLength = MAX_SAMPLES /2 ;
130+ if (waveLength < 1 ) waveLength = 1 ;
131+
132+ // Write sine wave
133+ for (int i = 0 ; i < waveLength * 2 ; i ++ )
134+ {
135+ data [i ] = (short )(sinf (((2 * PI * (float )i /waveLength )))* 32000 );
136+ }
137+ // Make sure the rest of the line is flat
138+ for (int j = waveLength * 2 ; j < MAX_SAMPLES ; j ++ )
139+ {
140+ data [j ] = (short )0 ;
141+ }
142+
143+ // Scale read cursor's position to minimize transition artifacts
144+ //readCursor = (int)(readCursor*((float)waveLength/(float)oldWavelength));
145+ oldFrequency = frequency ;
146+ }
147+
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+ */
178+ //----------------------------------------------------------------------------------
179+
180+ // Draw
181+ //----------------------------------------------------------------------------------
182+ BeginDrawing ();
183+
184+ ClearBackground (RAYWHITE );
185+
186+ DrawText (TextFormat ("sine frequency: %i" ,(int )frequency ), GetScreenWidth () - 220 , 10 , 20 , RED );
187+ DrawText ("click mouse button to change frequency or pan" , 10 , 10 , 20 , DARKGRAY );
188+
189+ // Draw the current buffer state proportionate to the screen
190+ for (int i = 0 ; i < screenWidth ; i ++ )
191+ {
192+ position .x = (float )i ;
193+ position .y = 250 + 50 * data [i * MAX_SAMPLES /screenWidth ]/32000.0f ;
194+
195+ DrawPixelV (position , RED );
196+ }
197+
198+ EndDrawing ();
199+ //----------------------------------------------------------------------------------
200+ }
201+
202+ // De-Initialization
203+ //--------------------------------------------------------------------------------------
204+ free (data ); // Unload sine wave data
205+ free (writeBuf ); // Unload write buffer
206+
207+ UnloadAudioStream (stream ); // Close raw audio stream and delete buffers from RAM
208+ CloseAudioDevice (); // Close audio device (music streaming is automatically stopped)
209+
210+ CloseWindow (); // Close window and OpenGL context
211+ //--------------------------------------------------------------------------------------
212+
213+ return 0 ;
214+ }
0 commit comments