diff --git a/src/Audio.cc b/src/Audio.cc
new file mode 100644
index 0000000000000000000000000000000000000000..53278823101a93218f265dd99a8dfd19b132507d
--- /dev/null
+++ b/src/Audio.cc
@@ -0,0 +1,165 @@
+#include "Audio.hh"
+
+using namespace Vivy;
+
+AudioStreamCodec::AudioStreamCodec(AVFormatContext *format, AVStream *stream)
+    : codecId(stream->codecpar->codec_id)
+    , codecParams(stream->codecpar)
+    , audioStream(stream)
+    , dataFormat(format)
+{
+    codec = avcodec_find_decoder(codecId);
+    if (codec == nullptr)
+        throw std::runtime_error("failed to find a decoder for stream");
+
+    codecContext.reset(avcodec_alloc_context3(codec));
+    if (!codecContext)
+        throw std::runtime_error("failed to allocate codec context");
+
+    if (avcodec_parameters_to_context(codecContext.get(), codecParams) < 0)
+        throw std::runtime_error("failed to copy parameters to codec context");
+
+    if (avcodec_open2(codecContext.get(), codec, nullptr) < 0)
+        throw std::runtime_error("failed to open audio decoder for a stream");
+
+    SwrContext *s = dataSwrContext.get();
+    av_opt_set_int(s, "in_channel_count", codecContext->channels, 0);
+    av_opt_set_int(s, "out_channel_count", 1, 0);
+    av_opt_set_int(s, "in_channel_layout", static_cast<int64_t>(codecContext->channel_layout), 0);
+    av_opt_set_int(s, "out_channel_layout", AV_CH_LAYOUT_MONO, 0);
+    av_opt_set_int(s, "in_sample_rate", codecContext->sample_rate, 0);
+    av_opt_set_int(s, "out_sample_rate", resamplerSampleRate, 0);
+    av_opt_set_sample_fmt(s, "in_sample_fmt", codecContext->sample_fmt, 0);
+    av_opt_set_sample_fmt(s, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
+    swr_init(s);
+    if (!swr_is_initialized(s)) {
+        throw std::runtime_error("failed to initialize SwrContext resampler");
+    }
+}
+
+void
+AudioStreamCodec::decodeData()
+{
+    if (isDecoded())
+        throw std::logic_error("audio stream is already resampled");
+
+    AVPacket packet;
+    av_init_packet(&packet);
+
+    /* Iterate through frames */
+    while (av_read_frame(dataFormat, &packet) >= 0) {
+        /* Decode one frame */
+        int response = avcodec_send_packet(codecContext.get(), &packet);
+        if (response < 0) [[unlikely]] {
+            // av_err2str(response); <- Compound literals are a C99-specific feature
+            throw std::runtime_error("error while sending a packet to the decoder");
+        }
+
+        double *buffer           = nullptr;
+        int old_frame_nb_samples = 0;
+
+        while (response >= 0) {
+            response = avcodec_receive_frame(codecContext.get(), dataFrame.get());
+            if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) [[unlikely]] {
+                break;
+            } else if (response < 0) [[unlikely]] {
+                // av_err2str(response); <- Compound literals are a C99-specific feature
+                throw std::runtime_error("error while receiving a frame from the decoder");
+            }
+
+            /* Resample frames */
+            if (old_frame_nb_samples < dataFrame->nb_samples) {
+                if (nullptr != buffer)
+                    av_free(buffer);
+
+                old_frame_nb_samples = dataFrame->nb_samples;
+                av_samples_alloc(reinterpret_cast<uint8_t **>(&buffer), nullptr, 1,
+                                 dataFrame->nb_samples, AV_SAMPLE_FMT_DBL, 0);
+            }
+
+            if (const int frame_count_int =
+                    swr_convert(dataSwrContext.get(), reinterpret_cast<uint8_t **>(&buffer),
+                                dataFrame->nb_samples, (const uint8_t **)dataFrame->data,
+                                dataFrame->nb_samples);
+                frame_count_int < 0) [[unlikely]] {
+                throw std::runtime_error("error on frame count, is negative but should not be");
+            }
+
+            else [[likely]] {
+                const size_t frame_count = static_cast<size_t>(frame_count_int);
+
+                /* Append resampled frames to data */
+                dataRealPtr = (double *)realloc(
+                    dataRealPtr, (dataSize + (size_t)dataFrame->nb_samples) * sizeof(double));
+                memcpy(dataRealPtr + dataSize, buffer, frame_count * sizeof(double));
+                dataSize += frame_count;
+            }
+        }
+        if (buffer)
+            av_free(buffer);
+
+        av_packet_unref(&packet);
+    }
+}
+
+void
+AudioStreamCodec::cleanUpData() noexcept
+{
+    dataPtr.reset();
+    dataRealPtr = nullptr;
+    dataSize    = 0;
+}
+
+int
+AudioStreamCodec::getChannels() const noexcept
+{
+    return codecContext->channels;
+}
+
+int
+AudioStreamCodec::getSampleRate() const noexcept
+{
+    return codecContext->sample_rate;
+}
+
+int
+AudioStreamCodec::getDataSampleRate() const noexcept
+{
+    return resamplerSampleRate;
+}
+
+QString
+AudioStreamCodec::getName() const noexcept
+{
+    return QString(codec->name);
+}
+
+AVCodecID
+AudioStreamCodec::getCodecId() const noexcept
+{
+    return codecId;
+}
+
+qint64
+AudioStreamCodec::getBitRate() const noexcept
+{
+    return codecContext->bit_rate;
+}
+
+bool
+AudioStreamCodec::isDecoded() const noexcept
+{
+    return dataPtr != nullptr && dataRealPtr != nullptr;
+}
+
+size_t
+AudioStreamCodec::getDecodedDataSize() const noexcept
+{
+    return dataSize;
+}
+
+AudioStreamCodec::DataWeakPtr
+AudioStreamCodec::getDecodedData() const noexcept
+{
+    return DataWeakPtr{ dataPtr };
+}
diff --git a/src/Audio.hh b/src/Audio.hh
index 67ef33151b2557b21d7fd632be432f40e84be73e..d6076292c15a8b60f2f2f1832880a1c7f046bec9 100644
--- a/src/Audio.hh
+++ b/src/Audio.hh
@@ -17,6 +17,7 @@ extern "C" {
 #include <QtGlobal>
 #include <QMap>
 #include <QVector>
+#include <QString>
 #include <memory.h>
 
 namespace Vivy
@@ -54,44 +55,47 @@ class AudioStreamCodec final {
     using SwrContextPtr     = std::unique_ptr<SwrContext, decltype(swrContenxtDeleter)>;
 
 public:
-    AudioStreamCodec(AVStream *);
-    ~AudioStreamCodec();
+    AudioStreamCodec(AVFormatContext *, AVStream *);
+    ~AudioStreamCodec() = default;
 
     // Decode the stream
     void decodeData();
+    void cleanUpData() noexcept;
+    bool isDecoded() const noexcept;
+    int getDataSampleRate() const noexcept;
     size_t getDecodedDataSize() const noexcept;
     DataWeakPtr getDecodedData() const noexcept;
 
     // Some getters
     int getChannels() const noexcept;
     int getSampleRate() const noexcept;
-    const char *getName() const noexcept;
+    QString getName() const noexcept;
     AVCodecID getCodecId() const noexcept;
     qint64 getBitRate() const noexcept;
 
 private:
-    bool initFromStream() noexcept;  // Init all the object
-    void cleanupForReuse() noexcept; // Free everything, can now use initFromStream again
-
-    // Check if ready
-    bool isReadyForUse() const noexcept;
-    bool isResampled() const noexcept;
-
     // Codec related informations
     AVCodecID codecId{ AV_CODEC_ID_NONE };
-    AVCodecContextPtr codecContext{ nullptr };
-    AVCodecParameters *codecParams{ nullptr };
     AVCodec *codec{ nullptr };
+    AVCodecParameters *codecParams{ nullptr };
+    AVCodecContextPtr codecContext{ nullptr };
 
     // Stream is held by AudioFormatCtx
     AVStream *audioStream{ nullptr };
-    bool isInitFromStream{ false };
 
     // Resampled frame data
-    SwrContextPtr dataSwrContext{ nullptr, swrContenxtDeleter };
-    AVFramePtr dataFrame{ nullptr, avFrameDeleter };
-    DataPtr dataPtr{ nullptr, dataDeleter };
+    AVFormatContext *dataFormat;
+    SwrContextPtr dataSwrContext{ swr_alloc(), swrContenxtDeleter };
+    AVFramePtr dataFrame{ av_frame_alloc(), avFrameDeleter };
+    DataPtr dataPtr{ nullptr, dataDeleter }; // Holds dataRealPtr
+    double *dataRealPtr{ nullptr };
     size_t dataSize{ 0 };
+
+    // Constants for the resampler
+    static constexpr uint resamplerChunkSize  = 512;
+    static constexpr uint resamplerOverlap    = 128;
+    static constexpr uint resamplerDecalage   = resamplerChunkSize - resamplerOverlap;
+    static constexpr uint resamplerSampleRate = 44100;
 };
 
 /* Facility for pointers to AudioStreamCodec objects */