159 lines
5.8 KiB
C#
159 lines
5.8 KiB
C#
/*******************************************************************************************
|
|
*
|
|
* raylib [audio] example - mixed processor
|
|
*
|
|
* Example complexity rating: [★★★★] 4/4
|
|
*
|
|
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
|
*
|
|
* Example contributed by hkc (@hatkidchan) and reviewed by Ramon Santamaria (@raysan5)
|
|
*
|
|
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
|
* BSD-like license that allows static linking with closed source software
|
|
*
|
|
* Copyright (c) 2023-2025 hkc (@hatkidchan)
|
|
*
|
|
********************************************************************************************/
|
|
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using static Raylib_cs.Raylib;
|
|
|
|
namespace Examples.Audio;
|
|
|
|
[ExcludeFromBrowser("AttachAudioMixedProcessor callback is unreliable on the wasm audio backend")]
|
|
public unsafe partial class MixedProcessor : IExample
|
|
{
|
|
private const int screenWidth = 800;
|
|
private const int screenHeight = 450;
|
|
|
|
public string Name => "Audio / Mixed Processor";
|
|
|
|
public string Title => "raylib [audio] example - mixed processor";
|
|
|
|
private static float exponent = 1.0f; // Audio exponentiation value
|
|
private static readonly float[] averageVolume = new float[400]; // Average volume history
|
|
|
|
private Music music;
|
|
private Sound sound;
|
|
|
|
//------------------------------------------------------------------------------------
|
|
// Audio processing function
|
|
//------------------------------------------------------------------------------------
|
|
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
|
private static void ProcessAudio(void* buffer, uint frames)
|
|
{
|
|
float* samples = (float*)buffer; // Samples internally stored as <float>s
|
|
float average = 0.0f; // Temporary average volume
|
|
|
|
for (uint frame = 0; frame < frames; frame++)
|
|
{
|
|
float* left = &samples[frame * 2 + 0];
|
|
float* right = &samples[frame * 2 + 1];
|
|
|
|
*left = MathF.Pow(MathF.Abs(*left), exponent) * ((*left < 0.0f) ? -1.0f : 1.0f);
|
|
*right = MathF.Pow(MathF.Abs(*right), exponent) * ((*right < 0.0f) ? -1.0f : 1.0f);
|
|
|
|
average += MathF.Abs(*left) / frames; // accumulating average volume
|
|
average += MathF.Abs(*right) / frames;
|
|
}
|
|
|
|
// Moving history to the left
|
|
for (int i = 0; i < 399; i++) averageVolume[i] = averageVolume[i + 1];
|
|
|
|
averageVolume[399] = average; // Adding last average value
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
InitAudioDevice(); // Initialize audio device
|
|
|
|
exponent = 1.0f;
|
|
Array.Clear(averageVolume, 0, averageVolume.Length);
|
|
|
|
AttachAudioMixedProcessor(&ProcessAudio);
|
|
|
|
music = LoadMusicStream("resources/audio/country.mp3");
|
|
sound = LoadSound("resources/audio/coin.wav");
|
|
|
|
PlayMusicStream(music);
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
// Update
|
|
//----------------------------------------------------------------------------------
|
|
UpdateMusicStream(music); // Update music buffer with new stream data
|
|
|
|
// Modify processing variables
|
|
//----------------------------------------------------------------------------------
|
|
if (IsKeyPressed(KeyboardKey.Left)) exponent -= 0.05f;
|
|
if (IsKeyPressed(KeyboardKey.Right)) exponent += 0.05f;
|
|
|
|
if (exponent <= 0.5f) exponent = 0.5f;
|
|
if (exponent >= 3.0f) exponent = 3.0f;
|
|
|
|
if (IsKeyPressed(KeyboardKey.Space)) PlaySound(sound);
|
|
|
|
// Draw
|
|
//----------------------------------------------------------------------------------
|
|
BeginDrawing();
|
|
|
|
ClearBackground(Color.RayWhite);
|
|
|
|
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
|
|
|
DrawText($"EXPONENT = {exponent:F2}", 215, 180, 20, Color.LightGray);
|
|
|
|
DrawRectangle(199, 199, 402, 34, Color.LightGray);
|
|
for (int i = 0; i < 400; i++)
|
|
{
|
|
DrawLine(201 + i, 232 - (int)(averageVolume[i] * 32), 201 + i, 232, Color.Maroon);
|
|
}
|
|
DrawRectangleLines(199, 199, 402, 34, Color.Gray);
|
|
|
|
DrawText("PRESS SPACE TO PLAY OTHER SOUND", 200, 250, 20, Color.LightGray);
|
|
DrawText("USE LEFT AND RIGHT ARROWS TO ALTER DISTORTION", 140, 280, 20, Color.LightGray);
|
|
|
|
EndDrawing();
|
|
//----------------------------------------------------------------------------------
|
|
}
|
|
|
|
public void Unload()
|
|
{
|
|
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
|
|
|
DetachAudioMixedProcessor(&ProcessAudio); // Disconnect audio processor
|
|
|
|
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
|
}
|
|
|
|
public static int Main()
|
|
{
|
|
// Initialization
|
|
//--------------------------------------------------------------------------------------
|
|
InitWindow(screenWidth, screenHeight, "raylib [audio] example - mixed processor");
|
|
|
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
var game = new MixedProcessor();
|
|
game.Init();
|
|
|
|
// Main game loop
|
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
|
{
|
|
game.Update();
|
|
}
|
|
|
|
game.Unload();
|
|
|
|
// De-Initialization
|
|
//--------------------------------------------------------------------------------------
|
|
CloseWindow(); // Close window and OpenGL context
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
return 0;
|
|
}
|
|
}
|