Merge branch 'master' into 'more-flip-fixes'

# Conflicts:
#   src/g_demo.cpp
This commit is contained in:
AJ Martinez 2025-09-17 02:57:14 +00:00
commit 237b72ea3e
69 changed files with 7488 additions and 66 deletions

View file

@ -0,0 +1,19 @@
# What version of Ring Racers are you playing?
(Replace this text with the version number. You can see this on the title screen at the bottom-left corner.)
# What is the fastest way to trigger the bug?
(Bugs that can't be reproduced are extremely hard to fix. If you can't make it happen on demand, try and describe the circumstances where it triggers.)
# What is the bugged behavior?
(Describe what happens when you encounter the bug.)
# What do you expect to happen instead?
(Describe what should be happening instead of the bugged behavior.)
# Logs, videos, or screenshots that showcase the issue
(For crash bugs, look for an .RPT file, or your `latest-log.txt`. You can drag it directly into this window.)

View file

@ -20,6 +20,14 @@
- libvorbis + libvorbisenc
Copyright (c) 2002-2020 Xiph.org Foundation
https://github.com/xiph/vorbis
- ReNameNoise + rnnoise
Copyright (c) 2024 The Mumble Developers
Copyright (c) 2017 Mozilla
Copyright (c) 2007-2017 Jean-Marc Valin
Copyright (c) 2005-2017 Xiph.Org Foundation
Copyright (c) 2003-2004 Mark Borgerding
https://github.com/mumble-voip/ReNameNoise
--------------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without

View file

@ -279,6 +279,7 @@ target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB)
target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG)
target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl)
target_link_libraries(SRB2SDL2 PRIVATE Opus::opus)
target_link_libraries(SRB2SDL2 PRIVATE ReNameNoise::renamenoise)
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
target_link_libraries(SRB2SDL2 PRIVATE -lexecinfo)
target_link_libraries(SRB2SDL2 PRIVATE -lpthread)

View file

@ -7,6 +7,7 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -89,8 +90,12 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
int luaO_str2d (const char *s, lua_Number *result) {
char *endptr;
double r = lua_str2number(s, &endptr);
*result = (lua_Number)r;
long r = lua_str2number(s, &endptr);
if (r > INT32_MAX)
r = INT32_MAX;
else if (r < INT32_MIN)
r = INT32_MIN;
*result = (lua_Number)r;
if (endptr == s) return 0; /* conversion failed */
if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */
*result = cast_num(strtoul(s, &endptr, 16));

View file

@ -103,7 +103,7 @@ CV_PossibleValue_t gpdifficulty_cons_t[] = {
{0, NULL}
};
CV_PossibleValue_t descriptiveinput_cons_t[] = {
{0, "\"Emulator\""},
{0, "\"Emulator\""},
{1, "Modern"},
{2, "Modern Flip"},
{3, "6Bt. (Auto)"},
@ -112,6 +112,7 @@ CV_PossibleValue_t descriptiveinput_cons_t[] = {
{6, "6Bt. (C)"},
{7, "6Bt. (D)"},
{8, "6Bt. (E)"},
{9, "6Bt. (F)"},
{0, NULL}
};

View file

@ -14,6 +14,7 @@
#include "../cxxutil.hpp"
#include "../z_zone.h"
#include "../lua_script.h"
using namespace srb2;
@ -117,6 +118,9 @@ void* PoolAllocator::allocate()
void PoolAllocator::deallocate(void* p)
{
// Required in case this block is reused
LUA_InvalidateUserdata(p);
FreeBlock* block = reinterpret_cast<FreeBlock*>(p);
block->next = head_;
head_ = block;
@ -127,6 +131,12 @@ void PoolAllocator::release()
ChunkFooter* next = nullptr;
for (ChunkFooter* i = first_chunk_; i != nullptr; i = next)
{
uint8_t *chunk = (uint8_t*)i->start;
for (size_t j = 0; j < blocks_; j++)
{
// Invalidate all blocks that possibly weren't passed to deallocate
LUA_InvalidateUserdata(chunk + (j * block_size_));
}
next = i->next;
Z_Free(i->start);
}

View file

@ -622,7 +622,7 @@ void Lagless_OnChange(void);
consvar_t cv_lagless = NetVar("lagless", "Off").on_off().onchange(Lagless_OnChange);
// max file size to send to a player (in kilobytes)
consvar_t cv_maxsend = NetVar("maxsend", "51200").min_max(0, 51200);
consvar_t cv_maxsend = NetVar("maxsend", "204800").min_max(-1, 999999999);
consvar_t cv_noticedownload = NetVar("noticedownload", "Off").on_off();
consvar_t cv_pingtimeout = NetVar("maxdelaytimeout", "10").min_max(8, 120);
@ -1410,6 +1410,10 @@ consvar_t cv_voice_loopback = Player("voice_loopback", "Off")
.dont_save()
.description("When on, plays the local player's voice");
consvar_t cv_voice_denoise = Player("voice_denoise", "On")
.on_off()
.description("When on, denoises the voice microphone signal");
consvar_t cv_voice_proximity = NetVar("voice_proximity", "On")
.on_off()
.description("Whether proximity effects for voice chat are enabled on the server.");

View file

@ -17,6 +17,7 @@
#endif
#include <opus.h>
#include <renamenoise.h>
#include "i_time.h"
#include "i_net.h"
@ -203,6 +204,7 @@ static UINT64 g_player_opus_lastframe[MAXPLAYERS];
static UINT32 g_player_voice_frames_this_tic[MAXPLAYERS];
#define MAX_PLAYER_VOICE_FRAMES_PER_TIC 3
static OpusEncoder *g_local_opus_encoder;
static ReNameNoiseDenoiseState *g_local_renamenoise_state;
static UINT64 g_local_opus_frame = 0;
#define SRB2_VOICE_OPUS_FRAME_SIZE 960
static float g_local_voice_buffer[SRB2_VOICE_OPUS_FRAME_SIZE];
@ -1585,6 +1587,7 @@ static void SendAskInfo(INT32 node)
serverelem_t serverlist[MAXSERVERLIST];
UINT32 serverlistcount = 0;
UINT32 serverlistultimatecount = 0;
boolean serverlistmode = false;
static boolean resendserverlistnode[MAXNETNODES];
static tic_t serverlistepoch;
@ -1655,7 +1658,7 @@ static boolean SL_InsertServer(serverinfo_pak* info, SINT8 node)
if (i == UINT32_MAX)
{
// Still not added to list... check for modifiedgame rejections
if (serverlistultimatecount)
if (serverlistmode)
{
// We're on the server browser page. We can reject based on our room.
if (
@ -2573,6 +2576,25 @@ static void Command_connect(void)
static void ResetNode(INT32 node);
static void RecreatePlayerOpusDecoder(INT32 playernum)
{
// Destroy and recreate the opus decoder for this playernum
OpusDecoder *opusdecoder = g_player_opus_decoders[playernum];
if (opusdecoder)
{
opus_decoder_destroy(opusdecoder);
opusdecoder = NULL;
}
int error;
opusdecoder = opus_decoder_create(48000, 1, &error);
if (error != OPUS_OK)
{
CONS_Alert(CONS_WARNING, "Failed to create Opus decoder for player %d: opus error %d\n", playernum, error);
opusdecoder = NULL;
}
g_player_opus_decoders[playernum] = opusdecoder;
}
//
// CL_ClearPlayer
//
@ -2648,23 +2670,7 @@ void CL_ClearPlayer(INT32 playernum)
// Clear voice chat data
S_ResetVoiceQueue(playernum);
{
// Destroy and recreate the opus decoder for this playernum
OpusDecoder *opusdecoder = g_player_opus_decoders[playernum];
if (opusdecoder)
{
opus_decoder_destroy(opusdecoder);
opusdecoder = NULL;
}
int error;
opusdecoder = opus_decoder_create(48000, 1, &error);
if (error != OPUS_OK)
{
CONS_Alert(CONS_WARNING, "Failed to create Opus decoder for player %d: opus error %d\n", playernum, error);
opusdecoder = NULL;
}
g_player_opus_decoders[playernum] = opusdecoder;
}
RecreatePlayerOpusDecoder(playernum);
}
//
@ -3709,6 +3715,17 @@ void D_QuitNetGame(void)
#endif
}
static void InitializeLocalVoiceDenoiser(void)
{
if (g_local_renamenoise_state != NULL)
{
renamenoise_destroy(g_local_renamenoise_state);
g_local_renamenoise_state = NULL;
}
g_local_renamenoise_state = renamenoise_create(NULL);
}
static void InitializeLocalVoiceEncoder(void)
{
// Reset voice opus encoder for local "player 1"
@ -3815,6 +3832,7 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum)
}
DEBFILE("spawning me\n");
InitializeLocalVoiceDenoiser();
InitializeLocalVoiceEncoder();
}
@ -7592,6 +7610,28 @@ void NetVoiceUpdate(void)
g_local_voice_buffer[i] *= ampfactor;
}
if (cv_voice_denoise.value)
{
if (g_local_renamenoise_state == NULL)
{
InitializeLocalVoiceDenoiser();
}
int rnnoise_size = renamenoise_get_frame_size();
float *subframe_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
float *denoise_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
// rnnoise frames are smaller than opus, but we should not expect the opus frame to be an exact multiple of rnnoise
for (int denoise_position = 0; denoise_position < SRB2_VOICE_OPUS_FRAME_SIZE; denoise_position += rnnoise_size)
{
memset(subframe_buffer, 0, rnnoise_size * sizeof(float));
memcpy(subframe_buffer, g_local_voice_buffer + denoise_position, min(rnnoise_size * sizeof(float), (SRB2_VOICE_OPUS_FRAME_SIZE - denoise_position) * sizeof(float)));
renamenoise_process_frame(g_local_renamenoise_state, denoise_buffer, subframe_buffer);
memcpy(g_local_voice_buffer + denoise_position, denoise_buffer, min(rnnoise_size * sizeof(float), (SRB2_VOICE_OPUS_FRAME_SIZE - denoise_position) * sizeof(float)));
}
Z_Free(denoise_buffer);
Z_Free(subframe_buffer);
}
float softmem = 0.f;
opus_pcm_soft_clip(g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, 1, &softmem);
@ -7670,6 +7710,10 @@ void NetVoiceUpdate(void)
if (cv_voice_loopback.value)
{
if (g_player_opus_decoders[consoleplayer] == NULL && !netgame)
{
RecreatePlayerOpusDecoder(consoleplayer);
}
result = opus_decode_float(g_player_opus_decoders[consoleplayer], encoded, result, g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
S_QueueVoiceFrameFromPlayer(consoleplayer, g_local_voice_buffer, result * sizeof(float), false);
}

View file

@ -508,6 +508,7 @@ struct serverelem_t
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount, serverlistultimatecount;
extern boolean serverlistmode;
extern INT32 mapchangepending;
// Points inside doomcom

View file

@ -1209,6 +1209,7 @@ void D_ClearState(void)
SV_StopServer();
SV_ResetServer();
serverlistultimatecount = 0;
serverlistmode = false;
for (i = 0; i < MAXPLAYERS; i++)
CL_ClearPlayer(i);

View file

@ -204,7 +204,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
// Store in the upper four bits
if (!cv_downloading.value)
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
else if (cv_maxsend.value == -1 || wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024)
filestatus += (1 << 4); // Will send if requested
// else
// filestatus += (0 << 4); -- Won't send, too big
@ -964,7 +964,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid
}
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
if (cv_maxsend.value != -1 && wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{
// Too big
// Don't inform client (client sucks, man)

View file

@ -754,6 +754,7 @@ struct player_t
UINT16 bigwaypointgap; // timer counts down if finish line distance gap is too big to update waypoint
UINT8 startboost; // (0 to 125) - Boost you get from start of race
UINT8 dropdashboost; // Boost you get when holding A while respawning
UINT8 aciddropdashboost; // acid dropdash
UINT16 flashing;
UINT16 spinouttimer; // Spin-out from a banana peel or oil slick (was "pw_bananacam")
@ -1131,6 +1132,7 @@ struct player_t
UINT32 lastringboost; // What was our accumulated boost when locking the award?
UINT8 amps;
UINT8 recentamps;
UINT8 amppickup;
UINT8 ampspending;

View file

@ -1506,6 +1506,13 @@ void readlevelheader(MYFILE *f, char * name)
mapheaderinfo[num]->cameraHeight = camheight;;
}
else if (fastcmp(word, "NOCOMMS") || fastcmp(word, "NOCOMM"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num]->levelflags |= LF_NOCOMMS;
else
mapheaderinfo[num]->levelflags &= ~LF_NOCOMMS;
}
else
deh_warning("Level header %d: unknown word '%s'", num, word);
}

View file

@ -4747,6 +4747,7 @@ struct int_const_s const INT_CONST[] = {
{"LF_NOZONE",LF_NOZONE},
{"LF_SECTIONRACE",LF_SECTIONRACE},
{"LF_SUBTRACTNUM",LF_SUBTRACTNUM},
{"LF_NOCOMMS",LF_NOCOMMS},
// And map flags
{"LF2_HIDEINMENU",LF2_HIDEINMENU},
{"LF2_NOTIMEATTACK",LF2_NOTIMEATTACK},

View file

@ -605,6 +605,7 @@ struct mapheader_t
#define LF_NOZONE (1<<1) ///< Don't include "ZONE" on level title
#define LF_SECTIONRACE (1<<2) ///< Section race level
#define LF_SUBTRACTNUM (1<<3) ///< Use subtractive position number (for bright levels)
#define LF_NOCOMMS (1<<4) ///< Disable dialogue "communications in progress" graphic
#define LF2_HIDEINMENU (1<<0) ///< Hide in the multiplayer menu
#define LF2_NOTIMEATTACK (1<<1) ///< Hide this map in Time Attack modes

View file

@ -2241,7 +2241,7 @@ void G_BeginRecording(void)
// Save follower's colour
for (j = (numskincolors+2)-1; j > 0; j--)
{
if (Followercolor_cons_t[j].value == players[i].followercolor)
if (Followercolor_cons_t[j].value == player->followercolor)
break;
}
demobuf.p += copy_fixed_buf(demobuf.p, Followercolor_cons_t[j].strvalue, g_buffer_sizes.color_name); // Not KartColor_Names because followercolor has extra values such as "Match"

View file

@ -3415,6 +3415,11 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
return; // cap
blend = HWR_SurfaceBlend(blendmode, trans, &Surf);
// if sprite has PF_ALWAYSONTOP, draw on top of everything.
if (cv_debugrender_spriteclip.value || spr->mobj->renderflags & RF_ALWAYSONTOP)
blend |= PF_NoDepthTest;
if (!trans && !blendmode)
{
// BP: i agree that is little better in environement but it don't
@ -3896,6 +3901,11 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
return; // cap
blend = HWR_SurfaceBlend(blendmode, trans, &Surf);
// if sprite has PF_ALWAYSONTOP, draw on top of everything.
if (cv_debugrender_spriteclip.value || spr->mobj->renderflags & RF_ALWAYSONTOP)
blend |= PF_NoDepthTest;
if (!trans && !blendmode)
{
// BP: i agree that is little better in environement but it don't
@ -3921,7 +3931,10 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
if (HWR_UseShader())
{
shader = (R_ThingIsPaperSprite(spr->mobj) || R_ThingIsFloorSprite(spr->mobj)) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK;;
shader = (R_ThingIsPaperSprite(spr->mobj)
|| R_ThingIsFloorSprite(spr->mobj)
|| (spr->mobj->terrain && spr->mobj->terrain->floorClip)
) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK;
blend |= PF_ColorMapped;
}
@ -5007,6 +5020,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
x1 = tr_x + x1 * rightcos;
x2 = tr_x - x2 * rightcos;
if (thing->terrain && thing->terrain->floorClip)
spr_topoffset -= thing->terrain->floorClip;
if (vflip)
{
gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);

View file

@ -1723,6 +1723,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
HWD.pfnSetShader(SHADER_MODEL); // model shader
{
float this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
fixed_t floorClip = spr->mobj->terrain ? spr->mobj->terrain->floorClip : 0;
float finalfloorClip = FIXED_TO_FLOAT(FixedMul(floorClip, mapobjectscale)*P_MobjFlip(spr->mobj));
float xs = this_scale * FIXED_TO_FLOAT(spr->mobj->spritexscale);
float ys = this_scale * FIXED_TO_FLOAT(spr->mobj->spriteyscale);
@ -1733,7 +1735,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
// offset perpendicular to the camera angle
p.x -= ox * gl_viewsin;
p.y += ox * gl_viewcos;
p.z += oy;
p.z += oy - finalfloorClip;
if (R_ThingIsUsingBakedOffsets(spr->mobj))
{

View file

@ -47,7 +47,7 @@
--------------------------------------------------*/
static inline boolean K_ItemButtonWasDown(const player_t *player)
{
return (player->oldcmd.buttons & BT_ATTACK);
return !!(player->oldcmd.buttons & BT_ATTACK);
}
/*--------------------------------------------------
@ -950,7 +950,7 @@ static void K_BotItemOrbinaut(const player_t *player, ticcmd_t *cmd)
cmd->buttons |= BT_LOOKBACK;
}
if (player->botvars.itemconfirm > 25*TICRATE)
if (player->botvars.itemconfirm > 10*TICRATE)
{
K_BotGenericPressItem(player, cmd, throwdir);
}
@ -1178,7 +1178,7 @@ static void K_BotItemJawz(const player_t *player, ticcmd_t *cmd)
cmd->buttons |= BT_LOOKBACK;
}
if (player->botvars.itemconfirm > 25*TICRATE)
if (player->botvars.itemconfirm > 10*TICRATE)
{
K_BotGenericPressItem(player, cmd, throwdir);
}
@ -1234,6 +1234,9 @@ static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd)
boolean hold = false;
if (player->botvars.itemconfirm > 10*TICRATE)
hold = true;
if (player->bubbleblowup <= 0)
{
UINT8 i;

View file

@ -316,7 +316,7 @@ void K_InitGrandPrixBots(void)
// Intentionally referenced before (currently dummied out) unlock check. Such a tease!
if (rivalnum != -1 && grabskins[(UINT16)rivalnum] != MAXSKINS)
{
botskinlist[botskinlistpos++] = (UINT8)rivalnum;
botskinlist[botskinlistpos++] = (UINT16)rivalnum;
grabskins[(UINT16)rivalnum] = MAXSKINS;
}
}

View file

@ -4320,7 +4320,7 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
if (stplyr->hudrings <= 0 && stplyr->ringvisualwarning > 1)
{
colorring = true;
if ((leveltime/2 & 1))
if ((leveltime/2 & 1) || (cv_reducevfx.value))
{
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
}
@ -4329,7 +4329,7 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_WHITE, GTC_CACHE);
}
}
else if (stplyr->hudrings <= 0 && (leveltime/5 & 1)) // In debt
else if (stplyr->hudrings <= 0 && ((leveltime/5 & 1) || (cv_reducevfx.value))) // In debt
{
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
colorring = true;
@ -7466,6 +7466,7 @@ static void K_DrawBotDebugger(void)
V_DrawSmallString(8, 76, 0, va("Prediction error: %.2fdeg", FIXED_TO_FLOAT(FixedDiv(bot->botvars.predictionError, ANG1))));
V_DrawSmallString(8, 80, 0, va("Recent deflection: %.2fdeg", FIXED_TO_FLOAT(FixedDiv(bot->botvars.recentDeflection, ANG1))));
V_DrawSmallString(8, 84, 0, va("Bumpslow: %d", bot->botvars.bumpslow));
}
static void K_DrawGPRankDebugger(void)
@ -7803,7 +7804,7 @@ void K_drawKartHUD(void)
// Tacitcal Normie Countermeasure
INT32 dfade = K_GetDialogueFade();
if (dfade)
if (dfade && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOCOMMS))
{
V_DrawFadeScreen(31, dfade); // Fade out

View file

@ -292,6 +292,22 @@ private:
};
}
if (cv_reducevfx.value)
{
return {
{ // Near
{8, 2, {kp_capsuletarget_near[0]}}, // 1P
{{8, 2, {kp_capsuletarget_near[1]}}}, // 4P
},
{{ // Far
{2, 16, foreground ?
layers {kp_capsuletarget_far[0], kp_capsuletarget_far_text} :
layers {kp_capsuletarget_far[0]}}, // 1P
{{2, 16, {kp_capsuletarget_far[1]}}}, // 4P
}},
};
}
return {
{ // Near
{8, 2, {kp_capsuletarget_near[0]}}, // 1P
@ -681,13 +697,19 @@ void K_DrawTargetTracking(const TargetTracking& target)
if (target.mobj->type == MT_BATTLECAPSULE
|| target.mobj->type == MT_CDUFO)
{
targetPatch = kp_capsuletarget_icon[timer & 1];
if (cv_reducevfx.value)
targetPatch = kp_capsuletarget_icon[(timer/6) & 1];
else
targetPatch = kp_capsuletarget_icon[timer & 1];
}
if (abs(borderDir.x) > abs(borderDir.y))
{
// Horizontal arrow
arrowPatch = kp_capsuletarget_arrow[1][timer & 1];
if (cv_reducevfx.value)
arrowPatch = kp_capsuletarget_arrow[1][(timer/6) & 1];
else
arrowPatch = kp_capsuletarget_arrow[1][timer & 1];
arrowDir.y = 0;
if (borderDir.x < 0)
@ -704,7 +726,10 @@ void K_DrawTargetTracking(const TargetTracking& target)
else
{
// Vertical arrow
arrowPatch = kp_capsuletarget_arrow[0][timer & 1];
if (cv_reducevfx.value)
arrowPatch = kp_capsuletarget_arrow[0][(timer/6) & 1];
else
arrowPatch = kp_capsuletarget_arrow[0][timer & 1];
arrowDir.x = 0;
if (borderDir.y < 0)

View file

@ -1937,7 +1937,7 @@ void K_SpawnDashDustRelease(player_t *player)
if (!P_IsObjectOnGround(player->mo))
return;
if (!player->speed && !player->startboost && !player->spindash && !player->dropdashboost)
if (!player->speed && !player->startboost && !player->spindash && !player->dropdashboost && !player->aciddropdashboost)
return;
travelangle = player->mo->angle;
@ -3802,6 +3802,11 @@ static void K_GetKartBoostPower(player_t *player)
ADDBOOST(FRACUNIT/3, 4*FRACUNIT, HANDLESCALING); // + 33% top speed, + 400% acceleration, +50% handling
}
if (player->aciddropdashboost) // Great value Drop dash
{
ADDBOOST(FRACUNIT/3, 4*FRACUNIT, HANDLESCALING/3); // + 33% top speed, + 400% acceleration, +33% handling, No sliptides here
}
if (player->driftboost) // Drift Boost
{
// Rebuff Eggman's stat block corner
@ -4452,6 +4457,22 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact)
// FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS);
scaledamps = FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS;
//CONS_Printf("SA=%d ", scaledamps);
// Arbitrary tuning constants.
// Reduce amp payouts by 1/40th for each 2 amps obtained recently
UINT8 num = 40;
UINT8 div = 40;
UINT8 reduction = min(30, player->recentamps);
num -= reduction;
//CONS_Printf("N=%d D=%d RA=%d ", num, div, player->recentamps);
scaledamps = num * scaledamps / div;
//CONS_Printf("SA2=%d\n", scaledamps);
/*
if (player->position <= 1)
scaledamps /= 2;
@ -4468,6 +4489,7 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact)
pickup->color = player->skincolor;
P_SetTarget(&pickup->target, player->mo);
player->ampspending++;
player->recentamps++;
}
}
@ -10012,6 +10034,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (onground && player->transfer)
{
if (G_CompatLevel(0x0010))
{
// Ghosts prior to 2.4 RC2 don't get this
}
else
{
if (player->fastfall) // If you elected to acid drop, you get a small dropdash boost on landing
{
S_StartSound(player->mo, sfx_s23c);
player->aciddropdashboost = max(player->aciddropdashboost, 35);
K_SpawnDashDustRelease(player);
}
}
player->fastfall = 0;
player->transfer = 0;
player->pflags2 &= ~PF2_SUPERTRANSFERVFX;
@ -10022,6 +10058,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
K_DropItems(player);
}
if (K_InRaceDuel() && D_NumPlayersInRace() < 2)
P_DoPlayerExit(player, 0);
if (G_TimeAttackStart() && !attacktimingstarted && player->speed && leveltime > introtime)
{
attacktimingstarted = leveltime;
@ -10468,8 +10507,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->trickboost)
player->trickboost--;
if (K_PlayerUsesBotMovement(players) && player->botvars.bumpslow && player->incontrol)
/*
if (K_PlayerUsesBotMovement(player) && player->botvars.bumpslow && player->incontrol)
player->botvars.bumpslow--;
*/
// WHOOPS! 2.4 bots were tuned around a bugged version of bumpslow that NEVER decayed
// if the player in slot 0 was a human. People seem to like this tuning, but the dampened
// rubberbanding only started applying after a bot wallbonked or got hit, which is
// probably why people report weird runaways.
//
// I'd like to retune this later, but for now, just set bumpslow on every bot, as if they all
// contact a wall instantly—consistently giving them the softer rubberband advancement.
// What the fuck making games is hard.
if (K_PlayerUsesBotMovement(player))
player->botvars.bumpslow = TICRATE*2;
if (player->flamedash)
{
@ -10532,6 +10585,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->dropdashboost)
player->dropdashboost--;
if (player->aciddropdashboost)
player->aciddropdashboost--;
if (player->wavedashboost > 0 && onground == true)
{
player->wavedashboost--;
@ -10614,6 +10670,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
}
if (player->recentamps && (leveltime%TICRATE == 0))
player->recentamps--;
if (player->invincibilitytimer && (player->ignoreAirtimeLeniency > 0 || onground == true || K_PowerUpRemaining(player, POWERUP_SMONITOR)))
{
player->invincibilitytimer--;
@ -12759,7 +12818,7 @@ static void K_KartDrift(player_t *player, boolean onground)
// Airtime means we're not gaining speed. Get grounded!
if (!onground)
player->mo->momz -= player->speed/2;
player->mo->momz -= (player->mo->eflags & MFE_VERTICALFLIP ? -1 : 1) * player->speed/2;
if (player->driftcharge < 0)
{
@ -13977,6 +14036,22 @@ static void K_KartSpindash(player_t *player)
player->transfer = 0;
}
}
else if (!G_CompatLevel(0x0010))
{
boolean ebrakelasttic = ((player->oldcmd.buttons & BT_EBRAKEMASK) == BT_EBRAKEMASK);
if (player->pflags2 & PF2_STRICTFASTFALL)
ebrakelasttic = (player->oldcmd.buttons & BT_SPINDASH);
boolean ebrakenow = K_PressingEBrake(player);
if (player->pflags2 & PF2_STRICTFASTFALL && !(player->cmd.buttons & BT_SPINDASH))
ebrakenow = false;
if (!ebrakelasttic && ebrakenow && player->fastfall && player->transfer)
{
player->transfer = 0;
S_StartSound(player->mo, sfx_s3k7d);
}
}
// Update fastfall.
player->fastfall = player->mo->momz;

View file

@ -5673,6 +5673,9 @@ void M_DrawProfileControls(void)
case 8:
help = va("6Bt. (E): Saturn buttons, Hori/M30X layout. (LB/LT = LS/RS)");
break;
case 9:
help = va("6Bt. (F): Saturn buttons, Mayflash layout. (C/Z = RS/LS)");
break;
}
V_DrawThinString(12, ypos, V_YELLOWMAP, help);

View file

@ -176,7 +176,7 @@ void M_ChangeCvarDirect(INT32 choice, consvar_t *cv)
if (cv == &cv_nettimeout || cv == &cv_jointimeout)
choice *= (TICRATE/7);
else if (cv == &cv_maxsend)
choice *= 512;
choice *= 1024;
CV_AddValue(cv, choice);
}
@ -548,9 +548,6 @@ void M_PlayMenuJam(void)
return;
}
if (soundtest.playing)
return;
const boolean trulystarted = M_GameTrulyStarted();
const boolean profilemode = (
optionsmenu.profilemenu

View file

@ -350,9 +350,6 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result)
case KITEM_INVINCIBILITY:
case KITEM_GROW:
case KITEM_SHRINK:
case KITEM_LIGHTNINGSHIELD:
case KITEM_BUBBLESHIELD:
case KITEM_FLAMESHIELD:
{
// Items that drastically improve your own defense and/or speed.
return BOT_ITEM_PR_POWER;
@ -389,6 +386,9 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result)
case KITEM_JAWZ:
case KITEM_BANANA:
case KITEM_MINE:
case KITEM_LIGHTNINGSHIELD:
case KITEM_BUBBLESHIELD:
case KITEM_FLAMESHIELD:
{
// Used in all other instances (close to other players, no priority override)
// Typically attack items that give you protection.

View file

@ -295,6 +295,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->lastringboost);
else if (fastcmp(field,"amps"))
lua_pushinteger(L, plr->amps);
else if (fastcmp(field,"recentamps"))
lua_pushinteger(L, plr->recentamps);
else if (fastcmp(field,"amppickup"))
lua_pushinteger(L, plr->amppickup);
else if (fastcmp(field,"ampspending"))
@ -319,6 +321,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->startboost);
else if (fastcmp(field,"dropdashboost"))
lua_pushinteger(L, plr->dropdashboost);
else if (fastcmp(field,"aciddropdashboost"))
lua_pushinteger(L, plr->aciddropdashboost);
else if (fastcmp(field,"aizdriftstrat"))
lua_pushinteger(L, plr->aizdriftstrat);
else if (fastcmp(field,"aizdriftextend"))
@ -958,6 +962,8 @@ static int player_set(lua_State *L)
plr->lastringboost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"amps"))
plr->amps = luaL_checkinteger(L, 3);
else if (fastcmp(field,"recentamps"))
plr->recentamps = luaL_checkinteger(L, 3);
else if (fastcmp(field,"amppickup"))
plr->amppickup = luaL_checkinteger(L, 3);
else if (fastcmp(field,"ampspending"))
@ -982,6 +988,8 @@ static int player_set(lua_State *L)
plr->startboost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"dropdashboost"))
plr->dropdashboost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"aciddropdashboost"))
plr->aciddropdashboost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"aizdriftstrat"))
plr->aizdriftstrat = luaL_checkinteger(L, 3);
else if (fastcmp(field,"aizdrifttilt"))

