Noise Cancellation Tutorial
What you’ll learn
In this tutorial you’ll learn how to setup the Immersitech SDK. You’ll create a room, add participants to that room, and apply the noise cancellation effect. You’ll also learn how to simulate the audio for participants to speed up development.
If you’d rather just see the finished application you can find it in our Github examples repository.
Boilerplate
Let’s start by setting up some headers and constants for our project. We’ll add the standard C libraries, include the Immersitech header file, and define some constants that we can use for initializing the Immersitech library.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <windows.h>
#include "immersitech.h"
#define OUTPUT_SAMPLING_RATE 48000
#define OUTPUT_NUM_FRAMES 480
#define OUTPUT_NUM_CHANNELS 1
#define INTERLEAVED true
#define SPATIAL_QUALITY 1
Initialize the library
Next, let’s create our main function, enable logging, and initialize the Immersitech library.
int main(int argc, char **argv) {
imm_enable_logging(true);
imm_error_code error_code;
imm_library_configuration output_config = {
OUTPUT_SAMPLING_RATE,
OUTPUT_NUM_FRAMES,
OUTPUT_NUM_CHANNELS,
INTERLEAVED,
SPATIAL_QUALITY
};
imm_handle imm = imm_initialize_library("Immersitech_Engineering_sound_manager_license_key.dat", NULL, NULL, output_config, &error_code);
printf("\nUsing Immersitech version: %s", imm_get_version());
printf("\nLicense Key Info: %s", imm_get_license_info(imm));
}
Go ahead and build the project to make sure that the library accepts your license key. You should see something like the following in your console output:
Using Immersitech version: v1.0.9
License Key Info: { "valid": true, "name": "Immersitech_Engineering_sound_manager_license_key.dat", "department": "Engineering", "minimum_version": "v0.8.0", "maximum_version": "v1.9.999", "creation_date": "3/9/2022", "expiration_date": "8/21/2022" }
Assuming that your license key is valid we can move forward with using the library.
Simulating participant audio
The main use case of the Immersitech SDK is to apply audio effects and mixing to real-time conferencing. During development it may not be practical for you to gather your coworkers together each time you need to test changes to your code. That’s why we’ve provided a tutorial that uses audio files to simulate participants. The input file will simulate the user who is speaking and the output file will simulate what is being heard in the room.
Setting up the input and output buffers
Let’s start by creating a struct to store the header information for the .wav file. We will need to read in the header for the input file so that we can calculate the size of the buffers and determine the format for the output file. Then we’ll write the WAV header to the output file and create our input and output buffers.
If you need some audio files to test with you can download them from our examples repository.
typedef struct wav_header {
unsigned char chunk_id[4];
unsigned int chunk_size;
unsigned char format[4];
unsigned char subchunk1_id[4];
unsigned int subchunk1_size;
unsigned short audio_format;
unsigned short num_channels;
unsigned int sample_rate;
unsigned int byte_rate;
unsigned short block_align;
unsigned short bits_per_sample;
unsigned char subchunk2_id[4];
unsigned int subchunk2_size;
} wav_header;
// Input files will simulate input audio from each individual participant
FILE* input_file = fopen("input.wav", "rb");
// Output files let you review what each participant hears
FILE* output_file = fopen("output.wav", "wb");
// Read in data about input file
struct wav_header wav_meta_data;
fread(&wav_meta_data, 1, sizeof(wav_header), input_file);
int input_rate = wav_meta_data.sample_rate;
int input_channels = wav_meta_data.num_channels;
printf("Input Configuration: %s || %i Hz || %i Channel(s)\n\n", argv[1], input_rate, input_channels);
// Write WAV Header data to the output file
if (wav_meta_data.sample_rate != OUTPUT_SAMPLING_RATE) {
wav_meta_data.subchunk2_size *= (OUTPUT_SAMPLING_RATE / wav_meta_data.sample_rate);
wav_meta_data.sample_rate = OUTPUT_SAMPLING_RATE;
wav_meta_data.chunk_size = 36 + wav_meta_data.subchunk2_size;
}
fwrite(&wav_meta_data, 1, sizeof(wav_header), output_file);
// Calculate the number of frames we must receive from each input
int input_num_frames = (OUTPUT_NUM_FRAMES * input_rate) / OUTPUT_SAMPLING_RATE;
// Initialize buffers to read input files and write to output files
short* input_buffer = (short*)malloc(input_num_frames * input_channels * sizeof(short));
short* output_buffer = (short*)malloc(OUTPUT_NUM_FRAMES * OUTPUT_NUM_CHANNELS * sizeof(short));
Great! Now we’re set up to read from an audio file and write to an audio output file. One final step we need to take is to setup the library for processing our audio.
Creating a room
Let’s create a room and add two participants into the room. Then, we’ll enable noise cancellation for each of the participants.
// Create and initialize a room to put participants into
int room_id = 0;
imm_create_room(imm, room_id);
// Add Participants into our room
int ID_1 = 1;
int ID_2 = 2;
imm_participant_configuration input_config = { input_rate, input_channels, IMM_PARTICIPANT_REGULAR };
imm_add_participant(imm, room_id, ID_1, "participant_1", input_config);
imm_add_participant(imm, room_id, ID_2, "participant_2", input_config);
// Turn on the noise cancellation for all the participants
imm_set_all_participants_state(imm, room_id, IMM_CONTROL_ANC_ENABLE, 1);
Processing the Audio
At this point we have everything that we need set up for audio processing. We just need to actually process the audio files to simulate a real-time audio stream.
// Loop through a file and buffer it as you would see in a real-time application
while ( !feof(input_file) ) {
// Read in one buffer of audio from each file
// Input each buffer into its respective Immersitech Participant within the room
fread(input_buffer, 1, input_num_frames * input_channels * sizeof(short), input_file);
imm_input_audio_short(imm, room_id, ID_1, input_buffer, input_num_frames);
// Now that all the audio is entered into the room for this cycle, we are ready to generate the outputs
// Generate the output for each participant and save it to their output file
imm_output_audio_short(imm, room_id, ID_2, output_buffer);
fwrite(output_buffer, 1, OUTPUT_NUM_FRAMES * OUTPUT_NUM_CHANNELS * sizeof(short), output_file);
}
Cleanup
Finally, let’s free up memory by calling the destructors for the library and closing our input and output buffers.
// Remove all participants from the room
imm_remove_participant( imm, room_id, ID_1 );
imm_remove_participant( imm, room_id, ID_2 );
// Destroy the room
imm_destroy_room(imm, room_id);
// Close and free the library
imm_destroy_library(imm);
// Close input and output files and free input / output buffers
fclose(input_file);
fclose(output_file);
free(input_buffer);
free(output_buffer);
We should now be able to run the application that we’ve written. Just make sure that your input.wav file is included with the project. After running the application you should have a clean, noise-reduced output.wav file!