Browse Source

Initial commit

master
dirkson 7 months ago
parent
commit
b24d9deecf
5 changed files with 1040 additions and 11 deletions
  1. 15
    11
      LICENSE
  2. 274
    0
      build
  3. 119
    0
      include/sfxr.h
  4. 16
    0
      meson.build
  5. 616
    0
      src/sfxr.c

+ 15
- 11
LICENSE View File

@@ -1,21 +1,25 @@
MIT License

Copyright (c) <year> <copyright holders>
Björn cleaned up DrPetter's original code, I pulled that code out and made a standalone C library out of it.

Copyright (c) 2018 Dirkson
Copyright (c) 2017 Björn Ritzl
Copyright (c) 2007 DrPetter

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 274
- 0
build View File

@@ -0,0 +1,274 @@
#!/bin/bash

#************
#***CONFIG***
#************

#If COMPILER isn't set, the script will attempt to figure it out itself.
#If you change the compiler, you'll need to clean your build.
#COMPILER=musl-gcc

#If this isn't set, the script will attempt to find ninja and samu, in that order.
#Alternatives include samurai's "samu"
#NINJACOMMAND=ninja

#Directories
BUILDDIR=meson
DOCDIR=doc
BINDIR=bin
LIBDIR=lib
DEPDIR=subprojects
SCRIPTDIR=scripts

#***********
#***OSMIA***
#***********
#
# This is osmia, a build script for meson.
#
# Official URL:
# https://git.orangehattech.com/dirkson/osmia
#

#*************
#***LICENSE***
#*************
#
# MIT License
#
# Copyright (c) 2018 Dirkson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

#Functions

osmia_help () {
echo "Osmia build script for meson."
echo "Usage: ./build [-mode] [target]"
echo "Target will be passed to ninja directly"
echo "Mode defaults to release, or is one of the following:"
echo "-r OR --release : Builds using Meson's release mode"
echo "-d OR --debug : Builds using Meson's debug mode, with --werror added"
echo "-c OR --clean : Cleans up current project meson/ninja/osmia files"
echo "-fc OR --full-clean : Fully clean - Removes dependencies too"
echo "-a OR --add-san : Clang's address sanitizer"
echo "-w OR --win : Cross-compile for win32 using scripts/win32cross.txt"
echo "-w64 OR --win64 : cross-compile for win64"
echo "-o OR --osx : cross-compile for OSX"
}
osmia_clean () {
rm -rf $BUILDDIR $BINDIR $LIBDIR
}

osmia_symlink () {
FILES="$(find $1 -maxdepth 1 -type f $2 2> /dev/null)"
if [ ! -z "$FILES" ]; then
mkdir -p $3 2> /dev/null
rm -rf $3/* 2> /dev/null
for I in $FILES; do
ln -s ../$I $3/
done
fi
}

osmia_get () {
if [ ! -d "$1" ]; then
$2
if [ ! $? -eq 0 ]; then
echo "osmia: git command failed: $1"
exit 1
fi
if [ ! -d "$1" ]; then
echo "osmia: could not find directory: $1"
exit 1
fi
fi
}



clear

err=0;

if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
err=1
echo "osmia: er... Yeah, don't source this file."
return 1
fi

#What type of build?
case "$1" in
-d|-debug|--debug)
DIR=debug
BLD=debug
MESONOPTS="--werror"
;;
-a)
DIR=debug
BLD=debug
MESONOPTS=-Db_sanitize=address
MESONOPTS="--werror"
;;
-w|-win|--win|-window|--windows)
DIR=release
BLD=release
MESONOPTS="--cross-file scripts/win32cross.txt"
;;
-w64|-win64|--win64|-windows64|--windows64)
DIR=release
BLD=release
MESONOPTS="--cross-file scripts/win64cross.txt"
;;
-c|-clean|--clean)
if [ "$#" -ne 1 ]; then
echo "osmia: you passed additional arguments to clean. I have no idea what you want. Did not clean."
exit 1
fi
osmia_clean
echo "osmia: cleaned."
exit 0
;;
-fc|-fullclean|--fullclean|-full-clean|--full-clean)
if [ "$#" -ne 1 ]; then
echo "osmia: you passed additional arguments to clean. I have no idea what you want. Did not clean."
exit 1
fi
osmia_clean
rm -rf $DEPDIR
echo "osmia: fully cleaned."
exit 0
;;
-?|-h|-help|--help)
osmia_help
err=1
;;
-r|--release|*)
DIR=release
BLD=release
;;
esac

#do some basic error checking for the user
if [ -z "$NINJACOMMAND" ]; then
NINJACOMMAND=ninja
if [ ! -x "$(command -v $NINJACOMMAND)" ]; then
NINJACOMMAND=samu
if [ ! -x "$(command -v $NINJACOMMAND)" ]; then
echo "osmia: neither ninja nor samu are installed. One of the two is required to build."
echo "osmia: Please install either samurai's samu or ninja-build's ninja."
err=1;
fi
fi
else
if [ ! -x "$(command -v $NINJACOMMAND)" ]; then
echo "osmia: manually specified ninja command not found"
err=1;
fi
fi
if [ ! -x "$(command -v meson)" ]; then
echo "osmia: meson not installed. The meson build system is required to build, please install.";
err=1;
fi
if [ -z "$COMPILER" ]; then
if [ -x "$(command -v clang)" ]; then
COMPILER="clang"
elif [ -x "$(command -v musl-gcc)" ]; then
COMPILER="musl-gcc -static"
elif [ -x "$(command -v gcc)" ]; then
COMPILER="gcc"
elif [ -x "$(command -v tcc)" ]; then
COMPILER="tcc"
elif [ -x "$(command -v icc)" ]; then
COMPILER="icc"
else
echo "osmia: unable to find any compiler at all. Please install one: clang, musl-gcc, gcc, tcc, icc"
err=1
fi
else
if [ ! -x "$(command -v $COMPILER)" ]; then
echo "osmia: manually specified compiler does not exist. Failing."
err=1
fi
fi
if [ ! -x "$(command -v ccache)" ]; then
echo "somia: ccache not installed. Installing it could speed the build up. Hint Hint.";
fi

if [ "$#" -gt 2 ]; then
osmia_help
echo "osmia: failed, too many parameters."
err=1;
fi

#Note: For exit '0' is 'true' and '1' in 'false', in spite of all logic.
if [ $err -ne 0 ]; then
exit 1
fi

#Grab dependencies
if [ -d "$SCRIPTDIR" ] && [ -e scripts/dependencies ]; then
mkdir -p $DEPDIR 2> /dev/null
cd "$DEPDIR"
source ../scripts/dependencies
cd ../
fi


#Set up basic directory structure, if needed
mkdir -p $BUILDDIR 2> /dev/null

#MESONOPTS=MESONOPTS:"-Dc_args=$3"

if [ ! -d "$BUILDDIR/$DIR" ]; then
export CC="$COMPILER"
#Run meson if required
mkdir $BUILDDIR/$DIR
meson $BUILDDIR/$DIR $MESONOPTS --buildtype $BLD
if [ ! $? -eq 0 ]; then
#Generally an error here means we need to clean before the next run
tail $BUILDDIR/$DIR/meson-logs/meson-log.txt
cp $BUILDDIR/$DIR/meson-logs/meson-log.txt meson-log.txt
echo "osmia: meson returned an error. Please check meson-log.txt for more info."
osmia_clean
exit 1
fi
#else
#May wish to look into this in the future
#meson configure $MESONOPTS
fi

#Actually build
cd $BUILDDIR/$DIR
$NINJACOMMAND $2
if [ ! $? -eq 0 ]; then
cd ../../
exit 1
fi
cd ../../

#set up symlinks
osmia_symlink "$BUILDDIR/$DIR/*" "-name *.a -o -name *.so -o -name *.dll" $LIBDIR
osmia_symlink "$BUILDDIR/$DIR/*" "-not -name *.so -not -name *.dll -executable -not -name sanitycheckc.exe" $BINDIR
osmia_symlink "$BUILDDIR/$DIR/*" "-name *.html -o -name *.htm" $DOCDIR

echo "osmia: successful build."

exit 0

+ 119
- 0
include/sfxr.h View File

@@ -0,0 +1,119 @@
#pragma once
#ifndef SFXR_H
#define SFXR_H

#ifdef __cplusplus
extern "C"{
#endif

#define rnd(n) (rand()%(n+1))

#define PI 3.14159265f

struct SfxrSound {
unsigned char* data;
int length;
};

typedef struct Sfxr {
int wave_type;

float p_base_freq;
float p_freq_limit;
float p_freq_ramp;
float p_freq_dramp;
float p_duty;
float p_duty_ramp;

float p_vib_strength;
float p_vib_speed;
float p_vib_delay;

float p_env_attack;
float p_env_sustain;
float p_env_decay;
float p_env_punch;

int filter_on;
float p_lpf_resonance;
float p_lpf_freq;
float p_lpf_ramp;
float p_hpf_freq;
float p_hpf_ramp;

float p_pha_offset;
float p_pha_ramp;

float p_repeat_speed;

float p_arp_speed;
float p_arp_mod;

float master_vol;
float sound_vol;

float vib_phase;
float vib_speed;
float vib_amp;

int env_stage;
int env_time;
int env_length[3];
float env_vol;

int iphase;
float phaser_buffer[1024];
int ipp;
float noise_buffer[32];

float square_duty;
float square_slide;

int rep_time;
int rep_limit;
int arp_time;
int arp_limit;
double arp_mod;

double fslide;
double fdslide;

float fphase;
float fdphase;

float fltp;
float fltdp;
float fltdmp;
float fltphp;
float flthp;
float flthp_d;
float fltw;
float fltw_d;

int period;
int phase;

double fperiod;
double fmaxperiod;

int playing_sample;
int samples_played;

int buffer_byteswritten;
int file_bytesswritten;
float filesample;
} Sfxr;

struct SfxrSound SfxrBlip(int seed);
struct SfxrSound SfxrJump(int seed);
struct SfxrSound SfxrHurt(int seed);
struct SfxrSound SfxrPowerup(int seed);
struct SfxrSound SfxrExplosion(int seed);
struct SfxrSound SfxrLaser(int seed);
struct SfxrSound SfxrPickup(int seed);

#ifdef __cplusplus
}
#endif

#endif

+ 16
- 0
meson.build View File

@@ -0,0 +1,16 @@
project('bepx', 'c', default_options : ['default_library=static', 'c_std=gnu89'])
incdir = include_directories('include')

libbepx = library('bepx', 'src/sfxr.c', 'src/bepx.c', include_directories : incdir)
bepx_dep = declare_dependency(link_with : libbepx, include_directories : incdir)

if not meson.is_subproject()

#Basic test binary
executable('bepxbasic', 'src/examples/basic.c', include_directories : incdir, dependencies: bepx_dep)

#Complex test binary
executable('bepxtest', 'src/examples/test.c', include_directories : incdir, dependencies: [bepx_dep])

endif


+ 616
- 0
src/sfxr.c View File

@@ -0,0 +1,616 @@
/*
Copyright (c) 2007 Tomas Pettersson <drpetter@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "sfxr.h"

static Sfxr sfxr;

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>

float sfxr_frnd(float range)
{
return (float)rnd(10000)/10000*range;
}

void SfxrResetParams()
{
sfxr.wave_type=0;

sfxr.p_base_freq=0.3f;
sfxr.p_freq_limit=0.0f;
sfxr.p_freq_ramp=0.0f;
sfxr.p_freq_dramp=0.0f;
sfxr.p_duty=0.0f;
sfxr.p_duty_ramp=0.0f;

sfxr.p_vib_strength=0.0f;
sfxr.p_vib_speed=0.0f;
sfxr.p_vib_delay=0.0f;

sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=0.3f;
sfxr.p_env_decay=0.4f;
sfxr.p_env_punch=0.0f;

sfxr.filter_on=0;
sfxr.p_lpf_resonance=0.0f;
sfxr.p_lpf_freq=1.0f;
sfxr.p_lpf_ramp=0.0f;
sfxr.p_hpf_freq=0.0f;
sfxr.p_hpf_ramp=0.0f;

sfxr.p_pha_offset=0.0f;
sfxr.p_pha_ramp=0.0f;

sfxr.p_repeat_speed=0.0f;

sfxr.p_arp_speed=0.0f;
sfxr.p_arp_mod=0.0f;

sfxr.master_vol=0.05f;
sfxr.sound_vol=0.5f;

sfxr.filesample=0.0f;

sfxr.playing_sample=0;
sfxr.samples_played=0;
}


void SfxrResetSample(int restart)
{
if(!restart) {
sfxr.phase=0;
}
sfxr.fperiod=100.0/(sfxr.p_base_freq*sfxr.p_base_freq+0.001);
sfxr.period=(int)sfxr.fperiod;
sfxr.fmaxperiod=100.0/(sfxr.p_freq_limit*sfxr.p_freq_limit+0.001);
sfxr.fslide=1.0-pow((double)sfxr.p_freq_ramp, 3.0)*0.01;
sfxr.fdslide=-pow((double)sfxr.p_freq_dramp, 3.0)*0.000001;
sfxr.square_duty=0.5f-sfxr.p_duty*0.5f;
sfxr.square_slide=-sfxr.p_duty_ramp*0.00005f;
if(sfxr.p_arp_mod>=0.0f) {
sfxr.arp_mod=1.0-pow((double)sfxr.p_arp_mod, 2.0)*0.9;
}
else {
sfxr.arp_mod=1.0+pow((double)sfxr.p_arp_mod, 2.0)*10.0;
}
sfxr.arp_time=0;
sfxr.arp_limit=(int)(pow(1.0f-sfxr.p_arp_speed, 2.0f)*20000+32);
if(sfxr.p_arp_speed==1.0f) {
sfxr.arp_limit=0;
}
if(!restart)
{
// reset filter
sfxr.fltp=0.0f;
sfxr.fltdp=0.0f;
sfxr.fltw=pow(sfxr.p_lpf_freq, 3.0f)*0.1f;
sfxr.fltw_d=1.0f+sfxr.p_lpf_ramp*0.0001f;
sfxr.fltdmp=5.0f/(1.0f+pow(sfxr.p_lpf_resonance, 2.0f)*20.0f)*(0.01f+sfxr.fltw);
if(sfxr.fltdmp>0.8f) sfxr.fltdmp=0.8f;
sfxr.fltphp=0.0f;
sfxr.flthp=pow(sfxr.p_hpf_freq, 2.0f)*0.1f;
sfxr.flthp_d=1.0+sfxr.p_hpf_ramp*0.0003f;
// reset vibrato
sfxr.vib_phase=0.0f;
sfxr.p_vib_speed=pow(sfxr.p_vib_speed, 2.0f)*0.01f;
sfxr.vib_amp=sfxr.p_vib_strength*0.5f;
// reset envelope
sfxr.env_vol=0.0f;
sfxr.env_stage=0;
sfxr.env_time=0;
sfxr.env_length[0]=(int)(sfxr.p_env_attack*sfxr.p_env_attack*100000.0f);
sfxr.env_length[1]=(int)(sfxr.p_env_sustain*sfxr.p_env_sustain*100000.0f);
sfxr.env_length[2]=(int)(sfxr.p_env_decay*sfxr.p_env_decay*100000.0f);

sfxr.fphase=pow(sfxr.p_pha_offset, 2.0f)*1020.0f;
if(sfxr.p_pha_offset<0.0f) sfxr.fphase=-sfxr.fphase;
sfxr.fdphase=pow(sfxr.p_pha_ramp, 2.0f)*1.0f;
if(sfxr.p_pha_ramp<0.0f) sfxr.fdphase=-sfxr.fdphase;
sfxr.iphase=abs((int)sfxr.fphase);
sfxr.ipp=0;
int i;
for(i=0;i<1024;i++) {
sfxr.phaser_buffer[i]=0.0f;
}

for(i=0;i<32;i++) {
sfxr.noise_buffer[i]=sfxr_frnd(2.0f)-1.0f;
}

sfxr.rep_time=0;
sfxr.rep_limit=(int)(pow(1.0f-sfxr.p_repeat_speed, 2.0f)*20000+32);
if(sfxr.p_repeat_speed==0.0f) {
sfxr.rep_limit=0;
}
}
}


void SfxrSynthSample(int length, unsigned char* buffer, FILE* file)
{
int i;
for(i=0;i<length;i++)
{
if(!sfxr.playing_sample) {
break;
}

sfxr.rep_time++;
if(sfxr.rep_limit!=0 && sfxr.rep_time>=sfxr.rep_limit)
{
sfxr.rep_time=0;
SfxrResetSample(1);
}

// frequency envelopes/arpeggios
sfxr.arp_time++;
if(sfxr.arp_limit!=0 && sfxr.arp_time>=sfxr.arp_limit)
{
sfxr.arp_limit=0;
sfxr.fperiod*=sfxr.arp_mod;
}
sfxr.fslide+=sfxr.fdslide;
sfxr.fperiod*=sfxr.fslide;
if(sfxr.fperiod>sfxr.fmaxperiod)
{
sfxr.fperiod=sfxr.fmaxperiod;
if(sfxr.p_freq_limit>0.0f) {
sfxr.playing_sample=0;
}
}
float rfperiod=sfxr.fperiod;
if(sfxr.vib_amp>0.0f)
{
sfxr.vib_phase+=sfxr.p_vib_speed;
rfperiod=sfxr.fperiod*(1.0+sin(sfxr.vib_phase)*sfxr.vib_amp);
}
sfxr.period=(int)rfperiod;
if(sfxr.period<8) sfxr.period=8;
sfxr.square_duty+=sfxr.square_slide;
if(sfxr.square_duty<0.0f) sfxr.square_duty=0.0f;
if(sfxr.square_duty>0.5f) sfxr.square_duty=0.5f;
// volume envelope
sfxr.env_time++;
if(sfxr.env_time>sfxr.env_length[sfxr.env_stage])
{
sfxr.env_time=0;
sfxr.env_stage++;
if(sfxr.env_stage==3) {
sfxr.playing_sample=0;
}
}
if(sfxr.env_stage==0) {
sfxr.env_vol=(float)sfxr.env_time/sfxr.env_length[0];
}
if(sfxr.env_stage==1) {
sfxr.env_vol=1.0f+pow(1.0f-(float)sfxr.env_time/sfxr.env_length[1], 1.0f)*2.0f*sfxr.p_env_punch;
}
if(sfxr.env_stage==2) {
sfxr.env_vol=1.0f-(float)sfxr.env_time/sfxr.env_length[2];
}

// phaser step
sfxr.fphase+=sfxr.fdphase;
sfxr.iphase=abs((int)sfxr.fphase);
if(sfxr.iphase>1023) sfxr.iphase=1023;

if(sfxr.flthp_d!=0.0f)
{
sfxr.flthp*=sfxr.flthp_d;
if(sfxr.flthp<0.00001f) sfxr.flthp=0.00001f;
if(sfxr.flthp>0.1f) sfxr.flthp=0.1f;
}

float ssample=0.0f;
int si;
for(si=0;si<8;si++) // 8x supersampling
{
float sample=0.0f;
sfxr.phase++;
if(sfxr.phase>=sfxr.period)
{
//phase=0;
sfxr.phase%=sfxr.period;
if(sfxr.wave_type==3) {
for(i=0;i<32;i++) {
sfxr.noise_buffer[i]=sfxr_frnd(2.0f)-1.0f;
}
}
}
// base waveform
float fp=(float)sfxr.phase/sfxr.period;
switch(sfxr.wave_type)
{
case 0: // square
if(fp<sfxr.square_duty) {
sample=0.5f;
}
else {
sample=-0.5f;
}
break;
case 1: // sawtooth
sample=1.0f-fp*2;
break;
case 2: // sine
sample=(float)sin(fp*2*PI);
break;
case 3: // noise
sample=sfxr.noise_buffer[sfxr.phase*32/sfxr.period];
break;
}
// lp filter
float pp=sfxr.fltp;
sfxr.fltw*=sfxr.fltw_d;
if(sfxr.fltw<0.0f) sfxr.fltw=0.0f;
if(sfxr.fltw>0.1f) sfxr.fltw=0.1f;
if(sfxr.p_lpf_freq!=1.0f)
{
sfxr.fltdp+=(sample-sfxr.fltp)*sfxr.fltw;
sfxr.fltdp-=sfxr.fltdp*sfxr.fltdmp;
}
else
{
sfxr.fltp=sample;
sfxr.fltdp=0.0f;
}
sfxr.fltp+=sfxr.fltdp;
// hp filter
sfxr.fltphp+=sfxr.fltp-pp;
sfxr.fltphp-=sfxr.fltphp*sfxr.flthp;
sample=sfxr.fltphp;
// phaser
sfxr.phaser_buffer[sfxr.ipp&1023]=sample;
sample+=sfxr.phaser_buffer[(sfxr.ipp-sfxr.iphase+1024)&1023];
sfxr.ipp=(sfxr.ipp+1)&1023;
// final accumulation and envelope application
ssample+=sample*sfxr.env_vol;
}
ssample=ssample/8*sfxr.master_vol;

ssample*=2.0f*sfxr.sound_vol;

if(buffer != NULL)
{
// 44100Hz 16 bits
ssample*=4.0f; // arbitrary gain to get reasonable output volume...
if(ssample>1.0f) ssample=1.0f;
if(ssample<-1.0f) ssample=-1.0f;

sfxr.filesample+=ssample;
unsigned short isample=(unsigned short)(sfxr.filesample*32000);
unsigned char c1 = (unsigned char)((isample & 0xFF00) >> 8);
unsigned char c2 = (unsigned char)(isample & 0x00FF);
buffer[sfxr.buffer_byteswritten++] = c2;
buffer[sfxr.buffer_byteswritten++] = c1;
sfxr.filesample=0.0f;
}
if(file!=NULL)
{
ssample*=4.0f; // arbitrary gain to get reasonable output volume...
if(ssample>1.0f) ssample=1.0f;
if(ssample<-1.0f) ssample=-1.0f;
sfxr.filesample+=ssample;
short isample=(short)(sfxr.filesample*32000);
fwrite(&isample, 1, 2, file);
sfxr.filesample=0.0f;
sfxr.file_bytesswritten+=2;
}

sfxr.samples_played++;
}
}

void SfxrPlaySample(unsigned char* buffer, FILE* file) {
SfxrResetSample(0);
sfxr.samples_played=0;
sfxr.playing_sample=1;
while(sfxr.playing_sample) {
SfxrSynthSample(256, buffer, file);
}
}



int SfxrCalculateLength() {
SfxrPlaySample(NULL, NULL);
return sfxr.samples_played * 2;
}


struct SfxrSound SfxrToBuffer() {
struct SfxrSound sound;
sound.length = SfxrCalculateLength();
sound.data = (unsigned char*) malloc(sound.length);

sfxr.buffer_byteswritten=0;
sfxr.file_bytesswritten=0;
sfxr.filesample=0.0f;

SfxrPlaySample(sound.data, NULL);
return sound;
}


int SfxrToWAV(const char* filename)
{
FILE* foutput=fopen(filename, "wb");
if(!foutput) {
return 0;
}
// write wav header
unsigned int dword=0;
unsigned short word=0;
const int wav_bits=16;
const int wav_freq=44100;

fwrite("RIFF", 4, 1, foutput); // "RIFF"
dword=0;
fwrite(&dword, 1, 4, foutput); // remaining file size
fwrite("WAVE", 4, 1, foutput); // "WAVE"

fwrite("fmt ", 4, 1, foutput); // "fmt "
dword=16;
fwrite(&dword, 1, 4, foutput); // chunk size
word=1;
fwrite(&word, 1, 2, foutput); // compression code
word=1;
fwrite(&word, 1, 2, foutput); // channels
dword=wav_freq;
fwrite(&dword, 1, 4, foutput); // sample rate
dword=wav_freq*wav_bits/8;
fwrite(&dword, 1, 4, foutput); // bytes/sec
word=wav_bits/8;
fwrite(&word, 1, 2, foutput); // block align
word=wav_bits;
fwrite(&word, 1, 2, foutput); // bits per sample

fwrite("data", 4, 1, foutput); // "data"
dword=0;
int foutstream_datasize=ftell(foutput);
fwrite(&dword, 1, 4, foutput); // chunk size

// write sample data
sfxr.file_bytesswritten=0;
sfxr.filesample=0.0f;
SfxrPlaySample(NULL, foutput);

// seek back to header and write size info
fseek(foutput, 4, SEEK_SET);
dword=0;
dword=foutstream_datasize-4+sfxr.file_bytesswritten;
fwrite(&dword, 1, 4, foutput); // remaining file size
fseek(foutput, foutstream_datasize, SEEK_SET);
dword=sfxr.file_bytesswritten;
fwrite(&dword, 1, 4, foutput); // chunk size (data)
fclose(foutput);

return 1;
}


struct SfxrSound SfxrPickup(int seed) {
srand(seed);
SfxrResetParams();

sfxr.p_base_freq=0.4f+sfxr_frnd(0.5f);
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=sfxr_frnd(0.1f);
sfxr.p_env_decay=0.1f+sfxr_frnd(0.4f);
sfxr.p_env_punch=0.3f+sfxr_frnd(0.3f);
if(rnd(1))
{
sfxr.p_arp_speed=0.5f+sfxr_frnd(0.2f);
sfxr.p_arp_mod=0.2f+sfxr_frnd(0.4f);
}
return SfxrToBuffer();
}

struct SfxrSound SfxrLaser(int seed) {
srand(seed);
SfxrResetParams();

sfxr.wave_type=rnd(2);
if(sfxr.wave_type==2 && rnd(1)) {
sfxr.wave_type=rnd(1);
}
sfxr.p_base_freq=0.5f+sfxr_frnd(0.5f);
sfxr.p_freq_limit=sfxr.p_base_freq-0.2f-sfxr_frnd(0.6f);
if(sfxr.p_freq_limit<0.2f) sfxr.p_freq_limit=0.2f;
sfxr.p_freq_ramp=-0.15f-sfxr_frnd(0.2f);
if(rnd(2)==0)
{
sfxr.p_base_freq=0.3f+sfxr_frnd(0.6f);
sfxr.p_freq_limit=sfxr_frnd(0.1f);
sfxr.p_freq_ramp=-0.35f-sfxr_frnd(0.3f);
}
if(rnd(1))
{
sfxr.p_duty=sfxr_frnd(0.5f);
sfxr.p_duty_ramp=sfxr_frnd(0.2f);
}
else
{
sfxr.p_duty=0.4f+sfxr_frnd(0.5f);
sfxr.p_duty_ramp=-sfxr_frnd(0.7f);
}
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=0.1f+sfxr_frnd(0.2f);
sfxr.p_env_decay=sfxr_frnd(0.4f);
if(rnd(1)) {
sfxr.p_env_punch=sfxr_frnd(0.3f);
}
if(rnd(2)==0)
{
sfxr.p_pha_offset=sfxr_frnd(0.2f);
sfxr.p_pha_ramp=-sfxr_frnd(0.2f);
}
if(rnd(1)) {
sfxr.p_hpf_freq=sfxr_frnd(0.3f);
}
return SfxrToBuffer();
}



struct SfxrSound SfxrExplosion(int seed) {
srand(seed);
SfxrResetParams();

sfxr.wave_type=3;
if(rnd(1))
{
sfxr.p_base_freq=0.1f+sfxr_frnd(0.4f);
sfxr.p_freq_ramp=-0.1f+sfxr_frnd(0.4f);
}
else
{
sfxr.p_base_freq=0.2f+sfxr_frnd(0.7f);
sfxr.p_freq_ramp=-0.2f-sfxr_frnd(0.2f);
}
sfxr.p_base_freq*=sfxr.p_base_freq;
if(rnd(4)==0) {
sfxr.p_freq_ramp=0.0f;
}
if(rnd(2)==0) {
sfxr.p_repeat_speed=0.3f+sfxr_frnd(0.5f);
}
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=0.1f+sfxr_frnd(0.3f);
sfxr.p_env_decay=sfxr_frnd(0.5f);
if(rnd(1)==0)
{
sfxr.p_pha_offset=-0.3f+sfxr_frnd(0.9f);
sfxr.p_pha_ramp=-sfxr_frnd(0.3f);
}
sfxr.p_env_punch=0.2f+sfxr_frnd(0.6f);
if(rnd(1))
{
sfxr.p_vib_strength=sfxr_frnd(0.7f);
sfxr.p_vib_speed=sfxr_frnd(0.6f);
}
if(rnd(2)==0)
{
sfxr.p_arp_speed=0.6f+sfxr_frnd(0.3f);
sfxr.p_arp_mod=0.8f-sfxr_frnd(1.6f);
}
return SfxrToBuffer();
}


struct SfxrSound SfxrPowerup(int seed) {
srand(seed);
SfxrResetParams();

if(rnd(1)) {
sfxr.wave_type=1;
}
else {
sfxr.p_duty=sfxr_frnd(0.6f);
}
if(rnd(1))
{
sfxr.p_base_freq=0.2f+sfxr_frnd(0.3f);
sfxr.p_freq_ramp=0.1f+sfxr_frnd(0.4f);
sfxr.p_repeat_speed=0.4f+sfxr_frnd(0.4f);
}
else
{
sfxr.p_base_freq=0.2f+sfxr_frnd(0.3f);
sfxr.p_freq_ramp=0.05f+sfxr_frnd(0.2f);
if(rnd(1))
{
sfxr.p_vib_strength=sfxr_frnd(0.7f);
sfxr.p_vib_speed=sfxr_frnd(0.6f);
}
}
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=sfxr_frnd(0.4f);
sfxr.p_env_decay=0.1f+sfxr_frnd(0.4f);
return SfxrToBuffer();
}


struct SfxrSound SfxrHurt(int seed) {
srand(seed);
SfxrResetParams();

sfxr.wave_type=rnd(2);
if(sfxr.wave_type==2) {
sfxr.wave_type=3;
}
if(sfxr.wave_type==0) {
sfxr.p_duty=sfxr_frnd(0.6f);
}
sfxr.p_base_freq=0.2f+sfxr_frnd(0.6f);
sfxr.p_freq_ramp=-0.3f-sfxr_frnd(0.4f);
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=sfxr_frnd(0.1f);
sfxr.p_env_decay=0.1f+sfxr_frnd(0.2f);
if(rnd(1)) {
sfxr.p_hpf_freq=sfxr_frnd(0.3f);
}
return SfxrToBuffer();
}


struct SfxrSound SfxrJump(int seed) {
srand(seed);
SfxrResetParams();

sfxr.wave_type=0;
sfxr.p_duty=sfxr_frnd(0.6f);
sfxr.p_base_freq=0.3f+sfxr_frnd(0.3f);
sfxr.p_freq_ramp=0.1f+sfxr_frnd(0.2f);
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=0.1f+sfxr_frnd(0.3f);
sfxr.p_env_decay=0.1f+sfxr_frnd(0.2f);
if(rnd(1)) {
sfxr.p_hpf_freq=sfxr_frnd(0.3f);
}
if(rnd(1)) {
sfxr.p_lpf_freq=1.0f-sfxr_frnd(0.6f);
}
return SfxrToBuffer();
}


struct SfxrSound SfxrBlip(int seed) {
srand(seed);
SfxrResetParams();

sfxr.wave_type=rnd(1);
if(sfxr.wave_type==0) {
sfxr.p_duty=sfxr_frnd(0.6f);
}
sfxr.p_base_freq=0.2f+sfxr_frnd(0.4f);
sfxr.p_env_attack=0.0f;
sfxr.p_env_sustain=0.1f+sfxr_frnd(0.1f);
sfxr.p_env_decay=sfxr_frnd(0.2f);
sfxr.p_hpf_freq=0.1f;
return SfxrToBuffer();
}

Loading…
Cancel
Save