View file

@ -533,7 +533,7 @@ static void M_ChallengesTutorial(UINT8 option)
{
M_StartMessage("Big Challenges & Chao Keys",
M_GetText(
"Watch out! You need 10 Chao Keys.\n"
"Watch out! You need 10 Chao Keys\n"
"to break open Big Challenge tiles.\n"
"\n"
"You'll also need to unlock\n"

View file

@ -91,6 +91,8 @@ void M_ResetOptions(void)
// For profiles:
memset(setup_player, 0, sizeof(setup_player));
optionsmenu.profile = NULL;
optionsmenu.profilemenu = false;
optionsmenu.resetprofilemenu = false;
}
void M_InitOptions(INT32 choice)

View file

@ -53,8 +53,7 @@ void M_FirstPickProfile(INT32 c)
{
if (c == MA_YES)
{
M_ResetOptions(); // Reset all options variables otherwise things are gonna go reaaal bad lol.
optionsmenu.profile = NULL; // Make sure to get rid of that, too.
M_ResetOptions(); // Reset all options variables otherwise things are gonna go reaaal bad lol.
PR_ApplyProfile(optionsmenu.profilen, 0);
@ -162,7 +161,7 @@ void M_HandleProfileSelect(INT32 ch)
if (menutransition.tics == 0 && optionsmenu.resetprofile)
{
optionsmenu.profile = NULL; // Make sure to reset that when transitions are done.'
optionsmenu.profile = NULL; // Make sure to reset that when transitions are done.
optionsmenu.resetprofile = false;
}

View file

@ -135,8 +135,7 @@ static void M_ProfileEditExit(void)
}
else
{
M_ResetOptions(); // Reset all options variables otherwise things are gonna go reaaal bad lol.
optionsmenu.profile = NULL; // Make sure to get rid of that, too.
M_ResetOptions(); // Reset all options variables otherwise things are gonna go reaaal bad lol.
}
PR_SaveProfiles(); // save profiles after we do that.

View file

@ -28,6 +28,9 @@ menuitem_t OPTIONS_Voice[] =
{IT_STRING | IT_CVAR, "Input Amplifier", "Amplify your voice, in decibels. Negative values are quieter.",
NULL, {.cvar = &cv_voice_inputamp}, 0, 0},
{IT_STRING | IT_CVAR, "Input Noise Suppression", "Suppress background noise from your voice.",
NULL, {.cvar = &cv_voice_denoise}, 0, 0},
{IT_STRING | IT_CVAR, "Input Sensitivity", "Voice higher than this threshold will transmit, in decibels.",
NULL, {.cvar = &cv_voice_activationthreshold}, 0, 0},

View file

@ -27,6 +27,7 @@ void M_ServerListFillDebug(void);
static boolean M_ServerBrowserQuit(void)
{
serverlistultimatecount = 0;
serverlistmode = false;
return true;
}
@ -240,6 +241,8 @@ void M_ServersMenu(INT32 choice)
// modified game check: no longer handled
// we don't request a restart unless the filelist differs
serverlistmode = true;
CL_UpdateServerList();
mpmenu.ticker = 0;

View file

@ -660,9 +660,12 @@ void M_LevelSelectInit(INT32 choice)
levellist.levelsearch.timeattack = false;
levellist.canqueue = true;
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto Gear" : cv_dummykartspeed.string);
if (gamestate == GS_MENU)
{
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto Gear" : cv_dummykartspeed.string);
}
break;
case 1:

View file

@ -68,7 +68,7 @@ struct Particle : Mobj
skins[pskinn]->sprites[states[spr2state].frame].numframes > 0)
{
x->skin = (void*)(&skins[pskinn]);
x->skin = (void*)(skins[pskinn]);
x->state(spr2state);
//frame will be set by state()
}

View file

@ -3510,9 +3510,20 @@ void A_AttractChase(mobj_t *actor)
if (actor->extravalue1 && actor->type != MT_EMERALD) // SRB2Kart
{
if (!actor->target || P_MobjWasRemoved(actor->target) || !actor->target->player
|| actor->target->player->baildrop || actor->target->player->bailcharge || actor->target->player->defenseLockout > PUNISHWINDOW)
// Screwed this up for staffghosts, so have a mess.
// 1. Insta-Whip's extended punish window used to delete flingrings off you while they were attracting
// 2. ALL conditions that deleted flingrings off you didn't decrement pickuprings, desyncing your ring count
boolean stale = (!actor->target || P_MobjWasRemoved(actor->target) || !actor->target->player);
boolean blocked = (actor->target->player->baildrop || actor->target->player->bailcharge);
if (G_CompatLevel(0x0010))
blocked |= (actor->target->player->defenseLockout > PUNISHWINDOW);
if (stale || blocked)
{
if (!G_CompatLevel(0x0010) && !stale)
actor->target->player->pickuprings--;
P_RemoveMobj(actor);
return;
}

View file

@ -489,9 +489,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (special->fuse) // This box is respawning, but was broken very recently (see P_FuseThink)
{
// What was this box broken as?
if (cv_thunderdome.value)
K_StartItemRoulette(player, true);
else if (special->cvmem && !(special->flags2 & MF2_BOSSDEAD))
if (!K_ThunderDome() && special->cvmem && !(special->flags2 & MF2_BOSSDEAD))
K_StartItemRoulette(player, false);
else
K_StartItemRoulette(player, true);

View file

@ -15569,7 +15569,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
//
void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration)
{
if (!pl)
if (!pl || cv_reducevfx.value)
return;
pl->flashcount = duration;
pl->flashpal = type;

View file

@ -468,6 +468,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT16(save->p, players[i].bigwaypointgap);
WRITEUINT8(save->p, players[i].startboost);
WRITEUINT8(save->p, players[i].dropdashboost);
WRITEUINT8(save->p, players[i].aciddropdashboost);
WRITEUINT16(save->p, players[i].flashing);
WRITEUINT16(save->p, players[i].spinouttimer);
@ -708,6 +709,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT32(save->p, players[i].lastringboost);
WRITEUINT8(save->p, players[i].amps);
WRITEUINT8(save->p, players[i].recentamps);
WRITEUINT8(save->p, players[i].amppickup);
WRITEUINT8(save->p, players[i].ampspending);
@ -1145,6 +1147,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].bigwaypointgap = READUINT16(save->p);
players[i].startboost = READUINT8(save->p);
players[i].dropdashboost = READUINT8(save->p);
players[i].aciddropdashboost = READUINT8(save->p);
players[i].flashing = READUINT16(save->p);
players[i].spinouttimer = READUINT16(save->p);
@ -1383,6 +1386,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].lastringboost = READUINT32(save->p);
players[i].amps =READUINT8(save->p);
players[i].recentamps =READUINT8(save->p);
players[i].amppickup =READUINT8(save->p);
players[i].ampspending =READUINT8(save->p);

View file

@ -2071,8 +2071,6 @@ static void K_HandleLapIncrement(player_t *player)
{
S_StartSound(player->mo, sfx_s23c);
player->startboost = 125;
if (!K_PlayerUsesBotMovement(player) && grandprixinfo.gp)
player->startboost /= 2;
K_SpawnDriftBoostExplosion(player, 4);
K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false);

View file

@ -1011,7 +1011,11 @@ void S_UpdateVoicePositionalProperties(void)
float pdirx = px / p2ddistance;
float pdiry = py / p2ddistance;
float angle = acosf(pdirx * ldirx + pdiry * ldiry);
angle = PointIsLeft(ldirx, ldiry, pdirx, pdiry) ? -angle : angle;
angle = (
PointIsLeft(ldirx, ldiry, pdirx, pdiry)
^ stereoreverse.value
^ encoremode
) ? -angle : angle;
float plrvolume = 1.0f;

View file

@ -52,6 +52,7 @@ extern consvar_t cv_voice_selfdeafen;
extern consvar_t cv_voice_mode;
extern consvar_t cv_voice_selfmute;
extern consvar_t cv_voice_loopback;
extern consvar_t cv_voice_denoise;
extern consvar_t cv_voice_inputamp;
extern consvar_t cv_voice_activationthreshold;
extern consvar_t cv_voice_proximity;

View file

@ -263,6 +263,9 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
case 8:
padconfig = saturntypeE;
break;
case 9:
padconfig = saturntypeF;
break;
}
if (auto pretty = prettyinputs.find(bind); pretty != prettyinputs.end()) // Gamepad direction or keyboard arrow, use something nice-looking

View file

@ -184,6 +184,23 @@ static const srb2::HashMap<INT32, char> saturntypeE = {
{nc_back, gb_back},
};
// Saturn Type F - Mayflash XInput Saturn adapter, CZ = RS LS
// Cannot be disambiguated. GEE I SURE WISH THERE WERE A STANDARD
static const srb2::HashMap<INT32, char> saturntypeF = {
{nc_a, sb_a},
{nc_b, sb_b},
{nc_x, sb_x},
{nc_y, sb_y},
{nc_rt, gb_rt},
{nc_rb, gb_rb},
{nc_lb, gb_lb},
{nc_lt, gb_lt},
{nc_ls, sb_z},
{nc_rs, sb_c},
{nc_start, gb_start},
{nc_back, gb_back},
};
namespace srb2
{

View file

@ -19,3 +19,5 @@ add_subdirectory(fmt)
add_subdirectory(vulkan-headers)
add_subdirectory(volk)
add_subdirectory(vma)
add_subdirectory(renamenoise)

1
thirdparty/renamenoise/AUTHORS vendored Normal file
View file

@ -0,0 +1 @@
Jean-Marc Valin <jmvalin@jmvalin.ca>

17
thirdparty/renamenoise/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,17 @@
# Update from https://github.com/mumble-voip/ReNameNoise
# ReNameNoise unversioned
# License: BSD-3
add_library(renamenoise STATIC)
target_sources(renamenoise PRIVATE
"src/rnn_data.c"
"src/rnn.c"
"src/pitch.c"
"src/renamenoise_fft.c"
"src/denoise.c"
"src/renamenoise_lpc.c"
)
target_include_directories(renamenoise PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_compile_definitions(renamenoise PRIVATE "RENAMENOISE_BUILD")
target_compile_definitions(renamenoise PRIVATE "ENABLE_ASSERTIONS")
add_library(ReNameNoise::renamenoise ALIAS renamenoise)

32
thirdparty/renamenoise/COPYING vendored Normal file
View file

@ -0,0 +1,32 @@
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2017, Mozilla
Copyright (c) 2007-2017, Jean-Marc Valin
Copyright (c) 2005-2017, Xiph.Org Foundation
Copyright (c) 2003-2004, Mark Borgerding
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.Org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

67
thirdparty/renamenoise/README.md vendored Normal file
View file

@ -0,0 +1,67 @@
# ReNameNoise
ReNameNoise - a fork of [RNNoise](https://gitlab.xiph.org/xiph/rnnoise) - is a noise suppression library based on a recurrent neural network.
A description of the algorithm is provided in the following paper:
```
J.-M. Valin, A Hybrid DSP/Deep Learning Approach to Real-Time Full-Band Speech
Enhancement, Proceedings of IEEE Multimedia Signal Processing (MMSP) Workshop,
arXiv:1709.08243, 2018.
https://arxiv.org/pdf/1709.08243.pdf
```
An interactive demo is available at: https://jmvalin.ca/demo/rnnoise/
## Prerequisites
To build the library with the existing, pre-trained network data you will need to install the following packages:
* build-essential
* cmake
## Build
To compile, open a terminal in the repository root directory and type:
```bash
cmake .
make
```
To compile the library only, without the demo executable:
```bash
cmake -DRENAMENOISE_DEMO_EXECUTABLE=OFF .
make
```
## Usage
While it is meant to be used as a library, a simple command-line tool is
provided as an example. It operates on RAW 16-bit (machine endian) mono
PCM files sampled at 48 kHz. It can be used as:
``./examples/renamenoise_demo <noisy speech> <output denoised>``
The output is also a 16-bit raw PCM file.d
## Training
Training is not necessary to use the library as presented in this repository.
However, if you want to train the network on your own samples you need to follow these steps:
```bash
cd src ; ./compile.sh
./denoise_training signal.raw noise.raw count > training.f32
# (note the matrix size and replace 500000 87 below)
cd training ; ./bin2hdf5.py ../src/training.f32 500000 87 training.h5
./rnn_train.py
./dump_rnn.py weights.hdf5 ../src/rnn_data.c ../src/rnn_data.h
```

View file

@ -0,0 +1,125 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2018, Gregor Richards
Copyright (c) 2017, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RENAMENOISE_H
#define RENAMENOISE_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RENAMENOISE_EXPORT
# if defined(WIN32)
# if defined(RENAMENOISE_BUILD) && defined(DLL_EXPORT)
# define RENAMENOISE_EXPORT __declspec(dllexport)
# else
# define RENAMENOISE_EXPORT
# endif
# elif defined(__GNUC__) && defined(RENAMENOISE_BUILD)
# define RENAMENOISE_EXPORT __attribute__((visibility("default")))
# else
# define RENAMENOISE_EXPORT
# endif
#endif
typedef struct ReNameNoiseDenoiseState ReNameNoiseDenoiseState;
typedef struct ReNameNoiseModel ReNameNoiseModel;
/**
* Return the size of ReNameNoiseDenoiseState
*/
RENAMENOISE_EXPORT int renamenoise_get_size(void);
/**
* Return the number of samples processed by renamenoise_process_frame at a time
*/
RENAMENOISE_EXPORT int renamenoise_get_frame_size(void);
/**
* Initializes a pre-allocated ReNameNoiseDenoiseState
*
* If model is NULL the default model is used.
*
* See: renamenoise_create() and renamenoise_model_from_file()
*/
RENAMENOISE_EXPORT int renamenoise_init(ReNameNoiseDenoiseState *st, ReNameNoiseModel *model);
/**
* Allocate and initialize a ReNameNoiseDenoiseState
*
* If model is NULL the default model is used.
*
* The returned pointer MUST be freed with renamenoise_destroy().
*/
RENAMENOISE_EXPORT ReNameNoiseDenoiseState *renamenoise_create(ReNameNoiseModel *model);
/**
* Free a ReNameNoiseDenoiseState produced by renamenoise_create.
*
* The optional custom model must be freed by renamenoise_model_free() after.
*/
RENAMENOISE_EXPORT void renamenoise_destroy(ReNameNoiseDenoiseState *st);
/**
* Denoise a frame of samples
*
* in and out must be at least renamenoise_get_frame_size() large.
*/
RENAMENOISE_EXPORT float renamenoise_process_frame(ReNameNoiseDenoiseState *st, float *out, const float *in);
/**
* Denoise a frame of samples, but clamp the output to fit into a 16 bit signed short
*
* in and out must be at least renamenoise_get_frame_size() large.
*/
RENAMENOISE_EXPORT float renamenoise_process_frame_clamped(ReNameNoiseDenoiseState *st, short *out, const float *in);
/**
* Load a model from a file
*
* It must be deallocated with renamenoise_model_free()
*/
RENAMENOISE_EXPORT ReNameNoiseModel *renamenoise_model_from_file(FILE *f);
/**
* Free a custom model
*
* It must be called after all the ReNameNoiseDenoiseStates referring to it are freed.
*/
RENAMENOISE_EXPORT void renamenoise_model_free(ReNameNoiseModel *model);
#ifdef __cplusplus
}
#endif
#endif /* RENAMENOISE_H */

View file

@ -0,0 +1,111 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2003-2004, Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RENAMENOISE_FFT_GUTS_H
#define RENAMENOISE_FFT_GUTS_H
/**
renamenoise_fft.h
Defines renamenoise_fft_scalar as either short or a float type
and defines
typedef struct {
renamenoise_fft_scalar r;
renamenoise_fft_scalar i;
} renamenoise_fft_cpx;
**/
#include "renamenoise_fft.h"
/*
Explanation of macros dealing with complex math:
C_MUL(m,a,b) : m = a*b
C_SUB( res, a,b) : res = a - b
C_SUBFROM( res , a) : res -= a
C_ADDTO( res , a) : res += a
*/
#define RENAMENOISE_S_MUL(a, b) ((a) * (b))
#define RENAMENOISE_C_MUL(m, a, b) \
do { \
(m).r = (a).r * (b).r - (a).i * (b).i; \
(m).i = (a).r * (b).i + (a).i * (b).r; \
} while (0)
#define RENAMENOISE_C_MULC(m, a, b) \
do { \
(m).r = (a).r * (b).r + (a).i * (b).i; \
(m).i = (a).i * (b).r - (a).r * (b).i; \
} while (0)
#define RENAMENOISE_C_MUL4(m, a, b) RENAMENOISE_C_MUL(m, a, b)
#define RENAMENOISE_C_MULBYSCALAR(c, s) \
do { \
(c).r *= (s); \
(c).i *= (s); \
} while (0)
#ifndef RENAMENOISE_C_ADD
# define RENAMENOISE_C_ADD(res, a, b) \
do { \
(res).r = (a).r + (b).r; \
(res).i = (a).i + (b).i; \
} while (0)
# define RENAMENOISE_C_SUB(res, a, b) \
do { \
(res).r = (a).r - (b).r; \
(res).i = (a).i - (b).i; \
} while (0)
# define RENAMENOISE_C_ADDTO(res, a) \
do { \
(res).r += (a).r; \
(res).i += (a).i; \
} while (0)
# define RENAMENOISE_C_SUBFROM(res, a) \
do { \
(res).r -= (a).r; \
(res).i -= (a).i; \
} while (0)
#endif /* !RENAMENOISE_C_ADD defined */
#define RENAMENOISE_FFT_COS(phase) (renamenoise_fft_scalar) cos(phase)
#define RENAMENOISE_FFT_SIN(phase) (renamenoise_fft_scalar) sin(phase)
#define renamenoise_kf_cexp(x, phase) \
do { \
(x)->r = RENAMENOISE_FFT_COS(phase); \
(x)->i = RENAMENOISE_FFT_SIN(phase); \
} while (0)
#endif /* RENAMENOISE_FFT_GUTS_H */

165
thirdparty/renamenoise/src/arch.h vendored Normal file
View file

@ -0,0 +1,165 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2007-2009, Xiph.Org Foundation
Copyright (c) 2007-2008, CSIRO
Copyright (c) 2003-2008, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@file arch.h
@brief Various architecture definitions for ReNameNoise
*/
#ifndef ARCH_H
#define ARCH_H
#include "common.h"
#include "renamenoise_types.h"
#if !defined(__GNUC_PREREQ)
# if defined(__GNUC__) && defined(__GNUC_MINOR__)
# define __GNUC_PREREQ(_maj, _min) ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((_maj) << 16) + (_min))
# else
# define __GNUC_PREREQ(_maj, _min) 0
# endif
#endif
#ifndef M_PI
# define M_PI (3.14159265358979323846)
#endif
#define renamenoise_fatal(str) _renamenoise_fatal(str, __FILE__, __LINE__);
#ifdef ENABLE_ASSERTIONS
# include <stdio.h>
# include <stdlib.h>
# ifdef __GNUC__
__attribute__((noreturn))
# endif
static RENAMENOISE_INLINE void
_renamenoise_fatal(const char *str, const char *file, int line) {
fprintf(stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
abort();
}
# define renamenoise_assert(cond) \
{ \
if (!(cond)) { \
renamenoise_fatal("assertion failed: " #cond); \
} \
}
# define renamenoise_assert2(cond, message) \
{ \
if (!(cond)) { \
renamenoise_fatal("assertion failed: " #cond "\n" message); \
} \
}
#else
# define renamenoise_assert(cond)
# define renamenoise_assert2(cond, message)
#endif /* !ENABLE_ASSERTIONS defined */
#define RENAMENOISE_MIN16(a, b) ((a) < (b) ? (a) : (b))
#define RENAMENOISE_MAX16(a, b) ((a) > (b) ? (a) : (b))
#define RENAMENOISE_MIN32(a, b) ((a) < (b) ? (a) : (b))
#define RENAMENOISE_MAX32(a, b) ((a) > (b) ? (a) : (b))
typedef float renamenoise_val16;
typedef float renamenoise_val32;
typedef float renamenoise_sig;
#ifdef RENAMENOISE_FLOAT_APPROX
// This code should reliably detect NaN/inf even when -ffast-math is used.
// Assumes IEEE 754 format.
static RENAMENOISE_INLINE int renamenoise_isnan(float x) {
union {
float f;
renamenoise_uint32 i;
} in;
in.f = x;
return ((in.i >> 23) & 0xFF) == 0xFF && (in.i & 0x007FFFFF) != 0;
}
#else
# ifdef __FAST_MATH__
# error Cannot build renamenoise with -ffast-math unless RENAMENOISE_FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input
# endif
# define renamenoise_isnan(x) ((x) != (x))
#endif
#define RENAMENOISE_Q15ONE 1.0f
#define RENAMENOISE_EPSILON 1e-15f
#define RENAMENOISE_VERY_SMALL 1e-30f
#define RENAMENOISE_VERY_LARGE16 1e15f
#define RENAMENOISE_HALF(x) (.5f * (x))
#define RENAMENOISE_ADD(a, b) ((a) + (b))
#define RENAMENOISE_SUB(a, b) ((a) - (b))
#define RENAMENOISE_MAC(c, a, b) ((c) + (renamenoise_val32) (a) * (renamenoise_val32) (b))
#define RENAMENOISE_MULT(a, b) ((a) * (b))
#if __STDC_VERSION__ < 199901L || (__STDC_VERSION__ > 201000L && __STDC_NO_VLA__ == 1)
# define RENAMENOISE_NO_VLA
#endif
#ifdef RENAMENOISE_NO_VLA
# include <malloc.h>
# define renamenoise_stackalloc(type, id, len) type *id = alloca((len) * sizeof(type))
#else
# define renamenoise_stackalloc(type, id, len) type id[len]
#endif
// Portable macros for denoting unreachable code.
// In such a scenario, perform an early exit ('panic')
#if _MSC_VER // MSVC
# define renamenoise_unreachable() __assume(0)
#elif __GNUC__ || __clang__ || __MINGW32__
# define renamenoise_unreachable() __builtin_unreachable()
// #elif __BORLANDC__
// #define renamenoise_unreachable() __builtin_unreachable() // unknown. needs investigation
#else
# define renamenoise_unreachable()
#endif
#endif /* ARCH_H */

54
thirdparty/renamenoise/src/common.h vendored Normal file
View file

@ -0,0 +1,54 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2017, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef COMMON_H
#define COMMON_H
#include "stdlib.h"
#include "string.h"
#define RENAMENOISE_INLINE inline
/** Copy n elements from src to dst. The 0* term provides compile-time type checking */
#ifndef OVERRIDE_RENAMENOISE_COPY
# define RENAMENOISE_COPY(dst, src, n) (memcpy((dst), (src), (n) * sizeof(*(dst)) + 0 * ((dst) - (src))))
#endif
/** Copy n elements from src to dst, allowing overlapping regions. The 0* term provides compile-time type checking */
#ifndef OVERRIDE_RENAMENOISE_MOVE
# define RENAMENOISE_MOVE(dst, src, n) (memmove((dst), (src), (n) * sizeof(*(dst)) + 0 * ((dst) - (src))))
#endif
/** Set n elements of dst to zero */
#ifndef OVERRIDE_RENAMENOISE_CLEAR
# define RENAMENOISE_CLEAR(dst, n) (memset((dst), 0, (n) * sizeof(*(dst))))
#endif
#endif /* COMMON_H */

3
thirdparty/renamenoise/src/compile.sh vendored Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
gcc -DRENAMENOISE_TRAINING=1 -Wall -W -O3 -g -I../include denoise.c renamenoise_fft.c pitch.c renamenoise_lpc.c rnn.c rnn_data.c -o denoise_training -lm

692
thirdparty/renamenoise/src/denoise.c vendored Normal file
View file

@ -0,0 +1,692 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2018, Gregor Richards
Copyright (c) 2017, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "arch.h"
#include "common.h"
#include "pitch.h"
#include "renamenoise.h"
#include "renamenoise_fft.h"
#include "rnn.h"
#include "rnn_data.h"
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RENAMENOISE_FRAME_SIZE_SHIFT 2
#define RENAMENOISE_FRAME_SIZE (120 << RENAMENOISE_FRAME_SIZE_SHIFT)
#define RENAMENOISE_WINDOW_SIZE (2 * RENAMENOISE_FRAME_SIZE)
#define RENAMENOISE_FREQ_SIZE (RENAMENOISE_FRAME_SIZE + 1)
#define RENAMENOISE_PITCH_MIN_PERIOD 60
#define RENAMENOISE_PITCH_MAX_PERIOD 768
#define RENAMENOISE_PITCH_FRAME_SIZE 960
#define RENAMENOISE_PITCH_BUF_SIZE (RENAMENOISE_PITCH_MAX_PERIOD + RENAMENOISE_PITCH_FRAME_SIZE)
#define RENAMENOISE_SQUARE(x) ((x) * (x))
#define RENAMENOISE_NB_BANDS 22
#define RENAMENOISE_CEPS_MEM 8
#define RENAMENOISE_NB_DELTA_CEPS 6
#define RENAMENOISE_NB_FEATURES (RENAMENOISE_NB_BANDS + 3 * RENAMENOISE_NB_DELTA_CEPS + 2)
#ifndef RENAMENOISE_TRAINING
# define RENAMENOISE_TRAINING 0
#endif
/* The built-in model, used if no file is given as input */
extern const struct ReNameNoiseModel renamenoise_model_orig;
static const renamenoise_int16 renamenoise_eband5ms[] = {
// 0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12,
// 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 20k
14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100};
typedef struct {
int init;
renamenoise_fft_state *kfft;
float half_window[RENAMENOISE_FRAME_SIZE];
float dct_table[RENAMENOISE_NB_BANDS * RENAMENOISE_NB_BANDS];
} ReNameNoiseCommonState;
struct ReNameNoiseDenoiseState {
float analysis_mem[RENAMENOISE_FRAME_SIZE];
float cepstral_mem[RENAMENOISE_CEPS_MEM][RENAMENOISE_NB_BANDS];
int memid;
float synthesis_mem[RENAMENOISE_FRAME_SIZE];
float pitch_buf[RENAMENOISE_PITCH_BUF_SIZE];
float pitch_enh_buf[RENAMENOISE_PITCH_BUF_SIZE];
float last_gain;
int last_period;
float mem_hp_x[2];
float lastg[RENAMENOISE_NB_BANDS];
ReNameNoiseRNNState rnn;
};
void renamenoise_compute_band_energy(float *bandE, const renamenoise_fft_cpx *X) {
int i;
float sum[RENAMENOISE_NB_BANDS] = {0};
for (i = 0; i < RENAMENOISE_NB_BANDS - 1; i++) {
int j;
int band_size;
band_size = (renamenoise_eband5ms[i + 1] - renamenoise_eband5ms[i]) << RENAMENOISE_FRAME_SIZE_SHIFT;
for (j = 0; j < band_size; j++) {
float tmp;
float frac = (float) j / band_size;
tmp = RENAMENOISE_SQUARE(X[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j].r);
tmp += RENAMENOISE_SQUARE(X[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j].i);
sum[i] = sum[i] + (1 - frac) * tmp;
sum[i + 1] = sum[i + 1] + frac * tmp;
}
}
sum[0] *= 2;
sum[RENAMENOISE_NB_BANDS - 1] *= 2;
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
bandE[i] = sum[i];
}
}
void renamenoise_compute_band_corr(float *bandE, const renamenoise_fft_cpx *X, const renamenoise_fft_cpx *P) {
int i;
float sum[RENAMENOISE_NB_BANDS] = {0};
for (i = 0; i < RENAMENOISE_NB_BANDS - 1; i++) {
int j;
int band_size;
band_size = (renamenoise_eband5ms[i + 1] - renamenoise_eband5ms[i]) << RENAMENOISE_FRAME_SIZE_SHIFT;
for (j = 0; j < band_size; j++) {
float tmp;
float frac = (float) j / band_size;
tmp = X[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j].r
* P[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j].r;
tmp += X[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j].i
* P[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j].i;
sum[i] += (1 - frac) * tmp;
sum[i + 1] += frac * tmp;
}
}
sum[0] *= 2;
sum[RENAMENOISE_NB_BANDS - 1] *= 2;
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
bandE[i] = sum[i];
}
}
void renamenoise_interp_band_gain(float *g, const float *bandE) {
int i;
memset(g, 0, RENAMENOISE_FREQ_SIZE);
for (i = 0; i < RENAMENOISE_NB_BANDS - 1; i++) {
int j;
int band_size;
band_size = (renamenoise_eband5ms[i + 1] - renamenoise_eband5ms[i]) << RENAMENOISE_FRAME_SIZE_SHIFT;
for (j = 0; j < band_size; j++) {
float frac = (float) j / band_size;
g[(renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT) + j] = (1 - frac) * bandE[i] + frac * bandE[i + 1];
}
}
}
ReNameNoiseCommonState renamenoise_common;
static void renamenoise_check_init(void) {
int i;
if (renamenoise_common.init) {
return;
}
renamenoise_common.kfft = renamenoise_fft_alloc_twiddles(2 * RENAMENOISE_FRAME_SIZE, NULL, NULL, NULL, 0);
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
renamenoise_common.half_window[i] =
sin(.5 * M_PI * sin(.5 * M_PI * (i + .5) / RENAMENOISE_FRAME_SIZE) * sin(.5 * M_PI * (i + .5) / RENAMENOISE_FRAME_SIZE));
}
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
int j;
for (j = 0; j < RENAMENOISE_NB_BANDS; j++) {
renamenoise_common.dct_table[i * RENAMENOISE_NB_BANDS + j] = cos((i + .5) * j * M_PI / RENAMENOISE_NB_BANDS);
if (j == 0) {
renamenoise_common.dct_table[i * RENAMENOISE_NB_BANDS + j] *= sqrt(.5);
}
}
}
renamenoise_common.init = 1;
}
static void renamenoise_dct(float *out, const float *in) {
int i;
renamenoise_check_init();
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
int j;
float sum = 0;
for (j = 0; j < RENAMENOISE_NB_BANDS; j++) {
sum += in[j] * renamenoise_common.dct_table[j * RENAMENOISE_NB_BANDS + i];
}
out[i] = sum * sqrt(2. / 22);
}
}
static void renamenoise_forward_transform(renamenoise_fft_cpx *out, const float *in) {
int i;
renamenoise_fft_cpx x[RENAMENOISE_WINDOW_SIZE];
renamenoise_fft_cpx y[RENAMENOISE_WINDOW_SIZE];
renamenoise_check_init();
for (i = 0; i < RENAMENOISE_WINDOW_SIZE; i++) {
x[i].r = in[i];
x[i].i = 0;
}
renamenoise_fft(renamenoise_common.kfft, x, y, 0);
for (i = 0; i < RENAMENOISE_FREQ_SIZE; i++) {
out[i] = y[i];
}
}
static void renamenoise_inverse_transform(float *out, const renamenoise_fft_cpx *in) {
int i;
renamenoise_fft_cpx x[RENAMENOISE_WINDOW_SIZE];
renamenoise_fft_cpx y[RENAMENOISE_WINDOW_SIZE];
renamenoise_check_init();
for (i = 0; i < RENAMENOISE_FREQ_SIZE; i++) {
x[i] = in[i];
}
for (; i < RENAMENOISE_WINDOW_SIZE; i++) {
x[i].r = x[RENAMENOISE_WINDOW_SIZE - i].r;
x[i].i = -x[RENAMENOISE_WINDOW_SIZE - i].i;
}
renamenoise_fft(renamenoise_common.kfft, x, y, 0);
// output in reverse order for IFFT.
out[0] = RENAMENOISE_WINDOW_SIZE * y[0].r;
for (i = 1; i < RENAMENOISE_WINDOW_SIZE; i++) {
out[i] = RENAMENOISE_WINDOW_SIZE * y[RENAMENOISE_WINDOW_SIZE - i].r;
}
}
static void renamenoise_apply_window(float *x) {
int i;
renamenoise_check_init();
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
x[i] *= renamenoise_common.half_window[i];
x[RENAMENOISE_WINDOW_SIZE - 1 - i] *= renamenoise_common.half_window[i];
}
}
int renamenoise_get_size(void) {
return sizeof(ReNameNoiseDenoiseState);
}
int renamenoise_get_frame_size(void) {
return RENAMENOISE_FRAME_SIZE;
}
int renamenoise_init(ReNameNoiseDenoiseState *st, ReNameNoiseModel *model) {
memset(st, 0, sizeof(*st));
if (model) {
st->rnn.model = model;
} else {
st->rnn.model = &renamenoise_model_orig;
}
st->rnn.vad_gru_state = calloc(sizeof(float), st->rnn.model->vad_gru_size);
st->rnn.noise_gru_state = calloc(sizeof(float), st->rnn.model->noise_gru_size);
st->rnn.denoise_gru_state = calloc(sizeof(float), st->rnn.model->denoise_gru_size);
return 0;
}
ReNameNoiseDenoiseState *renamenoise_create(ReNameNoiseModel *model) {
ReNameNoiseDenoiseState *st;
st = malloc(renamenoise_get_size());
renamenoise_init(st, model);
return st;
}
void renamenoise_destroy(ReNameNoiseDenoiseState *st) {
free(st->rnn.vad_gru_state);
free(st->rnn.noise_gru_state);
free(st->rnn.denoise_gru_state);
free(st);
}
#if RENAMENOISE_TRAINING
int lowpass = RENAMENOISE_FREQ_SIZE;
int band_lp = RENAMENOISE_NB_BANDS;
#endif
static void renamenoise_frame_analysis(ReNameNoiseDenoiseState *st, renamenoise_fft_cpx *X, float *Ex, const float *in) {
int i;
float x[RENAMENOISE_WINDOW_SIZE];
RENAMENOISE_COPY(x, st->analysis_mem, RENAMENOISE_FRAME_SIZE);
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
x[RENAMENOISE_FRAME_SIZE + i] = in[i];
}
RENAMENOISE_COPY(st->analysis_mem, in, RENAMENOISE_FRAME_SIZE);
renamenoise_apply_window(x);
renamenoise_forward_transform(X, x);
#if RENAMENOISE_TRAINING
for (i = lowpass; i < RENAMENOISE_FREQ_SIZE; i++) {
X[i].r = X[i].i = 0;
}
#endif
renamenoise_compute_band_energy(Ex, X);
}
static int renamenoise_compute_frame_features(ReNameNoiseDenoiseState *st, renamenoise_fft_cpx *X, renamenoise_fft_cpx *P, float *Ex, float *Ep,
float *Exp, float *features, const float *in) {
int i;
float E = 0;
float *ceps_0, *ceps_1, *ceps_2;
float spec_variability = 0;
float Ly[RENAMENOISE_NB_BANDS];
float p[RENAMENOISE_WINDOW_SIZE];
float pitch_buf[RENAMENOISE_PITCH_BUF_SIZE >> 1];
int pitch_index;
float gain;
float *(pre[1]);
float tmp[RENAMENOISE_NB_BANDS];
float follow, logMax;
renamenoise_frame_analysis(st, X, Ex, in);
RENAMENOISE_MOVE(st->pitch_buf, &st->pitch_buf[RENAMENOISE_FRAME_SIZE], RENAMENOISE_PITCH_BUF_SIZE - RENAMENOISE_FRAME_SIZE);
RENAMENOISE_COPY(&st->pitch_buf[RENAMENOISE_PITCH_BUF_SIZE - RENAMENOISE_FRAME_SIZE], in, RENAMENOISE_FRAME_SIZE);
pre[0] = &st->pitch_buf[0];
renamenoise_pitch_downsample(pre, pitch_buf, RENAMENOISE_PITCH_BUF_SIZE, 1);
renamenoise_pitch_search(pitch_buf + (RENAMENOISE_PITCH_MAX_PERIOD >> 1), pitch_buf, RENAMENOISE_PITCH_FRAME_SIZE,
RENAMENOISE_PITCH_MAX_PERIOD - 3 * RENAMENOISE_PITCH_MIN_PERIOD, &pitch_index);
pitch_index = RENAMENOISE_PITCH_MAX_PERIOD - pitch_index;
gain = renamenoise_remove_doubling(pitch_buf, RENAMENOISE_PITCH_MAX_PERIOD, RENAMENOISE_PITCH_MIN_PERIOD, RENAMENOISE_PITCH_FRAME_SIZE,
&pitch_index, st->last_period, st->last_gain);
st->last_period = pitch_index;
st->last_gain = gain;
for (i = 0; i < RENAMENOISE_WINDOW_SIZE; i++) {
p[i] = st->pitch_buf[RENAMENOISE_PITCH_BUF_SIZE - RENAMENOISE_WINDOW_SIZE - pitch_index + i];
}
renamenoise_apply_window(p);
renamenoise_forward_transform(P, p);
renamenoise_compute_band_energy(Ep, P);
renamenoise_compute_band_corr(Exp, X, P);
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
Exp[i] = Exp[i] / sqrt(.001 + Ex[i] * Ep[i]);
}
renamenoise_dct(tmp, Exp);
for (i = 0; i < RENAMENOISE_NB_DELTA_CEPS; i++) {
features[RENAMENOISE_NB_BANDS + 2 * RENAMENOISE_NB_DELTA_CEPS + i] = tmp[i];
}
features[RENAMENOISE_NB_BANDS + 2 * RENAMENOISE_NB_DELTA_CEPS] -= 1.3;
features[RENAMENOISE_NB_BANDS + 2 * RENAMENOISE_NB_DELTA_CEPS + 1] -= 0.9;
features[RENAMENOISE_NB_BANDS + 3 * RENAMENOISE_NB_DELTA_CEPS] = .01 * (pitch_index - 300);
logMax = -2;
follow = -2;
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
Ly[i] = log10(1e-2 + Ex[i]);
Ly[i] = RENAMENOISE_MAX16(logMax - 7, RENAMENOISE_MAX16(follow - 1.5, Ly[i]));
logMax = RENAMENOISE_MAX16(logMax, Ly[i]);
follow = RENAMENOISE_MAX16(follow - 1.5, Ly[i]);
E += Ex[i];
}
if (!RENAMENOISE_TRAINING && E < 0.04) {
// If there's no audio, avoid messing up the state.
RENAMENOISE_CLEAR(features, RENAMENOISE_NB_FEATURES);
return 1;
}
renamenoise_dct(features, Ly);
features[0] -= 12;
features[1] -= 4;
ceps_0 = st->cepstral_mem[st->memid];
ceps_1 = (st->memid < 1) ? st->cepstral_mem[RENAMENOISE_CEPS_MEM + st->memid - 1] : st->cepstral_mem[st->memid - 1];
ceps_2 = (st->memid < 2) ? st->cepstral_mem[RENAMENOISE_CEPS_MEM + st->memid - 2] : st->cepstral_mem[st->memid - 2];
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
ceps_0[i] = features[i];
}
st->memid++;
for (i = 0; i < RENAMENOISE_NB_DELTA_CEPS; i++) {
features[i] = ceps_0[i] + ceps_1[i] + ceps_2[i];
features[RENAMENOISE_NB_BANDS + i] = ceps_0[i] - ceps_2[i];
features[RENAMENOISE_NB_BANDS + RENAMENOISE_NB_DELTA_CEPS + i] = ceps_0[i] - 2 * ceps_1[i] + ceps_2[i];
}
// Spectral variability features.
if (st->memid == RENAMENOISE_CEPS_MEM) {
st->memid = 0;
}
for (i = 0; i < RENAMENOISE_CEPS_MEM; i++) {
int j;
float mindist = 1e15f;
for (j = 0; j < RENAMENOISE_CEPS_MEM; j++) {
int k;
float dist = 0;
for (k = 0; k < RENAMENOISE_NB_BANDS; k++) {
float tmp;
tmp = st->cepstral_mem[i][k] - st->cepstral_mem[j][k];
dist += tmp * tmp;
}
if (j != i) {
mindist = RENAMENOISE_MIN32(mindist, dist);
}
}
spec_variability += mindist;
}
features[RENAMENOISE_NB_BANDS + 3 * RENAMENOISE_NB_DELTA_CEPS + 1] = spec_variability / RENAMENOISE_CEPS_MEM - 2.1;
return RENAMENOISE_TRAINING && E < 0.1;
}
static void renamenoise_frame_synthesis(ReNameNoiseDenoiseState *st, float *out, const renamenoise_fft_cpx *y) {
float x[RENAMENOISE_WINDOW_SIZE];
int i;
renamenoise_inverse_transform(x, y);
renamenoise_apply_window(x);
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
out[i] = x[i] + st->synthesis_mem[i];
}
RENAMENOISE_COPY(st->synthesis_mem, &x[RENAMENOISE_FRAME_SIZE], RENAMENOISE_FRAME_SIZE);
}
static void renamenoise_biquad(float *y, float mem[2], const float *x, const float *b, const float *a, int N) {
int i;
for (i = 0; i < N; i++) {
float xi, yi;
xi = x[i];
yi = x[i] + mem[0];
mem[0] = mem[1] + (b[0] * (double) xi - a[0] * (double) yi);
mem[1] = (b[1] * (double) xi - a[1] * (double) yi);
y[i] = yi;
}
}
void renamenoise_pitch_filter(renamenoise_fft_cpx *X, const renamenoise_fft_cpx *P, const float *Ex, const float *Ep, const float *Exp,
const float *g) {
int i;
float r[RENAMENOISE_NB_BANDS];
float rf[RENAMENOISE_FREQ_SIZE] = {0};
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
if (Exp[i] > g[i]) {
r[i] = 1;
} else {
r[i] = RENAMENOISE_SQUARE(Exp[i]) * (1 - RENAMENOISE_SQUARE(g[i])) / (.001 + RENAMENOISE_SQUARE(g[i]) * (1 - RENAMENOISE_SQUARE(Exp[i])));
}
r[i] = sqrt(RENAMENOISE_MIN16(1, RENAMENOISE_MAX16(0, r[i])));
r[i] *= sqrt(Ex[i] / (1e-8 + Ep[i]));
}
renamenoise_interp_band_gain(rf, r);
for (i = 0; i < RENAMENOISE_FREQ_SIZE; i++) {
X[i].r += rf[i] * P[i].r;
X[i].i += rf[i] * P[i].i;
}
float newE[RENAMENOISE_NB_BANDS];
renamenoise_compute_band_energy(newE, X);
float norm[RENAMENOISE_NB_BANDS];
float normf[RENAMENOISE_FREQ_SIZE] = {0};
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
norm[i] = sqrt(Ex[i] / (1e-8 + newE[i]));
}
renamenoise_interp_band_gain(normf, norm);
for (i = 0; i < RENAMENOISE_FREQ_SIZE; i++) {
X[i].r *= normf[i];
X[i].i *= normf[i];
}
}
float renamenoise_process_frame(ReNameNoiseDenoiseState *st, float *out, const float *in) {
int i;
renamenoise_fft_cpx X[RENAMENOISE_FREQ_SIZE];
renamenoise_fft_cpx P[RENAMENOISE_WINDOW_SIZE];
float x[RENAMENOISE_FRAME_SIZE];
float Ex[RENAMENOISE_NB_BANDS], Ep[RENAMENOISE_NB_BANDS];
float Exp[RENAMENOISE_NB_BANDS];
float features[RENAMENOISE_NB_FEATURES];
float g[RENAMENOISE_NB_BANDS];
float gf[RENAMENOISE_FREQ_SIZE] = {1};
float vad_prob = 0;
int silence;
static const float a_hp[2] = {-1.99599, 0.99600};
static const float b_hp[2] = {-2, 1};
renamenoise_biquad(x, st->mem_hp_x, in, b_hp, a_hp, RENAMENOISE_FRAME_SIZE);
silence = renamenoise_compute_frame_features(st, X, P, Ex, Ep, Exp, features, x);
if (!silence) {
renamenoise_compute_rnn(&st->rnn, g, &vad_prob, features);
renamenoise_pitch_filter(X, P, Ex, Ep, Exp, g);
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
float alpha = .6f;
g[i] = RENAMENOISE_MAX16(g[i], alpha * st->lastg[i]);
st->lastg[i] = g[i];
}
renamenoise_interp_band_gain(gf, g);
for (i = 0; i < RENAMENOISE_FREQ_SIZE; i++) {
X[i].r *= gf[i];
X[i].i *= gf[i];
}
}
renamenoise_frame_synthesis(st, out, X);
return vad_prob;
}
float renamenoise_process_frame_clamped(ReNameNoiseDenoiseState *st, short *out, const float *in) {
float denoise_frames[RENAMENOISE_FRAME_SIZE];
float vad_prob = renamenoise_process_frame(st, denoise_frames, in);
for (unsigned int i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
out[i] = (short) RENAMENOISE_MIN16(RENAMENOISE_MAX16(denoise_frames[i], SHRT_MIN), SHRT_MAX);
}
return vad_prob;
}
#if RENAMENOISE_TRAINING
static float renamenoise_uni_rand() {
return rand() / (double) RAND_MAX - .5;
}
static void renamenoise_rand_resp(float *a, float *b) {
a[0] = .75 * renamenoise_uni_rand();
a[1] = .75 * renamenoise_uni_rand();
b[0] = .75 * renamenoise_uni_rand();
b[1] = .75 * renamenoise_uni_rand();
}
int main(int argc, char **argv) {
int i;
int count = 0;
static const float a_hp[2] = {-1.99599, 0.99600};
static const float b_hp[2] = {-2, 1};
float a_noise[2] = {0};
float b_noise[2] = {0};
float a_sig[2] = {0};
float b_sig[2] = {0};
float mem_hp_x[2] = {0};
float mem_hp_n[2] = {0};
float mem_resp_x[2] = {0};
float mem_resp_n[2] = {0};
float x[RENAMENOISE_FRAME_SIZE];
float n[RENAMENOISE_FRAME_SIZE];
float xn[RENAMENOISE_FRAME_SIZE];
int vad_cnt = 0;
int gain_change_count = 0;
float speech_gain = 1, noise_gain = 1;
FILE *f1, *f2;
int maxCount;
ReNameNoiseDenoiseState *st;
ReNameNoiseDenoiseState *noise_state;
ReNameNoiseDenoiseState *noisy;
st = renamenoise_create(NULL);
noise_state = renamenoise_create(NULL);
noisy = renamenoise_create(NULL);
if (argc != 4) {
fprintf(stderr, "usage: %s <speech> <noise> <count>\n", argv[0]);
return 1;
}
f1 = fopen(argv[1], "r");
f2 = fopen(argv[2], "r");
maxCount = atoi(argv[3]);
for (i = 0; i < 150; i++) {
short tmp[RENAMENOISE_FRAME_SIZE];
fread(tmp, sizeof(short), RENAMENOISE_FRAME_SIZE, f2);
}
while (1) {
renamenoise_fft_cpx X[RENAMENOISE_FREQ_SIZE], Y[RENAMENOISE_FREQ_SIZE], N[RENAMENOISE_FREQ_SIZE], P[RENAMENOISE_WINDOW_SIZE];
float Ex[RENAMENOISE_NB_BANDS], Ey[RENAMENOISE_NB_BANDS], En[RENAMENOISE_NB_BANDS], Ep[RENAMENOISE_NB_BANDS];
float Exp[RENAMENOISE_NB_BANDS];
float Ln[RENAMENOISE_NB_BANDS];
float features[RENAMENOISE_NB_FEATURES];
float g[RENAMENOISE_NB_BANDS];
short tmp[RENAMENOISE_FRAME_SIZE];
float vad = 0;
float E = 0;
if (count == maxCount) {
break;
}
if ((count % 1000) == 0) {
fprintf(stderr, "%d\r", count);
}
if (++gain_change_count > 2821) {
speech_gain = pow(10., (-40 + (rand() % 60)) / 20.);
noise_gain = pow(10., (-30 + (rand() % 50)) / 20.);
if (rand() % 10 == 0) {
noise_gain = 0;
}
noise_gain *= speech_gain;
if (rand() % 10 == 0) {
speech_gain = 0;
}
gain_change_count = 0;
renamenoise_rand_resp(a_noise, b_noise);
renamenoise_rand_resp(a_sig, b_sig);
lowpass = RENAMENOISE_FREQ_SIZE * 3000. / 24000. * pow(50., rand() / (double) RAND_MAX);
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
if (renamenoise_eband5ms[i] << RENAMENOISE_FRAME_SIZE_SHIFT > lowpass) {
band_lp = i;
break;
}
}
}
if (speech_gain != 0) {
fread(tmp, sizeof(short), RENAMENOISE_FRAME_SIZE, f1);
if (feof(f1)) {
rewind(f1);
fread(tmp, sizeof(short), RENAMENOISE_FRAME_SIZE, f1);
}
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
x[i] = speech_gain * tmp[i];
}
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
E += tmp[i] * (float) tmp[i];
}
} else {
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
x[i] = 0;
}
E = 0;
}
if (noise_gain != 0) {
fread(tmp, sizeof(short), RENAMENOISE_FRAME_SIZE, f2);
if (feof(f2)) {
rewind(f2);
fread(tmp, sizeof(short), RENAMENOISE_FRAME_SIZE, f2);
}
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
n[i] = noise_gain * tmp[i];
}
} else {
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
n[i] = 0;
}
}
renamenoise_biquad(x, mem_hp_x, x, b_hp, a_hp, RENAMENOISE_FRAME_SIZE);
renamenoise_biquad(x, mem_resp_x, x, b_sig, a_sig, RENAMENOISE_FRAME_SIZE);
renamenoise_biquad(n, mem_hp_n, n, b_hp, a_hp, RENAMENOISE_FRAME_SIZE);
renamenoise_biquad(n, mem_resp_n, n, b_noise, a_noise, RENAMENOISE_FRAME_SIZE);
for (i = 0; i < RENAMENOISE_FRAME_SIZE; i++) {
xn[i] = x[i] + n[i];
}
if (E > 1e9f) {
vad_cnt = 0;
} else if (E > 1e8f) {
vad_cnt -= 5;
} else if (E > 1e7f) {
vad_cnt++;
} else {
vad_cnt += 2;
}
if (vad_cnt < 0) {
vad_cnt = 0;
}
if (vad_cnt > 15) {
vad_cnt = 15;
}
if (vad_cnt >= 10) {
vad = 0;
} else if (vad_cnt > 0) {
vad = 0.5f;
} else {
vad = 1.f;
}
renamenoise_frame_analysis(st, Y, Ey, x);
renamenoise_frame_analysis(noise_state, N, En, n);
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
Ln[i] = log10(1e-2 + En[i]);
}
int silence = renamenoise_compute_frame_features(noisy, X, P, Ex, Ep, Exp, features, xn);
renamenoise_pitch_filter(X, P, Ex, Ep, Exp, g);
// printf("%f %d\n", noisy->last_gain, noisy->last_period);
for (i = 0; i < RENAMENOISE_NB_BANDS; i++) {
g[i] = sqrt((Ey[i] + 1e-3) / (Ex[i] + 1e-3));
if (g[i] > 1) {
g[i] = 1;
}
if (silence || i > band_lp) {
g[i] = -1;
}
if (Ey[i] < 5e-2 && Ex[i] < 5e-2) {
g[i] = -1;
}
if (vad == 0 && noise_gain == 0) {
g[i] = -1;
}
}
count++;
fwrite(features, sizeof(float), RENAMENOISE_NB_FEATURES, stdout);
fwrite(g, sizeof(float), RENAMENOISE_NB_BANDS, stdout);
fwrite(Ln, sizeof(float), RENAMENOISE_NB_BANDS, stdout);
fwrite(&vad, sizeof(float), 1, stdout);
}
fprintf(stderr, "matrix size: %d x %d\n", count, RENAMENOISE_NB_FEATURES + 2 * RENAMENOISE_NB_BANDS + 1);
fclose(f1);
fclose(f2);
return 0;
}
#endif

363
thirdparty/renamenoise/src/pitch.c vendored Normal file
View file

@ -0,0 +1,363 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2007-2009, Xiph.Org Foundation
Copyright (c) 2007-2008, CSIRO
Copyright (c) 2003-2008, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@file pitch.c
@brief Pitch analysis
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "pitch.h"
#include "common.h"
#include "math.h"
#include "renamenoise_lpc.h"
static void renamenoise_find_best_pitch(renamenoise_val32 *xcorr, renamenoise_val16 *y, int len, int max_pitch, int *best_pitch) {
int i, j;
renamenoise_val32 Syy = 1;
renamenoise_val16 best_num[2];
renamenoise_val32 best_den[2];
best_num[0] = -1;
best_num[1] = -1;
best_den[0] = 0;
best_den[1] = 0;
best_pitch[0] = 0;
best_pitch[1] = 1;
for (j = 0; j < len; j++) {
Syy = RENAMENOISE_ADD(Syy, RENAMENOISE_MULT(y[j], y[j]));
}
for (i = 0; i < max_pitch; i++) {
if (xcorr[i] > 0) {
renamenoise_val16 num;
renamenoise_val32 xcorr16;
xcorr16 = xcorr[i];
// Considering the range of xcorr16, this should avoid both underflows and overflows (inf) when squaring xcorr16
xcorr16 *= 1e-12f;
num = RENAMENOISE_MULT(xcorr16, xcorr16);
if (RENAMENOISE_MULT(num, best_den[1]) > RENAMENOISE_MULT(best_num[1], Syy)) {
if (RENAMENOISE_MULT(num, best_den[0]) > RENAMENOISE_MULT(best_num[0], Syy)) {
best_num[1] = best_num[0];
best_den[1] = best_den[0];
best_pitch[1] = best_pitch[0];
best_num[0] = num;
best_den[0] = Syy;
best_pitch[0] = i;
} else {
best_num[1] = num;
best_den[1] = Syy;
best_pitch[1] = i;
}
}
}
Syy += RENAMENOISE_MULT(y[i + len], y[i + len]) - RENAMENOISE_MULT(y[i], y[i]);
Syy = RENAMENOISE_MAX32(1, Syy);
}
}
static void renamenoise_fir5(const renamenoise_val16 *x, const renamenoise_val16 *num, renamenoise_val16 *y, int N, renamenoise_val16 *mem) {
int i;
renamenoise_val16 num0, num1, num2, num3, num4;
renamenoise_val32 mem0, mem1, mem2, mem3, mem4;
num0 = num[0];
num1 = num[1];
num2 = num[2];
num3 = num[3];
num4 = num[4];
mem0 = mem[0];
mem1 = mem[1];
mem2 = mem[2];
mem3 = mem[3];
mem4 = mem[4];
for (i = 0; i < N; i++) {
renamenoise_val32 sum = x[i];
sum = RENAMENOISE_MAC(sum, num0, mem0);
sum = RENAMENOISE_MAC(sum, num1, mem1);
sum = RENAMENOISE_MAC(sum, num2, mem2);
sum = RENAMENOISE_MAC(sum, num3, mem3);
sum = RENAMENOISE_MAC(sum, num4, mem4);
mem4 = mem3;
mem3 = mem2;
mem2 = mem1;
mem1 = mem0;
mem0 = x[i];
y[i] = sum;
}
mem[0] = mem0;
mem[1] = mem1;
mem[2] = mem2;
mem[3] = mem3;
mem[4] = mem4;
}
void renamenoise_pitch_downsample(renamenoise_sig *x[], renamenoise_val16 *x_lp, int len, int C) {
int i;
renamenoise_val32 ac[5];
renamenoise_val16 tmp = RENAMENOISE_Q15ONE;
renamenoise_val16 lpc[4], mem[5] = {0, 0, 0, 0, 0};
renamenoise_val16 lpc2[5];
renamenoise_val16 c1 = .8f;
for (i = 1; i < (len >> 1); i++) {
x_lp[i] = RENAMENOISE_HALF(RENAMENOISE_HALF(x[0][(2 * i - 1)] + x[0][(2 * i + 1)]) + x[0][2 * i]);
}
x_lp[0] = RENAMENOISE_HALF(RENAMENOISE_HALF(x[0][1]) + x[0][0]);
if (C == 2) {
for (i = 1; i < (len >> 1); i++) {
x_lp[i] += RENAMENOISE_HALF(RENAMENOISE_HALF(x[1][(2 * i - 1)] + x[1][(2 * i + 1)]) + x[1][2 * i]);
}
x_lp[0] += RENAMENOISE_HALF(RENAMENOISE_HALF(x[1][1]) + x[1][0]);
}
_renamenoise_autocorr(x_lp, ac, NULL, 0, 4, len >> 1);
// Noise floor -40 dB
ac[0] *= 1.0001f;
// Lag windowing
for (i = 1; i <= 4; i++) {
// ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));
ac[i] -= ac[i] * (.008f * i) * (.008f * i);
}
_renamenoise_lpc(lpc, ac, 4);
for (i = 0; i < 4; i++) {
tmp = RENAMENOISE_MULT(.9f, tmp);
lpc[i] = RENAMENOISE_MULT(lpc[i], tmp);
}
// Add a zero
lpc2[0] = lpc[0] + .8f;
lpc2[1] = lpc[1] + RENAMENOISE_MULT(c1, lpc[0]);
lpc2[2] = lpc[2] + RENAMENOISE_MULT(c1, lpc[1]);
lpc2[3] = lpc[3] + RENAMENOISE_MULT(c1, lpc[2]);
lpc2[4] = RENAMENOISE_MULT(c1, lpc[3]);
renamenoise_fir5(x_lp, lpc2, x_lp, len >> 1, mem);
}
void renamenoise_pitch_xcorr(const renamenoise_val16 *_x, const renamenoise_val16 *_y, renamenoise_val32 *xcorr, int len, int max_pitch) {
// Unrolled version of the pitch correlation -- runs faster on x86 and ARM
int i;
// The EDSP version requires that max_pitch is at least 1,
// and that _x is 32-bit aligned.
// Since it's hard to put asserts in assembly, put them here.
renamenoise_assert(max_pitch > 0);
renamenoise_assert((((unsigned char *) _x - (unsigned char *) NULL) & 3) == 0);
for (i = 0; i < max_pitch - 3; i += 4) {
renamenoise_val32 sum[4] = {0, 0, 0, 0};
renamenoise_xcorr_kernel(_x, _y + i, sum, len);
xcorr[i] = sum[0];
xcorr[i + 1] = sum[1];
xcorr[i + 2] = sum[2];
xcorr[i + 3] = sum[3];
}
// In case max_pitch isn't a multiple of 4, do non-unrolled version.
for (; i < max_pitch; i++) {
renamenoise_val32 sum;
sum = renamenoise_inner_prod(_x, _y + i, len);
xcorr[i] = sum;
}
}
void renamenoise_pitch_search(const renamenoise_val16 *x_lp, renamenoise_val16 *y, int len, int max_pitch, int *pitch) {
int i, j;
int lag;
int best_pitch[2] = {0, 0};
int offset;
renamenoise_assert(len > 0);
renamenoise_assert(max_pitch > 0);
lag = len + max_pitch;
renamenoise_stackalloc(renamenoise_val16, x_lp4, len >> 2);
renamenoise_stackalloc(renamenoise_val16, y_lp4, lag >> 2);
renamenoise_stackalloc(renamenoise_val32, xcorr, max_pitch >> 1);
// Downsample by 2 again
for (j = 0; j < (len >> 2); j++) {
x_lp4[j] = x_lp[2 * j];
}
for (j = 0; j < (lag >> 2); j++) {
y_lp4[j] = y[2 * j];
}
// Coarse search with 4x decimation
renamenoise_pitch_xcorr(x_lp4, y_lp4, xcorr, len >> 2, max_pitch >> 2);
renamenoise_find_best_pitch(xcorr, y_lp4, len >> 2, max_pitch >> 2, best_pitch);
// Finer search with 2x decimation
for (i = 0; i < (max_pitch >> 1); i++) {
renamenoise_val32 sum;
xcorr[i] = 0;
if (abs(i - 2 * best_pitch[0]) > 2 && abs(i - 2 * best_pitch[1]) > 2) {
continue;
}
sum = renamenoise_inner_prod(x_lp, y + i, len >> 1);
xcorr[i] = RENAMENOISE_MAX32(-1, sum);
}
renamenoise_find_best_pitch(xcorr, y, len >> 1, max_pitch >> 1, best_pitch);
// Refine by pseudo-interpolation
if (best_pitch[0] > 0 && best_pitch[0] < (max_pitch >> 1) - 1) {
renamenoise_val32 a, b, c;
a = xcorr[best_pitch[0] - 1];
b = xcorr[best_pitch[0]];
c = xcorr[best_pitch[0] + 1];
if ((c - a) > RENAMENOISE_MULT(.7f, b - a)) {
offset = 1;
} else if ((a - c) > RENAMENOISE_MULT(.7f, b - c)) {
offset = -1;
} else {
offset = 0;
}
} else {
offset = 0;
}
*pitch = 2 * best_pitch[0] - offset;
}
static renamenoise_val16 renamenoise_compute_pitch_gain(renamenoise_val32 xy, renamenoise_val32 xx, renamenoise_val32 yy) {
return xy / sqrt(1 + xx * yy);
}
static const int renamenoise_second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
renamenoise_val16 renamenoise_remove_doubling(renamenoise_val16 *x, int maxperiod, int minperiod, int N, int *T0_, int prev_period,
renamenoise_val16 prev_gain) {
int k, i, T, T0;
renamenoise_val16 g, g0;
renamenoise_val16 pg;
renamenoise_val32 xy, xx, yy, xy2;
renamenoise_val32 xcorr[3];
renamenoise_val32 best_xy, best_yy;
int offset;
int minperiod0;
minperiod0 = minperiod;
maxperiod /= 2;
minperiod /= 2;
*T0_ /= 2;
prev_period /= 2;
N /= 2;
x += maxperiod;
if (*T0_ >= maxperiod) {
*T0_ = maxperiod - 1;
}
T = T0 = *T0_;
renamenoise_stackalloc(renamenoise_val32, yy_lookup, maxperiod + 1);
renamenoise_dual_inner_prod(x, x, x - T0, N, &xx, &xy);
yy_lookup[0] = xx;
yy = xx;
for (i = 1; i <= maxperiod; i++) {
yy = yy + RENAMENOISE_MULT(x[-i], x[-i]) - RENAMENOISE_MULT(x[N - i], x[N - i]);
yy_lookup[i] = RENAMENOISE_MAX32(0, yy);
}
yy = yy_lookup[T0];
best_xy = xy;
best_yy = yy;
g = g0 = renamenoise_compute_pitch_gain(xy, xx, yy);
// Look for any pitch at T/k
for (k = 2; k <= 15; k++) {
int T1, T1b;
renamenoise_val16 g1;
renamenoise_val16 cont = 0;
renamenoise_val16 thresh;
T1 = (2 * T0 + k) / (2 * k);
if (T1 < minperiod) {
break;
}
// Look for another strong correlation at T1b
if (k == 2) {
if (T1 + T0 > maxperiod) {
T1b = T0;
} else {
T1b = T0 + T1;
}
} else {
T1b = (2 * renamenoise_second_check[k] * T0 + k) / (2 * k);
}
renamenoise_dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2);
xy = RENAMENOISE_HALF(xy + xy2);
yy = RENAMENOISE_HALF(yy_lookup[T1] + yy_lookup[T1b]);
g1 = renamenoise_compute_pitch_gain(xy, xx, yy);
if (abs(T1 - prev_period) <= 1) {
cont = prev_gain;
} else if (abs(T1 - prev_period) <= 2 && 5 * k * k < T0) {
cont = RENAMENOISE_HALF(prev_gain);
} else {
cont = 0;
}
thresh = RENAMENOISE_MAX16(.3f, RENAMENOISE_MULT(.7f, g0) - cont);
// Bias against very high pitch (very short period) to avoid false-positives due to short-term correlation
if (T1 < 3 * minperiod) {
thresh = RENAMENOISE_MAX16(.4f, RENAMENOISE_MULT(.85f, g0) - cont);
} else if (T1 < 2 * minperiod) {
thresh = RENAMENOISE_MAX16(.5f, RENAMENOISE_MULT(.9f, g0) - cont);
}
if (g1 > thresh) {
best_xy = xy;
best_yy = yy;
T = T1;
g = g1;
}
}
best_xy = RENAMENOISE_MAX32(0, best_xy);
if (best_yy <= best_xy) {
pg = RENAMENOISE_Q15ONE;
} else {
pg = best_xy / (best_yy + 1);
}
for (k = 0; k < 3; k++) {
xcorr[k] = renamenoise_inner_prod(x, x - (T + k - 1), N);
}
if ((xcorr[2] - xcorr[0]) > RENAMENOISE_MULT(.7f, xcorr[1] - xcorr[0])) {
offset = 1;
} else if ((xcorr[0] - xcorr[2]) > RENAMENOISE_MULT(.7f, xcorr[1] - xcorr[2])) {
offset = -1;
} else {
offset = 0;
}
if (pg > g) {
pg = g;
}
*T0_ = 2 * T + offset;
if (*T0_ < minperiod0) {
*T0_ = minperiod0;
}
return pg;
}

