Skip to content

Instantly share code, notes, and snippets.

@sdroege
Created October 6, 2017 23:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sdroege/ee3a449a5a8ee6c3db96ae989098bbc3 to your computer and use it in GitHub Desktop.
Save sdroege/ee3a449a5a8ee6c3db96ae989098bbc3 to your computer and use it in GitHub Desktop.
$ gcc -v
gcc version 6.4.0 20170724 (Debian 6.4.0-2)
$ gcc -O3 -o test-c test.c
$ gcc -O3 -o test-c2 test2.c
$ clang --version
clang version 3.8.1-24 (tags/RELEASE_381/final)
$ clang -O3 -o test-c-clang test.c
$ clang -O3 -o test-c2-clang test2.c
$ rustc -v
rustc 1.20.0 (f3d6973f4 2017-08-27)
$ rustc -C opt-level=3 test.rs -o test-rs
$ time ./test-rs 100000000 50000000 0.5 0.0 1000000 1024
0
11.87user 0.00system 0:11.87elapsed 100%CPU (0avgtext+0avgdata 2252maxresident)k
0inputs+0outputs (0major+141minor)pagefaults 0swaps
$ time ./test-c 100000000 50000000 0.5 0.0 1000000 1024
0.000000
19.47user 0.00system 0:19.47elapsed 100%CPU (0avgtext+0avgdata 1428maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps
$ time ./test-c2 100000000 50000000 0.5 0.0 1000000 1024
0.000000
13.26user 0.00system 0:13.26elapsed 99%CPU (0avgtext+0avgdata 1476maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps
ime ./test-c-clang 100000000 50000000 0.5 0.0 1000000 1024
0.000000
15.85user 0.00system 0:15.85elapsed 100%CPU (0avgtext+0avgdata 1484maxresident)k
0inputs+0outputs (0major+76minor)pagefaults 0swaps
time ./test-c2-clang 100000000 50000000 0.5 0.0 1000000 1024
0.000000
11.50user 0.00system 0:11.50elapsed 100%CPU (0avgtext+0avgdata 1380maxresident)k
0inputs+0outputs (0major+74minor)pagefaults 0swaps
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define RATE 48000
#define SECOND 1000000000
typedef struct {
double *buffer;
size_t pos, size;
} Buffer;
typedef struct {
uint64_t max_delay;
uint64_t delay;
double intensity;
double feedback;
} Settings;
static void
process(double *data, unsigned int num_samples, Buffer *buffer, Settings *settings) {
size_t i;
size_t echo_offset = buffer->size - (settings->delay * RATE / SECOND);
double intensity = settings->intensity;
double feedback = settings->feedback;
double *buffer_data = buffer->buffer;
size_t buffer_pos = buffer->pos;
size_t buffer_size = buffer->size;
for (i = 0; i < num_samples; i++) {
size_t echo_index = (echo_offset + buffer_pos) % buffer_size;
size_t rbout_index = buffer_pos % buffer_size;
double in = data[i];
double echo = buffer_data[echo_index];
double out = in + intensity * echo;
data[i] = out;
buffer_data[rbout_index] = in + feedback * echo;
buffer_pos = (buffer_pos + 1) % buffer_size;
}
buffer->pos = buffer_pos;
}
static void
parse_commandline_args(char **argv, Settings * settings, size_t *n_buffers, size_t *samples_per_buffer) {
settings->max_delay = strtoul(argv[1], NULL, 10);
settings->delay = strtoul(argv[2], NULL, 10);
settings->intensity = strtod(argv[3], NULL);
settings->feedback = strtod(argv[4], NULL);
*n_buffers = strtoul(argv[5], NULL, 10);
*samples_per_buffer = strtoul(argv[6], NULL, 10);
}
int
main(int argc, char **argv) {
Settings settings;
Buffer buffer;
size_t n_buffers;
size_t samples_per_buffer;
size_t i;
double *data;
parse_commandline_args(argv, &settings, &n_buffers, &samples_per_buffer);
buffer.pos = 0;
buffer.size = settings.max_delay * RATE / SECOND;
buffer.buffer = calloc(buffer.size, sizeof(double));
data = calloc(samples_per_buffer, sizeof(double));
for (i = 0; i < n_buffers; i++) {
process(data, samples_per_buffer, &buffer, &settings);
}
printf("%lf\n", data[0]);
}
use std::{iter, i32, u64, env};
const RATE: i32 = 48_000;
const SECOND: u64 = 1_000_000_000;
#[derive(Debug, Clone, Copy)]
struct Settings {
pub max_delay: u64,
pub delay: u64,
pub intensity: f64,
pub feedback: f64,
}
struct State {
buffer: RingBuffer,
}
fn process(data: &mut [f64], state: &mut State, settings: &Settings) {
let delay_frames = (settings.delay as usize) * (RATE as usize) / (SECOND as usize);
for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
let inp = *i;
let out = inp + settings.intensity * e;
*o = inp + settings.feedback * e;
*i = out;
}
}
pub fn main() {
let args: Vec<String> = env::args().collect();
let settings = Settings {
max_delay: args[1].parse().unwrap(),
delay: args[2].parse().unwrap(),
intensity: args[3].parse().unwrap(),
feedback: args[4].parse().unwrap(),
};
let mut state = State {
buffer: RingBuffer::new((settings.max_delay as usize) * (RATE as usize) / (SECOND as usize)),
};
let n_buffers: usize = args[5].parse().unwrap();
let samples_per_buffer: usize = args[6].parse().unwrap();
let mut buffer: Vec<f64> = Vec::with_capacity(samples_per_buffer);
buffer.extend(iter::repeat(0.0).take(samples_per_buffer as usize));
for _ in 0..n_buffers {
process(buffer.as_mut_slice(), &mut state, &settings);
}
println!("{}", buffer[0]);
}
struct RingBuffer {
buffer: Vec<f64>,
pos: usize,
size: usize,
}
impl RingBuffer {
fn new(size: usize) -> Self {
let mut buffer = Vec::with_capacity(size as usize);
buffer.extend(iter::repeat(0.0).take(size as usize));
Self {
buffer: buffer,
pos: 0,
size: size,
}
}
fn iter(&mut self, delay: usize) -> RingBufferIter {
RingBufferIter::new(self, delay)
}
}
struct RingBufferIter<'a> {
buffer: &'a mut RingBuffer,
ptr: *mut f64,
read_pos: usize,
write_pos: usize,
}
impl<'a> RingBufferIter<'a> {
fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
assert!(buffer.size >= delay);
assert_ne!(buffer.size, 0);
let ptr = buffer.buffer.as_mut_ptr();
let read_pos = (buffer.size - delay + buffer.pos) % buffer.size;
let write_pos = buffer.pos % buffer.size;
RingBufferIter {
buffer: buffer,
ptr: ptr,
read_pos: read_pos,
write_pos: write_pos,
}
}
}
impl<'a> Iterator for RingBufferIter<'a> {
type Item = (&'a mut f64, f64);
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let res = (&mut *self.ptr.offset(self.write_pos as isize), *self.ptr.offset(self.read_pos as isize));
self.write_pos = (self.write_pos + 1) % self.buffer.size;
self.read_pos = (self.read_pos + 1) % self.buffer.size;
Some(res)
}
}
}
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define RATE 48000
#define SECOND 1000000000
typedef struct {
double *buffer;
size_t pos, size;
} Buffer;
typedef struct {
uint64_t max_delay;
uint64_t delay;
double intensity;
double feedback;
} Settings;
static void
process(double *data, unsigned int num_samples, Buffer *buffer, Settings *settings) {
size_t i;
size_t echo_offset = buffer->size - (settings->delay * RATE / SECOND);
double intensity = settings->intensity;
double feedback = settings->feedback;
double *buffer_data = buffer->buffer;
size_t buffer_size = buffer->size;
size_t write_pos = buffer->pos;
size_t read_pos = (echo_offset + write_pos) % buffer_size;
for (i = 0; i < num_samples; i++) {
double in = data[i];
double echo = buffer_data[read_pos];
double out = in + intensity * echo;
data[i] = out;
buffer_data[write_pos] = in + feedback * echo;
write_pos = (write_pos + 1) % buffer_size;
read_pos = (read_pos + 1) % buffer_size;
}
buffer->pos = write_pos;
}
static void
parse_commandline_args(char **argv, Settings * settings, size_t *n_buffers, size_t *samples_per_buffer) {
settings->max_delay = strtoul(argv[1], NULL, 10);
settings->delay = strtoul(argv[2], NULL, 10);
settings->intensity = strtod(argv[3], NULL);
settings->feedback = strtod(argv[4], NULL);
*n_buffers = strtoul(argv[5], NULL, 10);
*samples_per_buffer = strtoul(argv[6], NULL, 10);
}
int
main(int argc, char **argv) {
Settings settings;
Buffer buffer;
size_t n_buffers;
size_t samples_per_buffer;
size_t i;
double *data;
parse_commandline_args(argv, &settings, &n_buffers, &samples_per_buffer);
buffer.pos = 0;
buffer.size = settings.max_delay * RATE / SECOND;
buffer.buffer = calloc(buffer.size, sizeof(double));
data = calloc(samples_per_buffer, sizeof(double));
for (i = 0; i < n_buffers; i++) {
process(data, samples_per_buffer, &buffer, &settings);
}
printf("%lf\n", data[0]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment