init
This commit is contained in:
38
lib_audio_dsp/examples/app_fd_block_fir/CMakeLists.txt
Normal file
38
lib_audio_dsp/examples/app_fd_block_fir/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
|
||||
project(app_td_block_fir)
|
||||
|
||||
set(APP_HW_TARGET XK-EVK-XU316)
|
||||
set(APP_DEPENDENT_MODULES
|
||||
"lib_audio_dsp"
|
||||
"lib_logging(3.2.0)"
|
||||
"lib_locks(2.2.0)"
|
||||
)
|
||||
set(APP_PCA_ENABLE OFF)
|
||||
set(EXAMPLE_BUILD_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm
|
||||
-Wall
|
||||
-O3
|
||||
-report
|
||||
-lquadflash
|
||||
-mcmodel=large
|
||||
-g
|
||||
-fxscope)
|
||||
|
||||
set(APP_COMPILER_FLAGS ${EXAMPLE_BUILD_FLAGS})
|
||||
|
||||
file(GLOB C_SRC CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_LIST_DIR} src/*.c)
|
||||
|
||||
set(DSP_DIR build/dsp_pipeline)
|
||||
|
||||
set(APP_C_SRCS
|
||||
"${C_SRC};${DSP_MAIN}")
|
||||
|
||||
|
||||
set(APP_INCLUDES
|
||||
src
|
||||
src/core
|
||||
src/extensions
|
||||
${CMAKE_CURRENT_LIST_DIR}/build/dsp_pipeline)
|
||||
set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
|
||||
XMOS_REGISTER_APP()
|
||||
27
lib_audio_dsp/examples/app_fd_block_fir/readme.md
Normal file
27
lib_audio_dsp/examples/app_fd_block_fir/readme.md
Normal file
@@ -0,0 +1,27 @@
|
||||
app_fd_block_fir
|
||||
---
|
||||
|
||||
This demonstrates the usage of a frequency domain FIR. It runs a 4096 tap
|
||||
bandpass filter with a 256 sample latency. This requires around 3x less
|
||||
compute than the equivalent block time domain filter, and around 6x less
|
||||
compute than a single sample implementation (both VPU optimised).
|
||||
|
||||
To build the example, first generate the test filter `test_0` by running `make_test_filters.py`:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cd examples/app_fd_block_fir/src
|
||||
python make_test_filters.py
|
||||
|
||||
Then autogenerate the frequency domain filter with a frame advance of 256 samples:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python -m audio_dsp.dsp.fd_block_fir test_0.npy 256
|
||||
|
||||
Finally, build the example app:
|
||||
|
||||
.. code-block:: console
|
||||
cd ..
|
||||
cmake -G "Unix Makefiles" -B build
|
||||
cmake -C build
|
||||
43
lib_audio_dsp/examples/app_fd_block_fir/src/main.c
Normal file
43
lib_audio_dsp/examples/app_fd_block_fir/src/main.c
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2024-2025 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <xcore/hwtimer.h>
|
||||
#include "test_0.h"
|
||||
|
||||
void foo(){
|
||||
|
||||
int32_t __attribute__((aligned (8))) new_data[test_0_TD_BLOCK_LENGTH];
|
||||
|
||||
//allocate a TD FIR for the example
|
||||
int32_t data[test_0_DATA_BUFFER_ELEMENTS];
|
||||
memset(data, 0, sizeof(data));
|
||||
fd_fir_data_t fd_fir_data_test_0;
|
||||
|
||||
fd_block_fir_data_init(&fd_fir_data_test_0, data,
|
||||
test_0_FRAME_ADVANCE,
|
||||
test_0_TD_BLOCK_LENGTH,
|
||||
test_0_BLOCK_COUNT);
|
||||
|
||||
for(int j=0;j<16;j++)
|
||||
{
|
||||
for(int i=0;i<test_0_FRAME_ADVANCE;i++)
|
||||
new_data[i] = rand()-rand();
|
||||
|
||||
int32_t __attribute__((aligned (8))) fd_processed[test_0_TD_BLOCK_LENGTH] = {0};
|
||||
|
||||
fd_block_fir_add_data(new_data, &fd_fir_data_test_0);
|
||||
|
||||
fd_block_fir_compute(
|
||||
fd_processed,
|
||||
&fd_fir_data_test_0,
|
||||
&fd_fir_filter_test_0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
foo();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Copyright 2024-2025 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
|
||||
def bandpass_filters(length, count):
|
||||
for i in range(count):
|
||||
t = signal.firwin(length, (i + 1) / (count + 2))
|
||||
name = 'test_' + str(i)
|
||||
np.save(name, t)
|
||||
|
||||
if __name__ == '__main__':
|
||||
bandpass_filters(4096, 1)
|
||||
@@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
|
||||
project(app_simple_audio_dsp_integration)
|
||||
|
||||
set(APP_HW_TARGET XK-EVK-XU316)
|
||||
set(APP_DEPENDENT_MODULES
|
||||
"lib_audio_dsp"
|
||||
"lib_logging(3.2.0)"
|
||||
"lib_locks(2.2.0)"
|
||||
)
|
||||
set(APP_PCA_ENABLE OFF)
|
||||
set(EXAMPLE_BUILD_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm
|
||||
-Wall
|
||||
-O3
|
||||
-report
|
||||
-lquadflash
|
||||
-g
|
||||
-fxscope)
|
||||
|
||||
set(APP_COMPILER_FLAGS ${EXAMPLE_BUILD_FLAGS})
|
||||
|
||||
file(GLOB C_SRC CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_LIST_DIR} src/*.c)
|
||||
|
||||
set(DSP_DIR build/dsp_pipeline)
|
||||
set(DSP_MAIN ${DSP_DIR}/adsp_generated_auto.c)
|
||||
if(NOT EXISTS ${DSP_MAIN})
|
||||
write_file(${DSP_MAIN} "#error Generate pipeline before building or build with dsp_pipeline.ipynb")
|
||||
write_file(${DSP_DIR}/adsp_generated_auto.h "#error Generate pipeline before building or build with dsp_pipeline.ipynb")
|
||||
endif()
|
||||
|
||||
set(APP_C_SRCS
|
||||
"${C_SRC};${DSP_MAIN}")
|
||||
|
||||
|
||||
set(APP_INCLUDES
|
||||
src
|
||||
src/core
|
||||
src/extensions
|
||||
${CMAKE_CURRENT_LIST_DIR}/build/dsp_pipeline)
|
||||
set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
|
||||
XMOS_REGISTER_APP()
|
||||
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ccc61334-38ac-4c86-a86a-bd2975d5a60d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# lib_audio_dsp pipeline designer\n",
|
||||
"\n",
|
||||
"In this file you can generate the DSP pipeline of your choice.\n",
|
||||
"\n",
|
||||
"Below you will find 3 cells which can be modified and executed to configure, tune and run the desired pipeline.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0acbc09d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"1. This is the pipeline design cell. Here you must break the DSP pipeline down into threads and use the provided DSP stages to create a pipeline. Running this cell will produce a diagram showing your pipeline. Make sure to capture each stage in your pipeline as a variable, as it will be needed in the next step.\n",
|
||||
"Note that every time the pipeline cell is changed, the app must be regenerated before the tuning stage can work correctly as the stage indices used for communication may have changed."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f3806bd0-99e0-42b6-a084-e9a2f17ba7dc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Pipeline design stage\n",
|
||||
"\n",
|
||||
"from audio_dsp.design.pipeline import Pipeline\n",
|
||||
"from audio_dsp.stages import *\n",
|
||||
"\n",
|
||||
"p, inputs = Pipeline.begin(1, fs=48000)\n",
|
||||
"\n",
|
||||
"# i is a list of pipeline inputs. \"lowshelf\" is a label for this instance of Biquad.\n",
|
||||
"# The new variable x is the output of the lowshelf Biquad\n",
|
||||
"x = p.stage(Biquad, inputs, \"lowshelf\")\n",
|
||||
"\n",
|
||||
"# The output of lowshelf \"x\" is passed as the input to the\n",
|
||||
"# highshelf. The variable x is reassigned to the outputs of the new Biquad.\n",
|
||||
"x = p.stage(Biquad, x, \"highshelf\")\n",
|
||||
"\n",
|
||||
"# Connect highshelf to the limiter. Labels are optional, however they are required\n",
|
||||
"# if the stage will be tuned later.\n",
|
||||
"x = p.stage(LimiterPeak, x)\n",
|
||||
"\n",
|
||||
"# Finally connect to the output of the pipeline.\n",
|
||||
"p.set_outputs(x)\n",
|
||||
"\n",
|
||||
"p.draw()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "27e9d385",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"2. This is the tuning cell. First time through this can be ignored, but once your pipeline is running on a connected device, this cell can be updated and executed to update each pipeline stage live."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "89d245d6-b908-4815-ae22-fa10e40d65dc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from audio_dsp.tuning import send_config_to_device, profile_pipeline\n",
|
||||
"from audio_dsp.tuning.transport import XScopeTransport\n",
|
||||
"from time import sleep\n",
|
||||
"\n",
|
||||
"# Make a low shelf with a centre frequency of 200 Hz, q of 0.7 and gain of +6 dB\n",
|
||||
"p[\"lowshelf\"].make_lowshelf(200, 0.7, 6)\n",
|
||||
"p[\"lowshelf\"].plot_frequency_response()\n",
|
||||
"\n",
|
||||
"# Make a high shelf with a centre frequency of 4000 Hz, q of 0.7 and gain of +6 dB\n",
|
||||
"p[\"highshelf\"].make_highshelf(4000, 0.7, 6)\n",
|
||||
"p[\"highshelf\"].plot_frequency_response()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2113ddc3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"3. This is the build and run cell. This stage generates an application which uses your pipeline. The tuning parameters set in the previous cell are baked in the application."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "32492495-d82a-45ba-87e3-80b01de38981",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Build and run\n",
|
||||
"from audio_dsp.design.pipeline import generate_dsp_main\n",
|
||||
"from audio_dsp.design.build_utils import XCommonCMakeHelper\n",
|
||||
"\n",
|
||||
"b = XCommonCMakeHelper()\n",
|
||||
"generate_dsp_main(p)\n",
|
||||
"\n",
|
||||
"b.configure_build_run()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2024-2025 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* System headers */
|
||||
/* Standard library*/
|
||||
#include <stdint.h> // for int32_t and related typedefs
|
||||
#include <string.h> // for memset
|
||||
|
||||
/* XMOS headers */
|
||||
#include <platform.h>
|
||||
#include <xs1.h>
|
||||
|
||||
/* lib_xcore */
|
||||
/* This is an incomplete list of headers exposed by lib_xcore; see the XTC
|
||||
tools documentation for more details */
|
||||
#include <xcore/assert.h> // for xassert()
|
||||
#include <xcore/hwtimer.h> // for hwtimer_t and related functions
|
||||
#include <xcore/parallel.h> // for PAR_JOBS, DECLARE_JOB, and related macros
|
||||
|
||||
/* Application libraries */
|
||||
#include <stages/adsp_pipeline.h>
|
||||
#include <adsp_generated_auto.h>
|
||||
#include "whitenoise_1024samples.h"
|
||||
|
||||
#define SAMPLE_RATE 48000 // Hertz
|
||||
#define OUTPUT_BUFFER_LENGTH 64 // samples
|
||||
#define NUM_CHANNELS 1 // dimensionless
|
||||
|
||||
/* Set up a dummy output buffer and state variable. */
|
||||
int32_t volatile output_buffer[OUTPUT_BUFFER_LENGTH];
|
||||
uint8_t volatile buffer_loop_flag = 0;
|
||||
uint32_t buffer_counter = 0;
|
||||
|
||||
DECLARE_JOB(signal_producer, (adsp_pipeline_t *));
|
||||
void signal_producer(adsp_pipeline_t * m_dsp)
|
||||
{
|
||||
/* Get a new hardware timer and check we've got it. */
|
||||
hwtimer_t event_timer = hwtimer_alloc();
|
||||
xassert(event_timer);
|
||||
|
||||
/* Set up the first event on the hardware timer */
|
||||
uint32_t const sample_period_ticks = XS1_TIMER_HZ / SAMPLE_RATE;
|
||||
uint32_t trigger_time = hwtimer_get_time(event_timer) + sample_period_ticks;
|
||||
hwtimer_set_trigger_time(event_timer, trigger_time);
|
||||
|
||||
/* Set up the input buffer. We're using precalculated white noise
|
||||
* and will just loop through this over and over. */
|
||||
int32_t white_noise[] = {WHITENOISE_1024};
|
||||
uint32_t const n_samps = sizeof(white_noise) / sizeof(white_noise[0]);
|
||||
uint32_t sample_no = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* Block until the trigger time*/
|
||||
hwtimer_get_time(event_timer);
|
||||
|
||||
/* Send the generated sample to the DSP pipeline.
|
||||
* This example currently assumes one input channel. Additional members
|
||||
* of this array need to be supplied in order to add more channels.
|
||||
* This example also currently assumes a frame size of 1. Increasing the
|
||||
* frame size would require each element of this array becoming an array
|
||||
* of length FRAME_SIZE. */
|
||||
int32_t * input_samples[NUM_CHANNELS] = {&white_noise[sample_no]};
|
||||
sample_no = (sample_no + 1) % n_samps;
|
||||
adsp_pipeline_source(m_dsp, input_samples);
|
||||
|
||||
/* Set up the next sample period */
|
||||
trigger_time += sample_period_ticks;
|
||||
hwtimer_set_trigger_time(event_timer, trigger_time);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_JOB(signal_consumer, (adsp_pipeline_t *));
|
||||
void signal_consumer(adsp_pipeline_t * m_dsp)
|
||||
{
|
||||
int32_t output_word = 0;
|
||||
memset((void *)output_buffer, 0, sizeof(int32_t) * OUTPUT_BUFFER_LENGTH);
|
||||
int32_t * output_samples[NUM_CHANNELS] = {&output_word};
|
||||
while(1)
|
||||
{
|
||||
/* Get the processed output from the DSP pipeline.
|
||||
* This operation blocks on data being available.
|
||||
* We assume single-channel with frame size of 1. */
|
||||
adsp_pipeline_sink(m_dsp, output_samples);
|
||||
|
||||
/* Place the output word in the output buffer,
|
||||
* wrapping around when the buffer is full. */
|
||||
output_buffer[buffer_counter] = output_word;
|
||||
buffer_counter = (buffer_counter + 1) % OUTPUT_BUFFER_LENGTH;
|
||||
|
||||
/* Set up an easy GDB watchpoint */
|
||||
if (buffer_counter == 0)
|
||||
{
|
||||
buffer_loop_flag = !buffer_loop_flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
adsp_pipeline_t * m_dsp = adsp_auto_pipeline_init();
|
||||
|
||||
PAR_JOBS(
|
||||
PJOB(signal_producer, (m_dsp)),
|
||||
PJOB(signal_consumer, (m_dsp)),
|
||||
PJOB(adsp_auto_pipeline_main, (m_dsp))
|
||||
);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
36
lib_audio_dsp/examples/app_td_block_fir/CMakeLists.txt
Normal file
36
lib_audio_dsp/examples/app_td_block_fir/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
|
||||
project(app_td_block_fir)
|
||||
|
||||
set(APP_HW_TARGET XK-EVK-XU316)
|
||||
set(APP_DEPENDENT_MODULES
|
||||
"lib_audio_dsp"
|
||||
"lib_logging(3.2.0)"
|
||||
"lib_locks(2.2.0)"
|
||||
)
|
||||
set(APP_PCA_ENABLE OFF)
|
||||
set(EXAMPLE_BUILD_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm
|
||||
-Wall
|
||||
-O3
|
||||
-report
|
||||
-lquadflash
|
||||
-mcmodel=large
|
||||
-g
|
||||
-fxscope)
|
||||
|
||||
set(APP_COMPILER_FLAGS ${EXAMPLE_BUILD_FLAGS})
|
||||
|
||||
file(GLOB C_SRC CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_LIST_DIR} src/*.c)
|
||||
|
||||
set(APP_C_SRCS
|
||||
"${C_SRC};${DSP_MAIN}")
|
||||
|
||||
|
||||
set(APP_INCLUDES
|
||||
src
|
||||
src/core
|
||||
src/extensions
|
||||
${CMAKE_CURRENT_LIST_DIR}/build/dsp_pipeline)
|
||||
set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
|
||||
XMOS_REGISTER_APP()
|
||||
7
lib_audio_dsp/examples/app_td_block_fir/readme.md
Normal file
7
lib_audio_dsp/examples/app_td_block_fir/readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
app_td_block_fir
|
||||
---
|
||||
|
||||
This demos 16 concurrent FIRs running on a single tile with a frame size of 8 and of length 4008.
|
||||
Currently, it runs at 46kHz.
|
||||
The application demonstrates how two channels per thread can be run in parallel over a single tile
|
||||
in order to get 16 channels running concurrently.
|
||||
17
lib_audio_dsp/examples/app_td_block_fir/src/gen.sh
Normal file
17
lib_audio_dsp/examples/app_td_block_fir/src/gen.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
python make_test_filters.py
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_0.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_1.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_2.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_3.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_4.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_5.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_6.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_7.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_8.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_9.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_10.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_11.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_12.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_13.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_14.npy
|
||||
python ../../../python/audio_dsp/dsp/td_block_fir.py test_15.npy
|
||||
130
lib_audio_dsp/examples/app_td_block_fir/src/main.c
Normal file
130
lib_audio_dsp/examples/app_td_block_fir/src/main.c
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2024-2025 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <xcore/hwtimer.h>
|
||||
#include <xcore/parallel.h>
|
||||
#include <xcore/channel.h>
|
||||
#include "dsp/td_block_fir.h"
|
||||
|
||||
#include "test_0.h"
|
||||
#include "test_1.h"
|
||||
#include "test_2.h"
|
||||
#include "test_3.h"
|
||||
#include "test_4.h"
|
||||
#include "test_5.h"
|
||||
#include "test_6.h"
|
||||
#include "test_7.h"
|
||||
#include "test_8.h"
|
||||
#include "test_9.h"
|
||||
#include "test_10.h"
|
||||
#include "test_11.h"
|
||||
#include "test_12.h"
|
||||
#include "test_13.h"
|
||||
#include "test_14.h"
|
||||
#include "test_15.h"
|
||||
|
||||
#define WORKER_THREAD_COUNT 8
|
||||
|
||||
DECLARE_JOB(worker, (chanend_t, int32_t*, uint32_t, td_block_fir_filter_t*, int32_t*, uint32_t, td_block_fir_filter_t*));
|
||||
void worker(chanend_t c,
|
||||
int32_t * data0,
|
||||
uint32_t data0_elements,
|
||||
td_block_fir_filter_t * f0,
|
||||
int32_t * data1,
|
||||
uint32_t data1_elements,
|
||||
td_block_fir_filter_t * f1)
|
||||
{
|
||||
td_block_fir_data_t d0, d1;
|
||||
td_block_fir_data_init(&d0, data0, data0_elements);
|
||||
td_block_fir_data_init(&d1, data1, data1_elements);
|
||||
memset(data0, 0, data0_elements *sizeof(int32_t));
|
||||
memset(data1, 0, data1_elements*sizeof(int32_t));
|
||||
|
||||
while(1){
|
||||
int32_t audio_channel_0[TD_BLOCK_FIR_LENGTH];
|
||||
int32_t audio_channel_1[TD_BLOCK_FIR_LENGTH];
|
||||
|
||||
chan_in_buf_word(c, audio_channel_0, TD_BLOCK_FIR_LENGTH);
|
||||
chan_in_buf_word(c, audio_channel_1, TD_BLOCK_FIR_LENGTH);
|
||||
|
||||
td_block_fir_add_data(audio_channel_0, &d0);
|
||||
td_block_fir_compute(audio_channel_0, &d0, f0);
|
||||
|
||||
td_block_fir_add_data(audio_channel_1, &d1);
|
||||
td_block_fir_compute(audio_channel_1, &d1, f1);
|
||||
|
||||
chan_out_buf_word(c, audio_channel_0, TD_BLOCK_FIR_LENGTH);
|
||||
chan_out_buf_word(c, audio_channel_1, TD_BLOCK_FIR_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void worker_tile(chanend_t c[WORKER_THREAD_COUNT]){
|
||||
int32_t mem_0[test_0_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_1[test_1_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_2[test_2_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_3[test_3_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_4[test_4_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_5[test_5_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_6[test_6_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_7[test_7_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_8[test_8_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_9[test_9_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_10[test_10_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_11[test_11_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_12[test_12_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_13[test_13_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_14[test_14_DATA_BUFFER_ELEMENTS];
|
||||
int32_t mem_15[test_15_DATA_BUFFER_ELEMENTS];
|
||||
|
||||
PAR_JOBS (
|
||||
PJOB(worker, (c[0], mem_0, test_0_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_0,
|
||||
mem_1, test_1_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_1)),
|
||||
PJOB(worker, (c[1], mem_2, test_2_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_2,
|
||||
mem_3, test_3_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_3)),
|
||||
PJOB(worker, (c[2], mem_4, test_4_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_4,
|
||||
mem_5, test_5_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_5)),
|
||||
PJOB(worker, (c[3], mem_6, test_6_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_6,
|
||||
mem_7, test_7_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_7)),
|
||||
PJOB(worker, (c[4], mem_8, test_8_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_8,
|
||||
mem_9, test_9_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_9)),
|
||||
PJOB(worker, (c[5], mem_10, test_10_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_10,
|
||||
mem_11, test_11_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_11)),
|
||||
PJOB(worker, (c[6], mem_12, test_12_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_12,
|
||||
mem_13, test_13_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_13)),
|
||||
PJOB(worker, (c[7], mem_14, test_14_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_14,
|
||||
mem_15, test_15_DATA_BUFFER_ELEMENTS, &td_block_fir_filter_test_15))
|
||||
);
|
||||
}
|
||||
|
||||
void audio_gen(chanend_t c[WORKER_THREAD_COUNT]){
|
||||
|
||||
hwtimer_t SysTimer = hwtimer_alloc();
|
||||
uint32_t from, to;
|
||||
|
||||
const uint32_t loops = 128;
|
||||
from = hwtimer_get_time(SysTimer);
|
||||
|
||||
int32_t buffer0[TD_BLOCK_FIR_LENGTH];
|
||||
int32_t buffer1[TD_BLOCK_FIR_LENGTH];
|
||||
for(int i=0;i<loops;i++){
|
||||
//send the unfiltered samples
|
||||
for(int worker_idx=0;worker_idx < WORKER_THREAD_COUNT;worker_idx++){
|
||||
chan_out_buf_word(c[worker_idx], buffer0, TD_BLOCK_FIR_LENGTH);
|
||||
chan_out_buf_word(c[worker_idx], buffer1, TD_BLOCK_FIR_LENGTH);
|
||||
}
|
||||
|
||||
//recieve the filtered samples
|
||||
for(int worker_idx=0;worker_idx < WORKER_THREAD_COUNT;worker_idx++){
|
||||
chan_in_buf_word(c[worker_idx], buffer0, TD_BLOCK_FIR_LENGTH);
|
||||
chan_in_buf_word(c[worker_idx], buffer1, TD_BLOCK_FIR_LENGTH);
|
||||
}
|
||||
}
|
||||
to = hwtimer_get_time(SysTimer);
|
||||
uint32_t elapsed = to - from;
|
||||
printf("elapsed: %lu\n", elapsed/loops);
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Copyright 2024-2025 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
|
||||
def bandpass_filters(length, count):
|
||||
for i in range(count):
|
||||
t = signal.firwin(length, (i + 1) / (count + 2))
|
||||
name = 'test_' + str(i)
|
||||
np.save(name, t)
|
||||
|
||||
if __name__ == '__main__':
|
||||
bandpass_filters(4008, 16)
|
||||
15
lib_audio_dsp/examples/app_td_block_fir/src/toplevel.xc
Normal file
15
lib_audio_dsp/examples/app_td_block_fir/src/toplevel.xc
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2024-2025 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <platform.h>
|
||||
|
||||
void audio_gen(chanend c[8]);
|
||||
void worker_tile(chanend c[8]);
|
||||
|
||||
int main(){
|
||||
chan c[8];
|
||||
par {
|
||||
on tile[0] : audio_gen(c);
|
||||
on tile[1] : worker_tile(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user