137
thirdparty/renamenoise/src/pitch.h vendored Normal file
View file

@ -0,0 +1,137 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2007-2009, Xiph.Org Foundation
Copyright (c) 2007-2008, CSIRO
Copyright (c) 2003-2008, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@file pitch.h
@brief Pitch analysis
*/
#ifndef PITCH_H
#define PITCH_H
#include "arch.h"
void renamenoise_pitch_downsample(renamenoise_sig *x[], renamenoise_val16 *x_lp, int len, int C);
void renamenoise_pitch_search(const renamenoise_val16 *x_lp, renamenoise_val16 *y, int len, int max_pitch, int *pitch);
renamenoise_val16 renamenoise_remove_doubling(renamenoise_val16 *x, int maxperiod, int minperiod, int N, int *T0, int prev_period,
renamenoise_val16 prev_gain);
// OPT: This is the kernel you really want to optimize. It gets used a lot by the prefilter and by the PLC.
static RENAMENOISE_INLINE void renamenoise_xcorr_kernel(const renamenoise_val16 *x, const renamenoise_val16 *y, renamenoise_val32 sum[4], int len) {
int j;
renamenoise_val16 y_0, y_1, y_2, y_3;
renamenoise_assert(len >= 3);
y_3 = 0; /* gcc doesn't realize that y_3 can't be used uninitialized */
y_0 = *y++;
y_1 = *y++;
y_2 = *y++;
for (j = 0; j < len - 3; j += 4) {
renamenoise_val16 tmp;
tmp = *x++;
y_3 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_0);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_1);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_2);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_3);
tmp = *x++;
y_0 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_1);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_2);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_3);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_0);
tmp = *x++;
y_1 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_2);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_3);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_0);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_1);
tmp = *x++;
y_2 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_3);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_0);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_1);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_2);
}
if (j++ < len) {
renamenoise_val16 tmp = *x++;
y_3 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_0);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_1);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_2);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_3);
}
if (j++ < len) {
renamenoise_val16 tmp = *x++;
y_0 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_1);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_2);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_3);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_0);
}
if (j < len) {
renamenoise_val16 tmp = *x++;
y_1 = *y++;
sum[0] = RENAMENOISE_MAC(sum[0], tmp, y_2);
sum[1] = RENAMENOISE_MAC(sum[1], tmp, y_3);
sum[2] = RENAMENOISE_MAC(sum[2], tmp, y_0);
sum[3] = RENAMENOISE_MAC(sum[3], tmp, y_1);
}
}
static RENAMENOISE_INLINE void renamenoise_dual_inner_prod(const renamenoise_val16 *x, const renamenoise_val16 *y01, const renamenoise_val16 *y02,
int N, renamenoise_val32 *xy1, renamenoise_val32 *xy2) {
int i;
renamenoise_val32 xy01 = 0;
renamenoise_val32 xy02 = 0;
for (i = 0; i < N; i++) {
xy01 = RENAMENOISE_MAC(xy01, x[i], y01[i]);
xy02 = RENAMENOISE_MAC(xy02, x[i], y02[i]);
}
*xy1 = xy01;
*xy2 = xy02;
}
// We make sure a C version is always available for cases where the overhead of vectorization and passing around an arch flag aren't worth it.
static RENAMENOISE_INLINE renamenoise_val32 renamenoise_inner_prod(const renamenoise_val16 *x, const renamenoise_val16 *y, int N) {
int i;
renamenoise_val32 xy = 0;
for (i = 0; i < N; i++) {
xy = RENAMENOISE_MAC(xy, x[i], y[i]);
}
return xy;
}
void renamenoise_pitch_xcorr(const renamenoise_val16 *_x, const renamenoise_val16 *_y, renamenoise_val32 *xcorr, int len, int max_pitch);
#endif /* PITCH_H */

