diff --git a/meson.build b/meson.build
index b727ffeb..9ce86b02 100644
--- a/meson.build
+++ b/meson.build
@@ -285,6 +285,7 @@ linux_platform_src = ['platform/targets/linux/emulator/emulator.c',
'platform/mcu/x86_64/drivers/rng.cpp',
'platform/drivers/baseband/radio_linux.cpp',
'platform/drivers/audio/audio_linux.c',
+ 'platform/drivers/audio/file_source.c',
'platform/targets/linux/platform.c',
'platform/drivers/CPS/cps_io_libc.c']
diff --git a/platform/drivers/audio/file_source.c b/platform/drivers/audio/file_source.c
new file mode 100644
index 00000000..c5ea0ac5
--- /dev/null
+++ b/platform/drivers/audio/file_source.c
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * 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 *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+#include "file_source.h"
+
+static int fileSource_start(const uint8_t instance, const void *config, struct streamCtx *ctx)
+{
+ (void) instance;
+
+ if(ctx == NULL)
+ return -EINVAL;
+
+ if(ctx->running != 0)
+ return -EBUSY;
+
+ ctx->running = 1;
+
+ FILE *fp = fopen(config, "rb");
+ if(fp == NULL)
+ {
+ ctx->running = 0;
+ return -EINVAL;
+ }
+
+ ctx->priv = fp;
+
+ return 0;
+}
+
+static int fileSource_data(struct streamCtx *ctx, stream_sample_t **buf)
+{
+ if(ctx->running == 0)
+ return -1;
+
+ FILE *fp = (FILE *) ctx->priv;
+ stream_sample_t *dest = *buf;
+ size_t size = ctx->bufSize;
+ size_t i;
+
+ if(ctx->bufMode == BUF_CIRC_DOUBLE)
+ size /= 2;
+
+ // Read data from the file, rollover when end is reached
+ while (i < size)
+ {
+ size_t n = fread(dest + i, sizeof(stream_sample_t), size - i, fp);
+ if (n < (size - i))
+ fseek(fp, 0, SEEK_SET);
+
+ i += n;
+ }
+
+ return size;
+}
+
+static int fileSource_sync(struct streamCtx *ctx, uint8_t dirty)
+{
+ (void) dirty;
+
+ size_t size = ctx->bufSize;
+ if(ctx->bufMode == BUF_CIRC_DOUBLE)
+ size /= 2;
+
+ // Simulate the time needed to get a new chunck of data from an equivalent
+ // hardware peripheral.
+ uint32_t waitTime = (1000000 * size) / ctx->sampleRate;
+ usleep(waitTime);
+
+ return 0;
+}
+
+static void fileSource_stop(struct streamCtx *ctx)
+{
+ if(ctx->running == 0)
+ return;
+
+ FILE *fp = (FILE *) ctx->priv;
+ fclose(fp);
+}
+
+static void fileSource_halt(struct streamCtx *ctx)
+{
+ if(ctx->running == 0)
+ return;
+
+ FILE *fp = (FILE *) ctx->priv;
+ fclose(fp);
+}
+
+#pragma GCC diagnostic ignored "-Wpedantic"
+const struct audioDriver file_source_audio_driver =
+{
+ .start = fileSource_start,
+ .data = fileSource_data,
+ .sync = fileSource_sync,
+ .stop = fileSource_stop,
+ .terminate = fileSource_halt
+};
+#pragma GCC diagnostic pop
diff --git a/platform/drivers/audio/file_source.h b/platform/drivers/audio/file_source.h
new file mode 100644
index 00000000..e0ffaf10
--- /dev/null
+++ b/platform/drivers/audio/file_source.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * 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 *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef FILE_SOURCE_H
+#define FILE_SOURCE_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Driver providing an audio input stream from a file. File format should be
+ * raw, 16 bit, little endian. The configuration parameter is the file name with
+ * the full path.
+ */
+
+extern const struct audioDriver file_source_audio_driver;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_DAC_H */