| 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 | |