1 | /******************************************************************************************* |
2 | * |
3 | * raylib [audio] example - Raw audio streaming |
4 | * |
5 | * This example has been created using raylib 1.6 (www.raylib.com) |
6 | * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) |
7 | * |
8 | * Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox) |
9 | * |
10 | * Copyright (c) 2015-2019 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) |
11 | * |
12 | ********************************************************************************************/ |
13 | |
14 | #include "raylib.h" |
15 | |
16 | #include <stdlib.h> // Required for: malloc(), free() |
17 | #include <math.h> // Required for: sinf() |
18 | #include <string.h> // Required for: memcpy() |
19 | |
20 | #define MAX_SAMPLES 512 |
21 | #define MAX_SAMPLES_PER_UPDATE 4096 |
22 | |
23 | int main(void) |
24 | { |
25 | // Initialization |
26 | //-------------------------------------------------------------------------------------- |
27 | const int screenWidth = 800; |
28 | const int screenHeight = 450; |
29 | |
30 | InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw audio streaming" ); |
31 | |
32 | InitAudioDevice(); // Initialize audio device |
33 | |
34 | // Init raw audio stream (sample rate: 22050, sample size: 16bit-short, channels: 1-mono) |
35 | AudioStream stream = InitAudioStream(22050, 16, 1); |
36 | |
37 | // Buffer for the single cycle waveform we are synthesizing |
38 | short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES); |
39 | |
40 | // Frame buffer, describing the waveform when repeated over the course of a frame |
41 | short *writeBuf = (short *)malloc(sizeof(short)*MAX_SAMPLES_PER_UPDATE); |
42 | |
43 | PlayAudioStream(stream); // Start processing stream buffer (no data loaded currently) |
44 | |
45 | // Position read in to determine next frequency |
46 | Vector2 mousePosition = { -100.0f, -100.0f }; |
47 | |
48 | // Cycles per second (hz) |
49 | float frequency = 440.0f; |
50 | |
51 | // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency |
52 | float oldFrequency = 1.0f; |
53 | |
54 | // Cursor to read and copy the samples of the sine wave buffer |
55 | int readCursor = 0; |
56 | |
57 | // Computed size in samples of the sine wave |
58 | int waveLength = 1; |
59 | |
60 | Vector2 position = { 0, 0 }; |
61 | |
62 | SetTargetFPS(30); // Set our game to run at 30 frames-per-second |
63 | //-------------------------------------------------------------------------------------- |
64 | |
65 | // Main game loop |
66 | while (!WindowShouldClose()) // Detect window close button or ESC key |
67 | { |
68 | // Update |
69 | //---------------------------------------------------------------------------------- |
70 | |
71 | // Sample mouse input. |
72 | mousePosition = GetMousePosition(); |
73 | |
74 | if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) |
75 | { |
76 | float fp = (float)(mousePosition.y); |
77 | frequency = 40.0f + (float)(fp); |
78 | } |
79 | |
80 | // Rewrite the sine wave. |
81 | // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc. |
82 | if (frequency != oldFrequency) |
83 | { |
84 | // Compute wavelength. Limit size in both directions. |
85 | int oldWavelength = waveLength; |
86 | waveLength = (int)(22050/frequency); |
87 | if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2; |
88 | if (waveLength < 1) waveLength = 1; |
89 | |
90 | // Write sine wave. |
91 | for (int i = 0; i < waveLength*2; i++) |
92 | { |
93 | data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000); |
94 | } |
95 | |
96 | // Scale read cursor's position to minimize transition artifacts |
97 | readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength)); |
98 | oldFrequency = frequency; |
99 | } |
100 | |
101 | // Refill audio stream if required |
102 | if (IsAudioStreamProcessed(stream)) |
103 | { |
104 | // Synthesize a buffer that is exactly the requested size |
105 | int writeCursor = 0; |
106 | |
107 | while (writeCursor < MAX_SAMPLES_PER_UPDATE) |
108 | { |
109 | // Start by trying to write the whole chunk at once |
110 | int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor; |
111 | |
112 | // Limit to the maximum readable size |
113 | int readLength = waveLength-readCursor; |
114 | |
115 | if (writeLength > readLength) writeLength = readLength; |
116 | |
117 | // Write the slice |
118 | memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short)); |
119 | |
120 | // Update cursors and loop audio |
121 | readCursor = (readCursor + writeLength) % waveLength; |
122 | |
123 | writeCursor += writeLength; |
124 | } |
125 | |
126 | // Copy finished frame to audio stream |
127 | UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE); |
128 | } |
129 | //---------------------------------------------------------------------------------- |
130 | |
131 | // Draw |
132 | //---------------------------------------------------------------------------------- |
133 | BeginDrawing(); |
134 | |
135 | ClearBackground(RAYWHITE); |
136 | |
137 | DrawText(FormatText("sine frequency: %i" ,(int)frequency), GetScreenWidth() - 220, 10, 20, RED); |
138 | DrawText("click mouse button to change frequency" , 10, 10, 20, DARKGRAY); |
139 | |
140 | // Draw the current buffer state proportionate to the screen |
141 | for (int i = 0; i < screenWidth; i++) |
142 | { |
143 | position.x = i; |
144 | position.y = 250 + 50*data[i*MAX_SAMPLES/screenWidth]/32000; |
145 | |
146 | DrawPixelV(position, RED); |
147 | } |
148 | |
149 | EndDrawing(); |
150 | //---------------------------------------------------------------------------------- |
151 | } |
152 | |
153 | // De-Initialization |
154 | //-------------------------------------------------------------------------------------- |
155 | free(data); // Unload sine wave data |
156 | free(writeBuf); // Unload write buffer |
157 | |
158 | CloseAudioStream(stream); // Close raw audio stream and delete buffers from RAM |
159 | CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) |
160 | |
161 | CloseWindow(); // Close window and OpenGL context |
162 | //-------------------------------------------------------------------------------------- |
163 | |
164 | return 0; |
165 | } |
166 | |