From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B16B8FA3744 for ; Fri, 13 Sep 2024 10:44:55 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 71B2D10E255; Fri, 13 Sep 2024 10:44:55 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.b="SjSPHqXN"; dkim-atps=neutral Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.13]) by gabe.freedesktop.org (Postfix) with ESMTPS id 08A4210E255 for ; Fri, 13 Sep 2024 10:44:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1726224294; x=1757760294; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=roQLUXcykDxQAkEOS79Fx9B2S3ppvf9x2Axw+Qr7r5M=; b=SjSPHqXNJF8vn4+EWxeoecGCFubBD+s6yIyOX8U2Rf5L0pymt8YTEeqI YfeYyxzXBRVuyki5sikxL1oKq4fD9q9sBZOKYgzW5f+JZlmBEKZUsO9qB T6CDNN+W110+jB4wrtYhpZJrIK+0ZR0bWf9/NxXtpi+v0lnDGAu3DOixZ nm7PgGxE1quXqVHJEY4ecQZrZirwyGkNIwAkZbJoOSkQ1prsRjmREKZLH F15LU0yOuM8aV30YZWDsRg9oSdym8rpWETPboKbmk3b5V20KQrcYXWRYF ufkf5x7wbwQczD9MBgNQjlvExKmVTKetelW5bHnCXjb1DGwrwfeZUPD1f A==; X-CSE-ConnectionGUID: yq5tSj9BSJ2pnpKVk2KpJQ== X-CSE-MsgGUID: BvOlCm+zQlyBIhXYdfw2Tg== X-IronPort-AV: E=McAfee;i="6700,10204,11193"; a="28033065" X-IronPort-AV: E=Sophos;i="6.10,225,1719903600"; d="scan'208";a="28033065" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2024 03:44:54 -0700 X-CSE-ConnectionGUID: Y5ITzFa2SNWmpazfsPc3DQ== X-CSE-MsgGUID: 1wsX1D1OTsetSTmzCB+snw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,225,1719903600"; d="scan'208";a="68517347" Received: from pgcooper-mobl3.ger.corp.intel.com (HELO localhost) ([10.245.245.162]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2024 03:44:52 -0700 From: Kamil Konieczny To: igt-dev@lists.freedesktop.org Cc: Ryszard Knop , Kamil Konieczny Subject: [PATCH i-g-t 3/3] lib/igt_audio: Replace GSL FFT usage with meow_fft Date: Fri, 13 Sep 2024 12:44:34 +0200 Message-ID: <20240913104434.56529-4-kamil.konieczny@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240913104434.56529-1-kamil.konieczny@linux.intel.com> References: <20240913104434.56529-1-kamil.konieczny@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: igt-dev@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development mailing list for IGT GPU Tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" From: Ryszard Knop Tested by running kms_chamelium tests related with audio and comparing GSL and meow_fft outputs in a separate test program. It appears meow_fft is slightly less accurate than GSL (result differs after the 6th decimal place), but the error is low enough that it does not matter here. v2: sort headers, remove blank spaces, fixed codestyle (Kamil) Signed-off-by: Ryszard Knop Signed-off-by: Kamil Konieczny --- lib/igt_audio.c | 74 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/lib/igt_audio.c b/lib/igt_audio.c index e0b1bafe1..193f9aa05 100644 --- a/lib/igt_audio.c +++ b/lib/igt_audio.c @@ -28,12 +28,14 @@ #include #include -#include +#include #include #include #include "igt_audio.h" +#include "igt_aux.h" #include "igt_core.h" +#include "meow_fft/meow_fft.h" #define FREQS_MAX 64 #define CHANNELS_MAX 8 @@ -322,6 +324,53 @@ static double hann_window(double v, size_t i, size_t N) return v * 0.5 * (1 - cos(2.0 * M_PI * (double) i / (double) N)); } +/** + * run_fft: + * @array: The signal to run FFT on + * @length: The signal buffer length (must be a power of 2) + * + * Run the Fast Fourier Transform on the provided signal, whose + * length must be a power of 2. The return value points to an + * array of N/2 structs with real (.r) and imaginary (.j) parts. + * + * For the 0-th FFT element, only the real part is valid - its + * imaginary part is always 0 and is not saved anywhere. + * + * For the (N/2)-th element, again, only the real part is valid. + * The array does not have enough space to save it as a separate + * element, so its real part is saved in the 0-th element's + * imaginary part. + */ +static Meow_FFT_Complex *run_fft(double *array, size_t length) +{ + size_t workset_bytes; + Meow_FFT_Complex *fft_data; + struct Meow_FFT_Workset_Real *fft_workset; + + igt_assert(length >= 2 && is_power_of_two(length)); + + // Get size for a N point fft working on non-complex (real) data. + workset_bytes = meow_fft_generate_workset_real(length, NULL); + if (workset_bytes == 0) + return NULL; + + fft_data = malloc(sizeof(Meow_FFT_Complex) * length); + if (!fft_data) + return NULL; + + fft_workset = (struct Meow_FFT_Workset_Real *)malloc(workset_bytes); + if (!fft_workset) { + free(fft_data); + return NULL; + } + + meow_fft_generate_workset_real(length, fft_workset); + meow_fft_real(fft_workset, array, fft_data); + free(fft_workset); + + return fft_data; +} + /** * Checks that frequencies specified in signal, and only those, are included * in the input data. @@ -333,11 +382,12 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate, int channel, const double *samples, size_t samples_len) { double *data; + Meow_FFT_Complex *fft_data; size_t data_len = samples_len; size_t bin_power_len = data_len / 2 + 1; double bin_power[bin_power_len]; bool detected[FREQS_MAX]; - int ret, freq_accuracy, freq, local_max_freq; + int freq_accuracy, freq, local_max_freq; double max, local_max, threshold; size_t i, j; bool above, success; @@ -360,27 +410,22 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate, freq_accuracy = sampling_rate / data_len; igt_debug("Allowed freq. error: %d Hz\n", freq_accuracy); - ret = gsl_fft_real_radix2_transform(data, 1, data_len); - if (ret != 0) { + fft_data = run_fft(data, data_len); + if (!fft_data) { free(data); igt_assert(0); } - /* Compute the power received by every bin of the FFT. - * - * For i < data_len / 2, the real part of the i-th term is stored at - * data[i] and its imaginary part is stored at data[data_len - i]. - * i = 0 and i = data_len / 2 are special cases, they are purely real - * so their imaginary part isn't stored. - * + /* Compute the power received by every bin of the FFT. The run_fft + * function docs explain the special cases outside of the for loop. * The power is encoded as the magnitude of the complex number and the * phase is encoded as its angle. */ - bin_power[0] = data[0]; + bin_power[0] = fft_data[0].r; for (i = 1; i < bin_power_len - 1; i++) { - bin_power[i] = hypot(data[i], data[data_len - i]); + bin_power[i] = hypot(fft_data[i].r, fft_data[i].j); } - bin_power[bin_power_len - 1] = data[data_len / 2]; + bin_power[bin_power_len - 1] = fft_data[0].j; /* Normalize the power */ for (i = 0; i < bin_power_len; i++) @@ -487,6 +532,7 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate, } } + free(fft_data); free(data); return success; -- 2.43.0