summaryrefslogtreecommitdiffhomepage
path: root/examples/web/audio/audio_raw_stream.c
blob: aeb16ba68124a84f9b7f6dac4583ef19cf9542fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*******************************************************************************************
*
*   raylib [audio] example - Raw audio streaming
*
*   This example has been created using raylib 1.6 (www.raylib.com)
*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
*   Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
*
*   Copyright (c) 2015-2019 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
*
********************************************************************************************/

#include "raylib.h"

#if defined(PLATFORM_WEB)
    #include <emscripten/emscripten.h>
#endif

#include <stdlib.h>         // Required for: malloc(), free()
#include <math.h>           // Required for: sinf()
#include <string.h>         // Required for: memcpy()

#define MAX_SAMPLES               512
#define MAX_SAMPLES_PER_UPDATE   4096

//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;

AudioStream stream = { 0 };
short *data;
short *writeBuf;

Vector2 mousePosition = { -100.0f, -100.0f };
float frequency = 440.0f;
float oldFrequency = 1.0f;
int readCursor = 0;
int waveLength = 1;
Vector2 position = { 0, 0 };

//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
void UpdateDrawFrame(void);     // Update and Draw one frame

//----------------------------------------------------------------------------------
// Program Main Entry Point
//----------------------------------------------------------------------------------
int main(void)
{
    // Initialization
    //--------------------------------------------------------------------------------------
    InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw audio streaming");

    InitAudioDevice();              // Initialize audio device

    // Init raw audio stream (sample rate: 22050, sample size: 16bit-short, channels: 1-mono)
    stream = InitAudioStream(22050, 16, 1);

    // Buffer for the single cycle waveform we are synthesizing
    data = (short *)malloc(sizeof(short)*MAX_SAMPLES);

    // Frame buffer, describing the waveform when repeated over the course of a frame
    writeBuf = (short *)malloc(sizeof(short)*MAX_SAMPLES_PER_UPDATE);

    PlayAudioStream(stream);        // Start processing stream buffer (no data loaded currently)

#if defined(PLATFORM_WEB)
    emscripten_set_main_loop(UpdateDrawFrame, 60, 1);
#else
    SetTargetFPS(30);               // Set our game to run at 30 frames-per-second
    //--------------------------------------------------------------------------------------

    // Main game loop
    while (!WindowShouldClose())    // Detect window close button or ESC key
    {
        UpdateDrawFrame();
    }
#endif

    // De-Initialization
    //--------------------------------------------------------------------------------------
    free(data);                 // Unload sine wave data
    free(writeBuf);             // Unload write buffer

    CloseAudioStream(stream);   // Close raw audio stream and delete buffers from RAM
    CloseAudioDevice();         // Close audio device (music streaming is automatically stopped)

    CloseWindow();              // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

    return 0;
}

//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
void UpdateDrawFrame(void)
{
    // Update
    //----------------------------------------------------------------------------------
    mousePosition = GetMousePosition();

    if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
    {
        float fp = (float)(mousePosition.y);
        frequency = 40.0f + (float)(fp);
    }

    // Rewrite the sine wave.
    // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
    if (frequency != oldFrequency)
    {
        // Compute wavelength. Limit size in both directions.
        int oldWavelength = waveLength;
        waveLength = (int)(22050/frequency);
        if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2;
        if (waveLength < 1) waveLength = 1;

        // Write sine wave.
        for (int i = 0; i < waveLength*2; i++)
        {
            data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000);
        }

        // Scale read cursor's position to minimize transition artifacts
        readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength));
        oldFrequency = frequency;
    }

    // Refill audio stream if required
    if (IsAudioStreamProcessed(stream))
    {
        // Synthesize a buffer that is exactly the requested size
        int writeCursor = 0;

        while (writeCursor < MAX_SAMPLES_PER_UPDATE)
        {
            // Start by trying to write the whole chunk at once
            int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor;

            // Limit to the maximum readable size
            int readLength = waveLength-readCursor;

            if (writeLength > readLength) writeLength = readLength;

            // Write the slice
            memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));

            // Update cursors and loop audio
            readCursor = (readCursor + writeLength) % waveLength;

            writeCursor += writeLength;
        }

        // Copy finished frame to audio stream
        UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE);
    }
    //----------------------------------------------------------------------------------

    // Draw
    //----------------------------------------------------------------------------------
    BeginDrawing();

        ClearBackground(RAYWHITE);

        DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED);
        DrawText("click mouse button to change frequency", 10, 10, 20, DARKGRAY);

        // Draw the current buffer state proportionate to the screen
        for (int i = 0; i < screenWidth; i++)
        {
            position.x = i;
            position.y = 250 + 50*data[i*MAX_SAMPLES/screenWidth]/32000;

            DrawPixelV(position, RED);
        }

    EndDrawing();
    //----------------------------------------------------------------------------------
}