View file

@ -0,0 +1,471 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2008, Xiph.Org Foundation, CSIRO
Copyright (c) 2005-2007, Xiph.Org Foundation
Lots of modifications by Jean-Marc Valin
Copyright (c) 2003-2004, Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Lots of modifications by Jean-Marc Valin. This code is originally from Mark
// Borgerding's KISS-FFT but has been heavily modified to better suit Opus and
// was subsequently refactored for ReNameNoise
#ifndef SKIP_CONFIG_H
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
#endif
#include "_renamenoise_fft_guts.h"
// The guts header contains all the multiplication and addition macros that are
// defined for complex numbers. It also declares the kf_ internal functions.
static void renamenoise_kf_bfly2(renamenoise_fft_cpx *Fout, int m, int N) {
renamenoise_fft_cpx *Fout2;
int i;
(void) m;
if (m == 1) {
renamenoise_assert(m == 1);
for (i = 0; i < N; i++) {
renamenoise_fft_cpx t;
Fout2 = Fout + 1;
t = *Fout2;
RENAMENOISE_C_SUB(*Fout2, *Fout, t);
RENAMENOISE_C_ADDTO(*Fout, t);
Fout += 2;
}
} else {
renamenoise_val16 tw;
tw = 0.7071067812f;
// We know that m==4 here because the radix-2 is just after a radix-4
renamenoise_assert(m == 4);
for (i = 0; i < N; i++) {
renamenoise_fft_cpx t;
Fout2 = Fout + 4;
t = Fout2[0];
RENAMENOISE_C_SUB(Fout2[0], Fout[0], t);
RENAMENOISE_C_ADDTO(Fout[0], t);
t.r = RENAMENOISE_S_MUL(RENAMENOISE_ADD(Fout2[1].r, Fout2[1].i), tw);
t.i = RENAMENOISE_S_MUL(RENAMENOISE_SUB(Fout2[1].i, Fout2[1].r), tw);
RENAMENOISE_C_SUB(Fout2[1], Fout[1], t);
RENAMENOISE_C_ADDTO(Fout[1], t);
t.r = Fout2[2].i;
t.i = -Fout2[2].r;
RENAMENOISE_C_SUB(Fout2[2], Fout[2], t);
RENAMENOISE_C_ADDTO(Fout[2], t);
t.r = RENAMENOISE_S_MUL(RENAMENOISE_SUB(Fout2[3].i, Fout2[3].r), tw);
t.i = RENAMENOISE_S_MUL(-RENAMENOISE_ADD(Fout2[3].i, Fout2[3].r), tw);
RENAMENOISE_C_SUB(Fout2[3], Fout[3], t);
RENAMENOISE_C_ADDTO(Fout[3], t);
Fout += 8;
}
}
}
static void renamenoise_kf_bfly4(renamenoise_fft_cpx *Fout, const size_t fstride, const renamenoise_fft_state *st, int m, int N, int mm) {
int i;
if (m == 1) {
// Degenerate case where all the twiddles are 1.
for (i = 0; i < N; i++) {
renamenoise_fft_cpx scratch0, scratch1;
RENAMENOISE_C_SUB(scratch0, *Fout, Fout[2]);
RENAMENOISE_C_ADDTO(*Fout, Fout[2]);
RENAMENOISE_C_ADD(scratch1, Fout[1], Fout[3]);
RENAMENOISE_C_SUB(Fout[2], *Fout, scratch1);
RENAMENOISE_C_ADDTO(*Fout, scratch1);
RENAMENOISE_C_SUB(scratch1, Fout[1], Fout[3]);
Fout[1].r = RENAMENOISE_ADD(scratch0.r, scratch1.i);
Fout[1].i = RENAMENOISE_SUB(scratch0.i, scratch1.r);
Fout[3].r = RENAMENOISE_SUB(scratch0.r, scratch1.i);
Fout[3].i = RENAMENOISE_ADD(scratch0.i, scratch1.r);
Fout += 4;
}
} else {
int j;
renamenoise_fft_cpx scratch[6];
const renamenoise_twiddle_cpx *tw1, *tw2, *tw3;
const int m2 = 2 * m;
const int m3 = 3 * m;
renamenoise_fft_cpx *Fout_beg = Fout;
for (i = 0; i < N; i++) {
Fout = Fout_beg + i * mm;
tw3 = tw2 = tw1 = st->twiddles;
// m is guaranteed to be a multiple of 4.
for (j = 0; j < m; j++) {
RENAMENOISE_C_MUL(scratch[0], Fout[m], *tw1);
RENAMENOISE_C_MUL(scratch[1], Fout[m2], *tw2);
RENAMENOISE_C_MUL(scratch[2], Fout[m3], *tw3);
RENAMENOISE_C_SUB(scratch[5], *Fout, scratch[1]);
RENAMENOISE_C_ADDTO(*Fout, scratch[1]);
RENAMENOISE_C_ADD(scratch[3], scratch[0], scratch[2]);
RENAMENOISE_C_SUB(scratch[4], scratch[0], scratch[2]);
RENAMENOISE_C_SUB(Fout[m2], *Fout, scratch[3]);
tw1 += fstride;
tw2 += fstride * 2;
tw3 += fstride * 3;
RENAMENOISE_C_ADDTO(*Fout, scratch[3]);
Fout[m].r = RENAMENOISE_ADD(scratch[5].r, scratch[4].i);
Fout[m].i = RENAMENOISE_SUB(scratch[5].i, scratch[4].r);
Fout[m3].r = RENAMENOISE_SUB(scratch[5].r, scratch[4].i);
Fout[m3].i = RENAMENOISE_ADD(scratch[5].i, scratch[4].r);
++Fout;
}
}
}
}
static void renamenoise_kf_bfly3(renamenoise_fft_cpx *Fout, const size_t fstride, const renamenoise_fft_state *st, int m, int N, int mm) {
int i;
size_t k;
const size_t m2 = 2 * m;
const renamenoise_twiddle_cpx *tw1, *tw2;
renamenoise_fft_cpx scratch[5];
renamenoise_twiddle_cpx epi3;
renamenoise_fft_cpx *Fout_beg = Fout;
epi3 = st->twiddles[fstride * m];
for (i = 0; i < N; i++) {
Fout = Fout_beg + i * mm;
tw1 = tw2 = st->twiddles;
// For non-custom modes, m is guaranteed to be a multiple of 4.
k = m;
do {
RENAMENOISE_C_MUL(scratch[1], Fout[m], *tw1);
RENAMENOISE_C_MUL(scratch[2], Fout[m2], *tw2);
RENAMENOISE_C_ADD(scratch[3], scratch[1], scratch[2]);
RENAMENOISE_C_SUB(scratch[0], scratch[1], scratch[2]);
tw1 += fstride;
tw2 += fstride * 2;
Fout[m].r = RENAMENOISE_SUB(Fout->r, RENAMENOISE_HALF(scratch[3].r));
Fout[m].i = RENAMENOISE_SUB(Fout->i, RENAMENOISE_HALF(scratch[3].i));
RENAMENOISE_C_MULBYSCALAR(scratch[0], epi3.i);
RENAMENOISE_C_ADDTO(*Fout, scratch[3]);
Fout[m2].r = RENAMENOISE_ADD(Fout[m].r, scratch[0].i);
Fout[m2].i = RENAMENOISE_SUB(Fout[m].i, scratch[0].r);
Fout[m].r = RENAMENOISE_SUB(Fout[m].r, scratch[0].i);
Fout[m].i = RENAMENOISE_ADD(Fout[m].i, scratch[0].r);
++Fout;
} while (--k);
}
}
static void renamenoise_kf_bfly5(renamenoise_fft_cpx *Fout, const size_t fstride, const renamenoise_fft_state *st, int m, int N, int mm) {
renamenoise_fft_cpx *Fout0, *Fout1, *Fout2, *Fout3, *Fout4;
int i, u;
renamenoise_fft_cpx scratch[13];
const renamenoise_twiddle_cpx *tw;
renamenoise_twiddle_cpx ya, yb;
renamenoise_fft_cpx *Fout_beg = Fout;
ya = st->twiddles[fstride * m];
yb = st->twiddles[fstride * 2 * m];
tw = st->twiddles;
for (i = 0; i < N; i++) {
Fout = Fout_beg + i * mm;
Fout0 = Fout;
Fout1 = Fout0 + m;
Fout2 = Fout0 + 2 * m;
Fout3 = Fout0 + 3 * m;
Fout4 = Fout0 + 4 * m;
// For non-custom modes, m is guaranteed to be a multiple of 4.
for (u = 0; u < m; ++u) {
scratch[0] = *Fout0;
RENAMENOISE_C_MUL(scratch[1], *Fout1, tw[u * fstride]);
RENAMENOISE_C_MUL(scratch[2], *Fout2, tw[2 * u * fstride]);
RENAMENOISE_C_MUL(scratch[3], *Fout3, tw[3 * u * fstride]);
RENAMENOISE_C_MUL(scratch[4], *Fout4, tw[4 * u * fstride]);
RENAMENOISE_C_ADD(scratch[7], scratch[1], scratch[4]);
RENAMENOISE_C_SUB(scratch[10], scratch[1], scratch[4]);
RENAMENOISE_C_ADD(scratch[8], scratch[2], scratch[3]);
RENAMENOISE_C_SUB(scratch[9], scratch[2], scratch[3]);
Fout0->r = RENAMENOISE_ADD(Fout0->r, RENAMENOISE_ADD(scratch[7].r, scratch[8].r));
Fout0->i = RENAMENOISE_ADD(Fout0->i, RENAMENOISE_ADD(scratch[7].i, scratch[8].i));
scratch[5].r =
RENAMENOISE_ADD(scratch[0].r, RENAMENOISE_ADD(RENAMENOISE_S_MUL(scratch[7].r, ya.r), RENAMENOISE_S_MUL(scratch[8].r, yb.r)));
scratch[5].i =
RENAMENOISE_ADD(scratch[0].i, RENAMENOISE_ADD(RENAMENOISE_S_MUL(scratch[7].i, ya.r), RENAMENOISE_S_MUL(scratch[8].i, yb.r)));
scratch[6].r = RENAMENOISE_ADD(RENAMENOISE_S_MUL(scratch[10].i, ya.i), RENAMENOISE_S_MUL(scratch[9].i, yb.i));
scratch[6].i = -RENAMENOISE_ADD(RENAMENOISE_S_MUL(scratch[10].r, ya.i), RENAMENOISE_S_MUL(scratch[9].r, yb.i));
RENAMENOISE_C_SUB(*Fout1, scratch[5], scratch[6]);
RENAMENOISE_C_ADD(*Fout4, scratch[5], scratch[6]);
scratch[11].r =
RENAMENOISE_ADD(scratch[0].r, RENAMENOISE_ADD(RENAMENOISE_S_MUL(scratch[7].r, yb.r), RENAMENOISE_S_MUL(scratch[8].r, ya.r)));
scratch[11].i =
RENAMENOISE_ADD(scratch[0].i, RENAMENOISE_ADD(RENAMENOISE_S_MUL(scratch[7].i, yb.r), RENAMENOISE_S_MUL(scratch[8].i, ya.r)));
scratch[12].r = RENAMENOISE_SUB(RENAMENOISE_S_MUL(scratch[9].i, ya.i), RENAMENOISE_S_MUL(scratch[10].i, yb.i));
scratch[12].i = RENAMENOISE_SUB(RENAMENOISE_S_MUL(scratch[10].r, yb.i), RENAMENOISE_S_MUL(scratch[9].r, ya.i));
RENAMENOISE_C_ADD(*Fout2, scratch[11], scratch[12]);
RENAMENOISE_C_SUB(*Fout3, scratch[11], scratch[12]);
++Fout0;
++Fout1;
++Fout2;
++Fout3;
++Fout4;
}
}
}
static void renamenoise_compute_bitrev_table(int Fout, renamenoise_int16 *f, const size_t fstride, int in_stride, renamenoise_int16 *factors,
const renamenoise_fft_state *st) {
const int p = *factors++; // the radix
const int m = *factors++; // stage's fft length/p
if (m == 1) {
int j;
for (j = 0; j < p; j++) {
*f = Fout + j;
f += fstride * in_stride;
}
} else {
int j;
for (j = 0; j < p; j++) {
renamenoise_compute_bitrev_table(Fout, f, fstride * p, in_stride, factors, st);
f += fstride * in_stride;
Fout += m;
}
}
}
// facbuf is populated by p1,m1,p2,m2, ...
// where
// p[i] * m[i] = m[i-1]
// m0 = n
static int renamenoise_kf_factor(int n, renamenoise_int16 *facbuf) {
int p = 4;
int i;
int stages = 0;
int nbak = n;
// factor out powers of 4, powers of 2, then any remaining primes
do {
while (n % p) {
switch (p) {
case 4: p = 2; break;
case 2: p = 3; break;
default: p += 2; break;
}
if (p > 32000 || (renamenoise_int32) p * (renamenoise_int32) p > n) {
p = n; // no more factors, skip to end
}
}
n /= p;
if (p > 5) {
return 0;
}
facbuf[2 * stages] = p;
if (p == 2 && stages > 1) {
facbuf[2 * stages] = 4;
facbuf[2] = 2;
}
stages++;
} while (n > 1);
n = nbak;
// Reverse the order to get the radix 4 at the end, so we can use the
// fast degenerate case. It turns out that reversing the order also
// improves the noise behaviour.
for (i = 0; i < stages / 2; i++) {
int tmp;
tmp = facbuf[2 * i];
facbuf[2 * i] = facbuf[2 * (stages - i - 1)];
facbuf[2 * (stages - i - 1)] = tmp;
}
for (i = 0; i < stages; i++) {
n /= facbuf[2 * i];
facbuf[2 * i + 1] = n;
}
return 1;
}
static void renamenoise_compute_twiddles(renamenoise_twiddle_cpx *twiddles, int nfft) {
int i;
for (i = 0; i < nfft; ++i) {
double phase = (-2 * M_PI / nfft) * i;
renamenoise_kf_cexp(twiddles + i, phase);
}
}
int renamenoise_fft_alloc_arch_c(renamenoise_fft_state *st) {
(void) st;
return 0;
}
/**
* Allocates all necessary storage space for the fft and ifft.
* The return value is a contiguous block of memory. As such,
* It can be freed with free().
*/
renamenoise_fft_state *renamenoise_fft_alloc_twiddles(int nfft, void *mem, size_t *lenmem, const renamenoise_fft_state *base, int arch) {
renamenoise_fft_state *st = NULL;
size_t memneeded = sizeof(struct renamenoise_fft_state); // twiddle factors
if (lenmem == NULL) {
st = (renamenoise_fft_state *) RENAMENOISE_FFT_MALLOC(memneeded);
} else {
if (mem != NULL && *lenmem >= memneeded) {
st = (renamenoise_fft_state *) mem;
}
*lenmem = memneeded;
}
if (st) {
renamenoise_int16 *bitrev;
renamenoise_twiddle_cpx *twiddles;
st->nfft = nfft;
st->scale = 1.f / nfft;
if (base != NULL) {
st->twiddles = base->twiddles;
st->shift = 0;
while (st->shift < 32 && nfft << st->shift != base->nfft) {
st->shift++;
}
if (st->shift >= 32) {
goto fail;
}
} else {
st->twiddles = twiddles = (renamenoise_twiddle_cpx *) RENAMENOISE_FFT_MALLOC(sizeof(renamenoise_twiddle_cpx) * nfft);
renamenoise_compute_twiddles(twiddles, nfft);
st->shift = -1;
}
if (!renamenoise_kf_factor(nfft, st->factors)) {
goto fail;
}
// bitrev
st->bitrev = bitrev = (renamenoise_int16 *) RENAMENOISE_FFT_MALLOC(sizeof(renamenoise_int16) * nfft);
if (st->bitrev == NULL) {
goto fail;
}
renamenoise_compute_bitrev_table(0, bitrev, 1, 1, st->factors, st);
// Initialize architecture specific fft parameters
if (renamenoise_fft_alloc_arch(st, arch)) {
goto fail;
}
}
return st;
fail:
renamenoise_fft_free(st, arch);
return NULL;
}
renamenoise_fft_state *renamenoise_fft_alloc(int nfft, void *mem, size_t *lenmem, int arch) {
return renamenoise_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch);
}
void renamenoise_fft_free_arch_c(renamenoise_fft_state *st) {
(void) st;
}
void renamenoise_fft_free(const renamenoise_fft_state *cfg, int arch) {
if (cfg) {
renamenoise_fft_free_arch((renamenoise_fft_state *) cfg, arch);
renamenoise_free2((renamenoise_int16 *) cfg->bitrev);
if (cfg->shift < 0) {
renamenoise_free2((renamenoise_twiddle_cpx *) cfg->twiddles);
}
renamenoise_free2((renamenoise_fft_state *) cfg);
}
}
void renamenoise_fft_impl(const renamenoise_fft_state *st, renamenoise_fft_cpx *fout) {
int m2, m;
int p;
int L;
int fstride[RENAMENOISE_MAXFACTORS];
int i;
int shift;
// st->shift can be -1
shift = st->shift > 0 ? st->shift : 0;
fstride[0] = 1;
L = 0;
do {
p = st->factors[2 * L];
m = st->factors[2 * L + 1];
fstride[L + 1] = fstride[L] * p;
L++;
} while (m != 1);
m = st->factors[2 * L - 1];
for (i = L - 1; i >= 0; i--) {
if (i != 0) {
m2 = st->factors[2 * i - 1];
} else {
m2 = 1;
}
switch (st->factors[2 * i]) {
case 2: renamenoise_kf_bfly2(fout, m, fstride[i]); break;
case 4: renamenoise_kf_bfly4(fout, fstride[i] << shift, st, m, fstride[i], m2); break;
case 3: renamenoise_kf_bfly3(fout, fstride[i] << shift, st, m, fstride[i], m2); break;
case 5: renamenoise_kf_bfly5(fout, fstride[i] << shift, st, m, fstride[i], m2); break;
}
m = m2;
}
}
void renamenoise_fft_c(const renamenoise_fft_state *st, const renamenoise_fft_cpx *fin, renamenoise_fft_cpx *fout) {
int i;
renamenoise_val16 scale;
scale = st->scale;
renamenoise_assert2(fin != fout, "In-place FFT not supported");
// Bit-reverse the input
for (i = 0; i < st->nfft; i++) {
renamenoise_fft_cpx x = fin[i];
fout[st->bitrev[i]].r = RENAMENOISE_MULT(scale, x.r);
fout[st->bitrev[i]].i = RENAMENOISE_MULT(scale, x.i);
}
renamenoise_fft_impl(st, fout);
}

