From 9a57aca8d4ff8784e0bccf4f38a856f301c38050 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 11 Jan 2014 02:24:20 -0800 Subject: Add an option to make HRTFs with a custom head radius --- utils/CIAIR.def | 2 +- utils/IRC_1005.def | 6 +++--- utils/MIT_KEMAR.def | 20 ++++++++++++-------- utils/makehrtf.c | 32 +++++++++++++++++++++++--------- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/utils/CIAIR.def b/utils/CIAIR.def index 07fb1654..9589a694 100644 --- a/utils/CIAIR.def +++ b/utils/CIAIR.def @@ -1,7 +1,7 @@ # This is a makehrtf HRIR definition file. It is used to define the layout # and source data to be processed into an OpenAL Soft compatible HRTF. # -# This definition is used to transform the left ear HRIRs from a dataset +# This definition is used to transform the left ear HRIRs from a data set # used in several papers and articles by Fumitada Itakura, Kazuya Takeda, # Mikio Ikeda, Shoji Kajita, and Takanori Nishino. # diff --git a/utils/IRC_1005.def b/utils/IRC_1005.def index 5c02c58a..f5a16934 100644 --- a/utils/IRC_1005.def +++ b/utils/IRC_1005.def @@ -2,9 +2,9 @@ # and source data to be processed into an OpenAL Soft compatible HRTF. # # This definition is used to transform an average of the left and right ear -# HRIRs from any raw dataset from the IRCAM/AKG Listen HRTF database. +# HRIRs from any raw data set from the IRCAM/AKG Listen HRTF database. # -# The datasets are available free of charge from: +# The data sets are available free of charge from: # # http://recherche.ircam.fr/equipes/salles/listen/index.html # @@ -32,7 +32,7 @@ distance = 1.95 # The IRCAM source azimuth is counter-clockwise, so it needs to be flipped. # Left and right ear HRIRs (from the respective WAVE channels) are averaged. -# Repalce all occurrences of IRC_#### for the desired subject (1005 was used +# Replace all occurrences of IRC_#### for the desired subject (1005 was used # in this demonstration). [ 3, 0 ] = wave (0) : "./IRC/RAW/WAV/IRC_1005_R/IRC_1005_R_R0195_T000_P315.wav" diff --git a/utils/MIT_KEMAR.def b/utils/MIT_KEMAR.def index 62412b2e..1067e0b4 100644 --- a/utils/MIT_KEMAR.def +++ b/utils/MIT_KEMAR.def @@ -5,17 +5,17 @@ # of KEMAR HRIRs provided by Bill Gardner and Keith # Martin of MIT Media Laboratory. # -# The data (full.tar.Z or full.zip) is available from: +# The data (full.zip) is available from: # # http://sound.media.mit.edu/resources/KEMAR.html # -# It is copyright 1994 by MIT Media Laboratory, and provided free of charge +# It is copyrighted 1994 by MIT Media Laboratory, and provided free of charge # with no restrictions on use so long as the authors (above) are cited. # # This definition is used to generate the internal HRTF table used by OpenAL # Soft. -# The following are the dataset metrics. They must always be specified at +# The following are the data set metrics. They must always be specified at # start of a definition file, but their order is not important. # Sampling rate of the HRIR data (in hertz). @@ -28,17 +28,21 @@ rate = 44100 points = 512 # A list of the number of azimuths measured for each elevation. There must -# be at least 5 elevations covering the 180 degrees for the dataset to be +# be at least 5 elevations covering the 180 degrees for the data set to be # viable. azimuths = 1, 12, 24, 36, 45, 56, 60, 72, 72, 72, 72, 72, 60, 56, 45, 36, 24, 12, 1 -# The approximate radius (measured ear-to-ear) of the listener's head (in -# meters). This does not have to match the dataset, since makehrtf uses a -# spherical model to reconstruct the propagation delay. +# The radius of the listener's head (measured ear-to-ear in meters). The +# makehrtf utility uses this value to rescale measured propagation delays +# when a custom head radius is specified on the command line. It is also +# used as the default radius when the spherical model is used to calculate an +# approximate set of delays. This should match the data set as close as +# possible for accurate rescaling when using the measured delays (the +# default). At the moment, radius rescaling does not adjust HRIR coupling. radius = 0.09 # The distance between the source and the listener (in meters). This does -# have to match the dataset, but it's effect is minimal at the moment due to +# have to match the data set, but it's effect is minimal at the moment due to # the coupled nature of OpenAL Soft's HRTF model. distance = 1.4 diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 45809099..f9da9429 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -2,7 +2,7 @@ * HRTF utility for producing and demonstrating the process of creating an * OpenAL Soft compatible HRIR data set. * - * Copyright (C) 2011-2013 Christopher Fitzgerald + * Copyright (C) 2011-2014 Christopher Fitzgerald * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,7 +58,7 @@ * 1999 */ -/* Needed for 64-bit unsigned integer. */ +// Needed for 64-bit unsigned integer. #include "config.h" #include @@ -153,6 +153,10 @@ #define MIN_TRUNCSIZE (8) #define MAX_TRUNCSIZE (128) +// The limits to the custom head radius on the command line. +#define MIN_CUSTOM_RADIUS (0.05) +#define MAX_CUSTOM_RADIUS (0.15) + // The truncation window size must be a multiple of the below value to allow // for vectorized convolution. #define MOD_TRUNCSIZE (8) @@ -163,6 +167,7 @@ #define DEFAULT_LIMIT (24.0) #define DEFAULT_TRUNCSIZE (32) #define DEFAULT_HEAD_MODEL (HM_DATASET) +#define DEFAULT_CUSTOM_RADIUS (0.0) // The four-character-codes for RIFF/RIFX WAVE file chunks. #define FOURCC_RIFF (0x46464952) // 'RIFF' @@ -2016,7 +2021,7 @@ static double CalcLTD (const double ev, const double az, const double rad, const // Calculate the effective head-related time delays for each minimum-phase // HRIR. -static void CalculateHrtds (const HeadModelT model, HrirDataT * hData) { +static void CalculateHrtds (const HeadModelT model, const double radius, HrirDataT * hData) { double minHrtd, maxHrtd; uint e, a, j; double t; @@ -2027,13 +2032,13 @@ static void CalculateHrtds (const HeadModelT model, HrirDataT * hData) { for (a = 0; a < hData -> mAzCount [e]; a ++) { j = hData -> mEvOffset [e] + a; if (model == HM_DATASET) { - t = hData -> mHrtds [j]; + t = hData -> mHrtds [j] * radius / hData -> mRadius; } else { t = CalcLTD ((-90.0 + (e * 180.0 / (hData -> mEvCount - 1))) * M_PI / 180.0, (a * 360.0 / hData -> mAzCount [e]) * M_PI / 180.0, - hData -> mRadius, hData -> mDistance); - hData -> mHrtds [j] = t; + radius, hData -> mDistance); } + hData -> mHrtds [j] = t; maxHrtd = fmax (t, maxHrtd); minHrtd = fmin (t, minHrtd); } @@ -2506,7 +2511,7 @@ static int ProcessSources (const HeadModelT model, TokenReaderT * tr, HrirDataT * resulting data set as desired. If the input name is NULL it will read * from standard input. */ -static int ProcessDefinition (const char * inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const OutputFormatT outFormat, const char * outName) { +static int ProcessDefinition (const char * inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const OutputFormatT outFormat, const char * outName) { FILE * fp = NULL; TokenReaderT tr; HrirDataT hData; @@ -2572,7 +2577,7 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin fprintf (stdout, "Normalizing final HRIRs...\n"); NormalizeHrirs (& hData); fprintf (stdout, "Calculating impulse delays...\n"); - CalculateHrtds (model, & hData); + CalculateHrtds (model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData . mRadius, & hData); snprintf (rateStr, 8, "%u", hData . mIrRate); StrSubst (outName, "%r", rateStr, MAX_PATH_LEN, expName); switch (outFormat) { @@ -2604,6 +2609,7 @@ int main (const int argc, const char * argv []) { double limit; uint truncSize; HeadModelT model; + double radius; char * end = NULL; if (argc < 2) { @@ -2632,6 +2638,7 @@ int main (const int argc, const char * argv []) { fprintf (stdout, " after minimum-phase reconstruction (default: %u).\n", DEFAULT_TRUNCSIZE); fprintf (stdout, " -d={dataset| Specify the model used for calculating the head-delay timing\n"); fprintf (stdout, " sphere} values (default: %s).\n", ((DEFAULT_HEAD_MODEL == HM_DATASET) ? "dataset" : "sphere")); + fprintf (stdout, " -c= Use a customized head radius measured ear-to-ear in meters.\n"); fprintf (stdout, " -i= Specify an HRIR definition file to use (defaults to stdin).\n"); fprintf (stdout, " -o= Specify an output file. Overrides command-selected default.\n"); fprintf (stdout, " Use of '%%r' will be substituted with the data set sample rate.\n"); @@ -2661,6 +2668,7 @@ int main (const int argc, const char * argv []) { limit = DEFAULT_LIMIT; truncSize = DEFAULT_TRUNCSIZE; model = DEFAULT_HEAD_MODEL; + radius = DEFAULT_CUSTOM_RADIUS; while (argi < argc) { if (strncmp (argv [argi], "-r=", 3) == 0) { outRate = strtoul (& argv [argi] [3], & end, 10); @@ -2717,6 +2725,12 @@ int main (const int argc, const char * argv []) { fprintf (stderr, "Error: Expected 'dataset' or 'sphere' for '-d'.\n"); return (-1); } + } else if (strncmp (argv [argi], "-c=", 3) == 0) { + radius = strtod (& argv [argi] [3], & end); + if ((end [0] != '\0') || (radius < MIN_CUSTOM_RADIUS) || (radius > MAX_CUSTOM_RADIUS)) { + fprintf (stderr, "Error: Expected a value from %.2f to %.2f for '-c'.\n", MIN_CUSTOM_RADIUS, MAX_CUSTOM_RADIUS); + return (-1); + } } else if (strncmp (argv [argi], "-i=", 3) == 0) { inName = & argv [argi] [3]; } else if (strncmp (argv [argi], "-o=", 3) == 0) { @@ -2727,7 +2741,7 @@ int main (const int argc, const char * argv []) { } argi ++; } - if (! ProcessDefinition (inName, outRate, fftSize, equalize, surface, limit, truncSize, model, outFormat, outName)) + if (! ProcessDefinition (inName, outRate, fftSize, equalize, surface, limit, truncSize, model, radius, outFormat, outName)) return (-1); fprintf (stdout, "Operation completed.\n"); return (0); -- cgit v1.2.3