mirror of
https://github.com/Not-Nik/raylib-zig.git
synced 2025-09-08 19:47:28 +00:00
Add an implementation of Zig's Allocator interface (#94)
This commit is contained in:
parent
b5330624d6
commit
39909cdcb3
@ -163,6 +163,11 @@ pub fn build(b: *std.Build) !void {
|
||||
};
|
||||
|
||||
const examples = [_]Program{
|
||||
.{
|
||||
.name = "raw_stream",
|
||||
.path = "examples/audio/raw_stream.zig",
|
||||
.desc = "Plays a sine wave",
|
||||
},
|
||||
.{
|
||||
.name = "basic_screen_manager",
|
||||
.path = "examples/core/basic_screen_manager.zig",
|
||||
|
131
examples/audio/raw_stream.zig
Normal file
131
examples/audio/raw_stream.zig
Normal file
@ -0,0 +1,131 @@
|
||||
// raylib-zig (c) Nikolas Wipper 2023
|
||||
|
||||
const rl = @import("raylib");
|
||||
|
||||
const MAX_SAMPLES = 512;
|
||||
const MAX_SAMPLES_PER_UPDATE = 4096;
|
||||
|
||||
const pi = @import("std").math.pi;
|
||||
var frequency: f32 = 440;
|
||||
var audioFrequency: f32 = 440;
|
||||
var oldFrequency: f32 = 1;
|
||||
var sineIdx: f32 = 0;
|
||||
|
||||
fn audioInputCallback(buffer: ?*anyopaque, frames: c_uint) callconv(.C) void {
|
||||
audioFrequency = frequency + (audioFrequency - frequency) * 0.95;
|
||||
|
||||
const incr = audioFrequency / 44100;
|
||||
const d: [*]i16 = @alignCast(@ptrCast(buffer orelse return));
|
||||
|
||||
for (0..frames) |i| {
|
||||
d[i] = @intFromFloat(32000 * @sin(2 * pi * sineIdx));
|
||||
sineIdx += incr;
|
||||
if (sineIdx > 1) {
|
||||
sineIdx -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const screenWidth = 800;
|
||||
const screenHeight = 450;
|
||||
|
||||
rl.initWindow(screenWidth, screenHeight, "raylib-zig [core] example - raw audio streaming");
|
||||
defer rl.closeWindow(); // Close window and OpenGL context
|
||||
|
||||
rl.initAudioDevice(); // Initialize audio device
|
||||
defer rl.closeAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
|
||||
rl.setAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
|
||||
const stream = rl.loadAudioStream(44100, 16, 1);
|
||||
defer rl.unloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
|
||||
|
||||
rl.setAudioStreamCallback(stream, &audioInputCallback);
|
||||
|
||||
// Buffer for the single cycle waveform we are synthesizing
|
||||
const data = try rl.mem.alloc(i16, MAX_SAMPLES);
|
||||
defer rl.mem.free(data); // Unload sine wave data
|
||||
|
||||
// Frame buffer, describing the waveform when repeated over the course of a frame
|
||||
const writeBuf = try rl.mem.alloc(i16, MAX_SAMPLES_PER_UPDATE);
|
||||
defer rl.mem.free(writeBuf); // Unload write buffer
|
||||
|
||||
rl.playAudioStream(stream); // Start processing stream buffer (no data loaded currently)
|
||||
|
||||
// Computed size in samples of the sine wave
|
||||
var waveLength: i32 = 1;
|
||||
|
||||
var position = rl.Vector2{ .x = 0, .y = 0 };
|
||||
|
||||
rl.setTargetFPS(30); // Set our game to run at 30 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
if (rl.isMouseButtonDown(.mouse_button_left)) {
|
||||
// Sample mouse input.
|
||||
const mousePosition = rl.getMousePosition();
|
||||
|
||||
const fp = (screenHeight - mousePosition.y);
|
||||
frequency = 40 + fp;
|
||||
|
||||
const pan = (screenWidth - mousePosition.x) / screenWidth;
|
||||
rl.setAudioStreamPan(stream, pan);
|
||||
}
|
||||
|
||||
// Rewrite the sine wave
|
||||
// Compute two cycles to allow buffer padding, simplifying any modulation, resampling, etc.
|
||||
if (frequency != oldFrequency) {
|
||||
// Compute wavelength. Limit size in both directions.
|
||||
//int oldWavelength = waveLength;
|
||||
waveLength = @intFromFloat(22050 / frequency);
|
||||
waveLength = @min(@max(1, waveLength), MAX_SAMPLES / 2);
|
||||
|
||||
// Write sine wave
|
||||
const n: u32 = @intCast(waveLength * 2);
|
||||
for (0..n) |i| {
|
||||
const wlen: f32 = @floatFromInt(waveLength);
|
||||
const idx: f32 = @floatFromInt(i);
|
||||
data[i] = @intFromFloat(@sin((2 * pi * idx / wlen)) * 32000);
|
||||
}
|
||||
// Make sure the rest of the line is flat
|
||||
for (n..MAX_SAMPLES) |i| {
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
// Scale read cursor's position to minimize transition artifacts
|
||||
//readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength));
|
||||
oldFrequency = frequency;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
rl.beginDrawing();
|
||||
defer rl.endDrawing();
|
||||
|
||||
rl.clearBackground(rl.Color.ray_white);
|
||||
|
||||
rl.drawText(rl.textFormat("sine frequency: %i", .{@as(i32, @intFromFloat(frequency))}),
|
||||
rl.getScreenWidth() - 220, 10, 20, rl.Color.red);
|
||||
rl.drawText("click mouse button to change frequency or pan",
|
||||
10, 10, 20, rl.Color.dark_gray);
|
||||
|
||||
// Draw the current buffer state proportionate to the screen
|
||||
for (0..screenWidth) |i| {
|
||||
position.x = @floatFromInt(i);
|
||||
const y: f32 = @floatFromInt(data[@divFloor(i * MAX_SAMPLES, screenWidth)]);
|
||||
position.y = 250 + 50 * y / 32000;
|
||||
|
||||
rl.drawPixelV(position, rl.Color.red);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
}
|
@ -1437,3 +1437,27 @@ pub fn textJoin(textList: [][:0]const u8, delimiter: [:0]const u8) [:0]const u8
|
||||
pub fn drawTriangleStrip3D(points: []Vector3, color: Color) void {
|
||||
cdef.DrawTriangleStrip3D(@as([*c]Vector3, @ptrCast(points)), @as(c_int, @intCast(points.len)), color);
|
||||
}
|
||||
|
||||
fn alloc(_: *anyopaque, len: usize, _: u8, _: usize) ?[*]u8 {
|
||||
std.debug.assert(len > 0);
|
||||
return @ptrCast(cdef.MemAlloc(@intCast(len)));
|
||||
}
|
||||
|
||||
fn resize(_: *anyopaque, buf: []u8, _: u8, new_len: usize, _: usize) bool {
|
||||
return (new_len <= buf.len);
|
||||
}
|
||||
|
||||
fn free(_: *anyopaque, buf: []u8, _: u8, _: usize) void {
|
||||
cdef.MemFree(buf.ptr);
|
||||
}
|
||||
|
||||
const mem_vtable = std.mem.Allocator.VTable{
|
||||
.alloc = alloc,
|
||||
.resize = resize,
|
||||
.free = free,
|
||||
};
|
||||
|
||||
pub const mem = std.mem.Allocator{
|
||||
.ptr = undefined,
|
||||
.vtable = &mem_vtable,
|
||||
};
|
||||
|
@ -1438,6 +1438,30 @@ pub fn drawTriangleStrip3D(points: []Vector3, color: Color) void {
|
||||
cdef.DrawTriangleStrip3D(@as([*c]Vector3, @ptrCast(points)), @as(c_int, @intCast(points.len)), color);
|
||||
}
|
||||
|
||||
fn alloc(_: *anyopaque, len: usize, _: u8, _: usize) ?[*]u8 {
|
||||
std.debug.assert(len > 0);
|
||||
return @ptrCast(cdef.MemAlloc(@intCast(len)));
|
||||
}
|
||||
|
||||
fn resize(_: *anyopaque, buf: []u8, _: u8, new_len: usize, _: usize) bool {
|
||||
return (new_len <= buf.len);
|
||||
}
|
||||
|
||||
fn free(_: *anyopaque, buf: []u8, _: u8, _: usize) void {
|
||||
cdef.MemFree(buf.ptr);
|
||||
}
|
||||
|
||||
const mem_vtable = std.mem.Allocator.VTable{
|
||||
.alloc = alloc,
|
||||
.resize = resize,
|
||||
.free = free,
|
||||
};
|
||||
|
||||
pub const mem = std.mem.Allocator{
|
||||
.ptr = undefined,
|
||||
.vtable = &mem_vtable,
|
||||
};
|
||||
|
||||
pub fn initWindow(width: i32, height: i32, title: [:0]const u8) void {
|
||||
cdef.InitWindow(@as(c_int, width), @as(c_int, height), @as([*c]const u8, @ptrCast(title)));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user