View file

@ -0,0 +1,150 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2008, Xiph.Org Foundation, CSIRO
Copyright (c) 2005-2007, Xiph.Org Foundation
Lots of modifications by Jean-Marc Valin
Copyright (c) 2003-2004, Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RENAMENOISE_FFT_H
#define RENAMENOISE_FFT_H
#include "arch.h"
#include <math.h>
#include <stdlib.h>
#define renamenoise_alloc2(x) malloc(x)
#define renamenoise_free2(x) free(x)
#ifdef __cplusplus
extern "C" {
#endif
#define RENAMENOISE_FFT_MALLOC renamenoise_alloc2
#ifndef renamenoise_fft_scalar
// default is float
# define renamenoise_fft_scalar float
# define renamenoise_twiddle_scalar float
#endif
typedef struct {
renamenoise_fft_scalar r;
renamenoise_fft_scalar i;
} renamenoise_fft_cpx;
typedef struct {
renamenoise_twiddle_scalar r;
renamenoise_twiddle_scalar i;
} renamenoise_twiddle_cpx;
#define RENAMENOISE_MAXFACTORS 8
// e.g. an fft of length 128 has 4 factors
// as far as renamenoisefft is concerned
// 4*4*4*2
typedef struct renamenoise_arch_fft_state {
int is_supported;
void *priv;
} renamenoise_arch_fft_state;
typedef struct renamenoise_fft_state {
int nfft;
renamenoise_val16 scale;
int shift;
renamenoise_int16 factors[2 * RENAMENOISE_MAXFACTORS];
const renamenoise_int16 *bitrev;
const renamenoise_twiddle_cpx *twiddles;
renamenoise_arch_fft_state *arch_fft;
} renamenoise_fft_state;
// typedef struct renamenoise_fft_state* renamenoise_fft_cfg;
/**
* renamenoise_fft_alloc
*
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
*
* typical usage: renamenoise_fft_cfg
* mycfg=renamenoise_fft_alloc(1024,0,NULL,NULL);
*
* The return value from fft_alloc is a cfg buffer used internally
* by the fft routine or NULL.
*
* If lenmem is NULL, then renamenoise_fft_alloc will allocate a cfg buffer
* using malloc. The returned value should be free()d when done to avoid memory
* leaks.
*
* The state can be placed in a user supplied buffer 'mem':
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
* then the function places the cfg in mem and the size used in *lenmem
* and returns mem.
*
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
* then the function returns NULL and places the minimum cfg
* buffer size in *lenmem.
*/
renamenoise_fft_state *renamenoise_fft_alloc_twiddles(int nfft, void *mem, size_t *lenmem, const renamenoise_fft_state *base, int arch);
renamenoise_fft_state *renamenoise_fft_alloc(int nfft, void *mem, size_t *lenmem, int arch);
/**
* renamenoise_fft(cfg,in_out_buf)
*
* Perform an FFT on a complex input buffer.
* for a forward FFT,
* fin should be f[0] , f[1] , ... ,f[nfft-1]
* fout will be F[0] , F[1] , ... ,F[nfft-1]
* Note that each element is complex and can be accessed like
* f[k].r and f[k].i
*/
void renamenoise_fft_c(const renamenoise_fft_state *cfg, const renamenoise_fft_cpx *fin, renamenoise_fft_cpx *fout);
void renamenoise_fft_impl(const renamenoise_fft_state *st, renamenoise_fft_cpx *fout);
void renamenoise_fft_free(const renamenoise_fft_state *cfg, int arch);
void renamenoise_fft_free_arch_c(renamenoise_fft_state *st);
int renamenoise_fft_alloc_arch_c(renamenoise_fft_state *st);
#if !defined(OVERRIDE_RENAMENOISE_FFT)
# define renamenoise_fft_alloc_arch(_st, arch) ((void) (arch), renamenoise_fft_alloc_arch_c(_st))
# define renamenoise_fft_free_arch(_st, arch) ((void) (arch), renamenoise_fft_free_arch_c(_st))
# define renamenoise_fft(_cfg, _fin, _fout, arch) ((void) (arch), renamenoise_fft_c(_cfg, _fin, _fout))
#endif /* end if !defined(OVERRIDE_RENAMENOISE_FFT) */
#ifdef __cplusplus
}
#endif
#endif /* RENAMENOISE_FFT_H */

View file

@ -0,0 +1,111 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2009-2010, Xiph.Org Foundation, Written by Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "renamenoise_lpc.h"
#include "arch.h"
#include "common.h"
#include "pitch.h"
void _renamenoise_lpc(renamenoise_val16 *_lpc, // out: [0...p-1] LPC coefficients
const renamenoise_val32 *ac, // in: [0...p] autocorrelation values
int p) {
int i, j;
renamenoise_val32 r;
renamenoise_val32 error = ac[0];
float *lpc = _lpc;
RENAMENOISE_CLEAR(lpc, p);
if (ac[0] != 0) {
for (i = 0; i < p; i++) {
// Sum up this iteration's reflection coefficient
renamenoise_val32 rr = 0;
for (j = 0; j < i; j++) {
rr += RENAMENOISE_MULT(lpc[j], ac[i - j]);
}
rr += ac[i + 1];
r = -rr / error;
// Update LPC coefficients and total error
lpc[i] = r;
for (j = 0; j < ((i + 1) >> 1); j++) {
renamenoise_val32 tmp1, tmp2;
tmp1 = lpc[j];
tmp2 = lpc[i - 1 - j];
lpc[j] = tmp1 + RENAMENOISE_MULT(r, tmp2);
lpc[i - 1 - j] = tmp2 + RENAMENOISE_MULT(r, tmp1);
}
error = error - RENAMENOISE_MULT(RENAMENOISE_MULT(r, r), error);
// Bail out once we get 30 dB gain
if (error < .001f * ac[0]) {
break;
}
}
}
}
int _renamenoise_autocorr(const renamenoise_val16 *x, // in: [0...n-1] samples x
renamenoise_val32 *ac, // out: [0...lag-1] ac values
const renamenoise_val16 *window, int overlap, int lag, int n) {
renamenoise_val32 d;
int i, k;
int fastN = n - lag;
int shift;
const renamenoise_val16 *xptr;
renamenoise_stackalloc(renamenoise_val16, xx, n);
renamenoise_assert(n > 0);
renamenoise_assert(overlap >= 0);
if (overlap == 0) {
xptr = x;
} else {
for (i = 0; i < n; i++) {
xx[i] = x[i];
}
for (i = 0; i < overlap; i++) {
xx[i] = RENAMENOISE_MULT(x[i], window[i]);
xx[n - i - 1] = RENAMENOISE_MULT(x[n - i - 1], window[i]);
}
xptr = xx;
}
shift = 0;
renamenoise_pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
for (k = 0; k <= lag; k++) {
for (i = k + fastN, d = 0; i < n; i++) {
d = RENAMENOISE_MAC(d, xptr[i], xptr[i - k]);
}
ac[k] += d;
}
return shift;
}

View file

@ -0,0 +1,41 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2009-2010, Xiph.Org Foundation, Written by Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RENAMENOISE_LPC_H
#define RENAMENOISE_LPC_H
#include "arch.h"
#include "common.h"
void _renamenoise_lpc(renamenoise_val16 *_lpc, const renamenoise_val32 *ac, int p);
int _renamenoise_autocorr(const renamenoise_val16 *x, renamenoise_val32 *ac, const renamenoise_val16 *window, int overlap, int lag, int n);
#endif /* RENAMENOISE_LPC_H */

View file

@ -0,0 +1,164 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 1994-2002, Xiph.Org Foundation, Modified by Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// renamenoise_types.h based on opus_types.h based on ogg_types.h from libogg
/**
@file renamenoise_types.h
@brief Reference implementation types
*/
#ifndef RENAMENOISE_TYPES_H
#define RENAMENOISE_TYPES_H
// Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h)
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \
|| (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined(HAVE_STDINT_H))
# include <stdint.h>
typedef int16_t renamenoise_int16;
typedef uint16_t renamenoise_uint16;
typedef int32_t renamenoise_int32;
typedef uint32_t renamenoise_uint32;
#elif defined(_WIN32)
# if defined(__CYGWIN__)
# include <_G_config.h>
typedef _G_int32_t renamenoise_int32;
typedef _G_uint32_t renamenoise_uint32;
typedef _G_int16 renamenoise_int16;
typedef _G_uint16 renamenoise_uint16;
# elif defined(__MINGW32__)
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
# elif defined(__MWERKS__)
typedef int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
# else
// MSVC/Borland
typedef __int32 renamenoise_int32;
typedef unsigned __int32 renamenoise_uint32;
typedef __int16 renamenoise_int16;
typedef unsigned __int16 renamenoise_uint16;
# endif
#elif defined(__MACOS__)
# include <sys/types.h>
typedef SInt16 renamenoise_int16;
typedef UInt16 renamenoise_uint16;
typedef SInt32 renamenoise_int32;
typedef UInt32 renamenoise_uint32;
#elif (defined(__APPLE__) && defined(__MACH__)) // MacOS X Framework build
# include <sys/types.h>
typedef int16_t renamenoise_int16;
typedef u_int16_t renamenoise_uint16;
typedef int32_t renamenoise_int32;
typedef u_int32_t renamenoise_uint32;
#elif defined(__BEOS__)
// Be
# include <inttypes.h>
typedef int16 renamenoise_int16;
typedef u_int16 renamenoise_uint16;
typedef int32_t renamenoise_int32;
typedef u_int32_t renamenoise_uint32;
#elif defined(__EMX__)
// OS/2 GCC
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
#elif defined(DJGPP)
// DJGPP
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
#elif defined(R5900)
// PS2 EE
typedef int renamenoise_int32;
typedef unsigned renamenoise_uint32;
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
#elif defined(__SYMBIAN32__)
// Symbian GCC
typedef signed short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef signed int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
#elif defined(CONFIG_TI_C54X) || defined(CONFIG_TI_C55X)
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef long renamenoise_int32;
typedef unsigned long renamenoise_uint32;
#elif defined(CONFIG_TI_C6X)
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
#else
// Give up, take a reasonable guess
typedef short renamenoise_int16;
typedef unsigned short renamenoise_uint16;
typedef int renamenoise_int32;
typedef unsigned int renamenoise_uint32;
#endif
#define renamenoise_int int // used for counters etc; at least 16 bits
#define renamenoise_int64 long long
#define renamenoise_int8 signed char
#define renamenoise_uint unsigned int // used for counters etc; at least 16 bits
#define renamenoise_uint64 unsigned long long
#define renamenoise_uint8 unsigned char
#endif /* RENAMENOISE_TYPES_H */

238
thirdparty/renamenoise/src/rnn.c vendored Normal file
View file

@ -0,0 +1,238 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2012-2017, Jean-Marc Valin
Copyright (c) 2008-2011, Octasic Inc
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "rnn.h"
#include "arch.h"
#include "common.h"
#include "renamenoise_types.h"
#include "rnn_data.h"
#include "tansig_table.h"
#include <math.h>
#include <stdio.h>
static RENAMENOISE_INLINE float renamenoise_tansig_approx(float x) {
int i;
float y, dy;
float sign = 1;
// Tests are reversed to catch NaNs
if (!(x < 8)) {
return 1;
}
if (!(x > -8)) {
return -1;
}
// Another check in case of -ffast-math
if (renamenoise_isnan(x)) {
return 0;
}
if (x < 0) {
x = -x;
sign = -1;
}
i = (int) floor(.5f + 25 * x);
x -= .04f * i;
y = renamenoise_tansig_table[i];
dy = 1 - y * y;
y = y + x * dy * (1 - y * x);
return sign * y;
}
static RENAMENOISE_INLINE float renamenoise_sigmoid_approx(float x) {
return .5 + .5 * renamenoise_tansig_approx(.5 * x);
}
static RENAMENOISE_INLINE float renamenoise_relu(float x) {
return x < 0 ? 0 : x;
}
static void renamenoise_faxpy(float *restrict a, const renamenoise_rnn_weight *restrict b, const int k, const float u) {
if (u == 0.0) {
return;
}
for (int idx = 0; idx < k; idx++) {
a[idx] += b[idx] * u;
}
}
static void renamenoise_faxpy2(float *restrict a, const renamenoise_rnn_weight *restrict b, const int k, const float u, const float u2) {
if (u == 0.0 || u2 == 0.0) {
return;
}
for (int idx = 0; idx < k; idx++) {
a[idx] += (b[idx] * u) * u2;
}
}
void renamenoise_compute_dense(const ReNameNoiseDenseLayer *layer, float *output, const float *input) {
int i, j;
int N, M;
M = layer->nb_inputs;
N = layer->nb_neurons;
const renamenoise_rnn_weight *ip = layer->input_weights;
// Compute update gate.
for (i = 0; i < N; i++) {
output[i] = layer->bias[i];
}
for (j = 0; j < M; j++, ip += N) {
renamenoise_faxpy(output, ip, N, input[j]);
}
if (layer->activation == RENAMENOISE_ACTIVATION_SIGMOID) {
for (i = 0; i < N; i++) {
output[i] = renamenoise_sigmoid_approx(RENAMENOISE_WEIGHTS_SCALE * output[i]);
}
} else if (layer->activation == RENAMENOISE_ACTIVATION_TANH) {
for (i = 0; i < N; i++) {
output[i] = renamenoise_tansig_approx(RENAMENOISE_WEIGHTS_SCALE * output[i]);
}
} else if (layer->activation == RENAMENOISE_ACTIVATION_RELU) {
for (i = 0; i < N; i++) {
output[i] = renamenoise_relu(RENAMENOISE_WEIGHTS_SCALE * output[i]);
}
} else {
renamenoise_unreachable();
}
}
void renamenoise_compute_gru(const ReNameNoiseGRULayer *gru, float *state, const float *input) {
int i, j;
int N, M;
int stride;
float z[RENAMENOISE_MAX_NEURONS];
float r[RENAMENOISE_MAX_NEURONS];
float h[RENAMENOISE_MAX_NEURONS];
M = gru->nb_inputs;
N = gru->nb_neurons;
stride = 3 * N;
const renamenoise_rnn_weight *ip = gru->input_weights;
const renamenoise_rnn_weight *rp = gru->recurrent_weights;
// Compute update gate.
for (i = 0; i < N; i++) {
z[i] = gru->bias[i];
}
for (j = 0; j < M; j++, ip += stride) {
renamenoise_faxpy(z, ip, N, input[j]);
}
for (j = 0; j < N; j++, rp += stride) {
renamenoise_faxpy(z, rp, N, state[j]);
}
for (i = 0; i < N; i++) {
z[i] = renamenoise_sigmoid_approx(RENAMENOISE_WEIGHTS_SCALE * z[i]);
}
// Compute reset gate.
for (i = 0; i < N; i++) {
r[i] = gru->bias[N + i];
}
ip = gru->input_weights + N;
rp = gru->recurrent_weights + N;
for (j = 0; j < M; j++, ip += stride) {
renamenoise_faxpy(r, ip, N, input[j]);
}
for (j = 0; j < N; j++, rp += stride) {
renamenoise_faxpy(r, rp, N, state[j]);
}
for (i = 0; i < N; i++) {
r[i] = renamenoise_sigmoid_approx(RENAMENOISE_WEIGHTS_SCALE * r[i]);
}
// Compute output.
for (i = 0; i < N; i++) {
h[i] = gru->bias[2 * N + i];
}
ip = gru->input_weights + 2 * N;
rp = gru->recurrent_weights + 2 * N;
for (j = 0; j < M; j++, ip += stride) {
renamenoise_faxpy(h, ip, N, input[j]);
}
for (j = 0; j < N; j++, rp += stride) {
renamenoise_faxpy2(h, rp, N, state[j], r[j]);
}
for (i = 0; i < N; i++) {
if (gru->activation == RENAMENOISE_ACTIVATION_SIGMOID) {
h[i] = renamenoise_sigmoid_approx(RENAMENOISE_WEIGHTS_SCALE * h[i]);
} else if (gru->activation == RENAMENOISE_ACTIVATION_TANH) {
h[i] = renamenoise_tansig_approx(RENAMENOISE_WEIGHTS_SCALE * h[i]);
} else if (gru->activation == RENAMENOISE_ACTIVATION_RELU) {
h[i] = renamenoise_relu(RENAMENOISE_WEIGHTS_SCALE * h[i]);
} else {
renamenoise_unreachable();
}
h[i] = z[i] * state[i] + (1 - z[i]) * h[i];
}
memcpy((void *) state, (void *) h, N * sizeof(float));
}
#define RENAMENOISE_INPUT_SIZE 42
void renamenoise_compute_rnn(ReNameNoiseRNNState *rnn, float *gains, float *vad, const float *input) {
int i;
float dense_out[RENAMENOISE_MAX_NEURONS];
float noise_input[RENAMENOISE_MAX_NEURONS * 3];
float denoise_input[RENAMENOISE_MAX_NEURONS * 3];
renamenoise_compute_dense(rnn->model->input_dense, dense_out, input);
renamenoise_compute_gru(rnn->model->vad_gru, rnn->vad_gru_state, dense_out);
renamenoise_compute_dense(rnn->model->vad_output, vad, rnn->vad_gru_state);
for (i = 0; i < rnn->model->input_dense_size; i++) {
noise_input[i] = dense_out[i];
}
for (i = 0; i < rnn->model->vad_gru_size; i++) {
noise_input[i + rnn->model->input_dense_size] = rnn->vad_gru_state[i];
}
for (i = 0; i < RENAMENOISE_INPUT_SIZE; i++) {
noise_input[i + rnn->model->input_dense_size + rnn->model->vad_gru_size] = input[i];
}
renamenoise_compute_gru(rnn->model->noise_gru, rnn->noise_gru_state, noise_input);
for (i = 0; i < rnn->model->vad_gru_size; i++) {
denoise_input[i] = rnn->vad_gru_state[i];
}
for (i = 0; i < rnn->model->noise_gru_size; i++) {
denoise_input[i + rnn->model->vad_gru_size] = rnn->noise_gru_state[i];
}
for (i = 0; i < RENAMENOISE_INPUT_SIZE; i++) {
denoise_input[i + rnn->model->vad_gru_size + rnn->model->noise_gru_size] = input[i];
}
renamenoise_compute_gru(rnn->model->denoise_gru, rnn->denoise_gru_state, denoise_input);
renamenoise_compute_dense(rnn->model->denoise_output, gains, rnn->denoise_gru_state);
}

72
thirdparty/renamenoise/src/rnn.h vendored Normal file
View file

@ -0,0 +1,72 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2017, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RNN_H_
#define RNN_H_
#include "renamenoise.h"
#include "renamenoise_types.h"
#define RENAMENOISE_WEIGHTS_SCALE (1.f / 256)
#define RENAMENOISE_MAX_NEURONS 128
#define RENAMENOISE_ACTIVATION_TANH 0
#define RENAMENOISE_ACTIVATION_SIGMOID 1
#define RENAMENOISE_ACTIVATION_RELU 2
typedef signed char renamenoise_rnn_weight;
typedef struct {
const renamenoise_rnn_weight *bias;
const renamenoise_rnn_weight *input_weights;
int nb_inputs;
int nb_neurons;
int activation;
} ReNameNoiseDenseLayer;
typedef struct {
const renamenoise_rnn_weight *bias;
const renamenoise_rnn_weight *input_weights;
const renamenoise_rnn_weight *recurrent_weights;
int nb_inputs;
int nb_neurons;
int activation;
} ReNameNoiseGRULayer;
typedef struct ReNameNoiseRNNState ReNameNoiseRNNState;
void renamenoise_compute_dense(const ReNameNoiseDenseLayer *layer, float *output, const float *input);
void renamenoise_compute_gru(const ReNameNoiseGRULayer *gru, float *state, const float *input);
void renamenoise_compute_rnn(ReNameNoiseRNNState *rnn, float *gains, float *vad, const float *input);
#endif /* RNN_H_ */

3735
thirdparty/renamenoise/src/rnn_data.c vendored Normal file

File diff suppressed because it is too large Load diff

63
thirdparty/renamenoise/src/rnn_data.h vendored Normal file
View file

@ -0,0 +1,63 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2017, Xiph.Org Foundation, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RNN_DATA_H
#define RNN_DATA_H
#include "rnn.h"
struct ReNameNoiseModel {
int input_dense_size;
const ReNameNoiseDenseLayer *input_dense;
int vad_gru_size;
const ReNameNoiseGRULayer *vad_gru;
int noise_gru_size;
const ReNameNoiseGRULayer *noise_gru;
int denoise_gru_size;
const ReNameNoiseGRULayer *denoise_gru;
int denoise_output_size;
const ReNameNoiseDenseLayer *denoise_output;
int vad_output_size;
const ReNameNoiseDenseLayer *vad_output;
};
struct ReNameNoiseRNNState {
const ReNameNoiseModel *model;
float *vad_gru_state;
float *noise_gru_state;
float *denoise_gru_state;
};
#endif /* RNN_DATA_H */

179
thirdparty/renamenoise/src/rnn_reader.c vendored Normal file
View file

@ -0,0 +1,179 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2018, Gregor Richards
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "renamenoise.h"
#include "rnn.h"
#include "rnn_data.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
// Although these values are the same as in rnn.h, we make them separate to
// avoid accidentally burning internal values into a file format
#define F_RENAMENOISE_ACTIVATION_TANH 0
#define F_RENAMENOISE_ACTIVATION_SIGMOID 1
#define F_RENAMENOISE_ACTIVATION_RELU 2
ReNameNoiseModel *renamenoise_model_from_file(FILE *f) {
int i, in;
if (fscanf(f, "renamenoise-nu model file version %d\n", &in) != 1 || in != 1) {
return NULL;
}
ReNameNoiseModel *ret = calloc(1, sizeof(ReNameNoiseModel));
if (!ret) {
return NULL;
}
#define RENAMENOISE_ALLOC_LAYER(type, name) \
type *name; \
name = calloc(1, sizeof(type)); \
if (!name) { \
renamenoise_model_free(ret); \
return NULL; \
} \
ret->name = name
RENAMENOISE_ALLOC_LAYER(ReNameNoiseDenseLayer, input_dense);
RENAMENOISE_ALLOC_LAYER(ReNameNoiseGRULayer, vad_gru);
RENAMENOISE_ALLOC_LAYER(ReNameNoiseGRULayer, noise_gru);
RENAMENOISE_ALLOC_LAYER(ReNameNoiseGRULayer, denoise_gru);
RENAMENOISE_ALLOC_LAYER(ReNameNoiseDenseLayer, denoise_output);
RENAMENOISE_ALLOC_LAYER(ReNameNoiseDenseLayer, vad_output);
#define RENAMENOISE_INPUT_VAL(name) \
do { \
if (fscanf(f, "%d", &in) != 1 || in < 0 || in > 128) { \
renamenoise_model_free(ret); \
return NULL; \
} \
name = in; \
} while (0)
#define RENAMENOISE_INPUT_ACTIVATION(name) \
do { \
int activation; \
RENAMENOISE_INPUT_VAL(activation); \
switch (activation) { \
case F_RENAMENOISE_ACTIVATION_SIGMOID: name = RENAMENOISE_ACTIVATION_SIGMOID; break; \
case F_RENAMENOISE_ACTIVATION_RELU: name = RENAMENOISE_ACTIVATION_RELU; break; \
default: name = RENAMENOISE_ACTIVATION_TANH; \
} \
} while (0)
#define RENAMENOISE_INPUT_ARRAY(name, len) \
do { \
renamenoise_rnn_weight *values = malloc((len) * sizeof(renamenoise_rnn_weight)); \
if (!values) { \
renamenoise_model_free(ret); \
return NULL; \
} \
name = values; \
for (i = 0; i < (len); i++) { \
if (fscanf(f, "%d", &in) != 1) { \
renamenoise_model_free(ret); \
return NULL; \
} \
values[i] = in; \
} \
} while (0)
#define RENAMENOISE_INPUT_DENSE(name) \
do { \
RENAMENOISE_INPUT_VAL(name->nb_inputs); \
RENAMENOISE_INPUT_VAL(name->nb_neurons); \
ret->name##_size = name->nb_neurons; \
RENAMENOISE_INPUT_ACTIVATION(name->activation); \
RENAMENOISE_INPUT_ARRAY(name->input_weights, name->nb_inputs * name->nb_neurons); \
RENAMENOISE_INPUT_ARRAY(name->bias, name->nb_neurons); \
} while (0)
#define RENAMENOISE_INPUT_GRU(name) \
do { \
RENAMENOISE_INPUT_VAL(name->nb_inputs); \
RENAMENOISE_INPUT_VAL(name->nb_neurons); \
ret->name##_size = name->nb_neurons; \
RENAMENOISE_INPUT_ACTIVATION(name->activation); \
RENAMENOISE_INPUT_ARRAY(name->input_weights, name->nb_inputs * name->nb_neurons * 3); \
RENAMENOISE_INPUT_ARRAY(name->recurrent_weights, name->nb_neurons * name->nb_neurons * 3); \
RENAMENOISE_INPUT_ARRAY(name->bias, name->nb_neurons * 3); \
} while (0)
RENAMENOISE_INPUT_DENSE(input_dense);
RENAMENOISE_INPUT_GRU(vad_gru);
RENAMENOISE_INPUT_GRU(noise_gru);
RENAMENOISE_INPUT_GRU(denoise_gru);
RENAMENOISE_INPUT_DENSE(denoise_output);
RENAMENOISE_INPUT_DENSE(vad_output);
return ret;
}
void renamenoise_model_free(ReNameNoiseModel *model) {
#define RENAMENOISE_FREE_MAYBE(ptr) \
do { \
if (ptr) \
free(ptr); \
} while (0)
#define RENAMENOISE_FREE_DENSE(name) \
do { \
if (model->name) { \
free((void *) model->name->input_weights); \
free((void *) model->name->bias); \
free((void *) model->name); \
} \
} while (0)
#define RENAMENOISE_FREE_GRU(name) \
do { \
if (model->name) { \
free((void *) model->name->input_weights); \
free((void *) model->name->recurrent_weights); \
free((void *) model->name->bias); \
free((void *) model->name); \
} \
} while (0)
if (!model) {
return;
}
RENAMENOISE_FREE_DENSE(input_dense);
RENAMENOISE_FREE_GRU(vad_gru);
RENAMENOISE_FREE_GRU(noise_gru);
RENAMENOISE_FREE_GRU(denoise_gru);
RENAMENOISE_FREE_DENSE(denoise_output);
RENAMENOISE_FREE_DENSE(vad_output);
free(model);
}

94
thirdparty/renamenoise/src/rnn_train.py vendored Executable file
View file

@ -0,0 +1,94 @@
#!/usr/bin/python
#
# Copyright (c) 2017, Jean-Marc Valin
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
from keras.models import Sequential
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import GRU
from keras.layers import SimpleRNN
from keras.layers import Dropout
from keras import losses
import h5py
from keras import backend as K
import numpy as np
print('Build model...')
main_input = Input(shape=(None, 22), name='main_input')
#x = Dense(44, activation='relu')(main_input)
#x = GRU(44, dropout=0.0, recurrent_dropout=0.0, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x)
x=main_input
x = GRU(128, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x)
#x = GRU(128, return_sequences=True)(x)
#x = GRU(22, activation='relu', return_sequences=True)(x)
x = Dense(22, activation='sigmoid')(x)
#x = Dense(22, activation='softplus')(x)
model = Model(inputs=main_input, outputs=x)
batch_size = 32
print('Loading data...')
with h5py.File('denoise_data.h5', 'r') as hf:
all_data = hf['denoise_data'][:]
print('done.')
window_size = 500
nb_sequences = len(all_data)//window_size
print(nb_sequences, ' sequences')
x_train = all_data[:nb_sequences*window_size, :-22]
x_train = np.reshape(x_train, (nb_sequences, window_size, 22))
y_train = np.copy(all_data[:nb_sequences*window_size, -22:])
y_train = np.reshape(y_train, (nb_sequences, window_size, 22))
#y_train = -20*np.log10(np.add(y_train, .03));
all_data = 0;
x_train = x_train.astype('float32')
y_train = y_train.astype('float32')
print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape)
# try using different optimizers and different optimizer configs
model.compile(loss='mean_squared_error',
optimizer='adam',
metrics=['binary_accuracy'])
print('Train...')
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=200,
validation_data=(x_train, y_train))
model.save("newweights.hdf5")

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2024, The Mumble Developers
Copyright (c) 2017, Jean-Marc Valin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* This file is auto-generated by gen_tables */
#ifndef TANSIG_TABLE_H
#define TANSIG_TABLE_H
static const float renamenoise_tansig_table[201] = {
0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f, 0.446244f,
0.477700f, 0.507977f, 0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, 0.761594f,
0.777888f, 0.793199f, 0.807569f, 0.821040f, 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, 0.893698f, 0.901468f, 0.908698f,
0.915420f, 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f, 0.964028f, 0.966747f,
0.969265f, 0.971594f, 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f, 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f,
0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, 0.998508f,
0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f, 0.999428f, 0.999472f,
0.999513f, 0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, 0.999798f, 0.999813f,
0.999828f, 0.999841f, 0.999853f, 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f, 0.999973f, 0.999975f, 0.999977f,
0.999978f, 0.999980f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, 0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, 0.999992f,
0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, 0.999997f,
0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
};
#endif /* TANSIG_TABLE_H */