diff --git a/.gitignore b/.gitignore
index 8cfdfce..6e26e55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,8 @@
 audio
 solo.dbg
 solo.opt
+
+cmake-*
+.idea
+
+build/
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index f06b4b4..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,6 +0,0 @@
-[submodule "libspatialaudio"]
-	path = libspatialaudio
-	url = https://github.com/ILLIXR/libspatialaudio.git
-[submodule "portaudio"]
-	path = portaudio
-	url = https://github.com/PortAudio/portaudio.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..994e9fe
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,53 @@
+cmake_minimum_required(VERSION 3.16)
+set(CMAKE_VERBOSE_MAKEFILE True)
+
+project(audio_pipeline VERSION 1.0 LANGUAGES CXX)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+include(FindPkgConfig)
+
+set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -Wall -fPIC -Wno-overloaded-virtual")
+set(CMAKE_CXX_FLAGE_RELEASE "-O3 -DNDEBUG -Wall -fPIC -Wno-overloaded-virtual")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-ggdb -O3 -Wall -fPIC -Wno-overloaded-virtual")
+set(ILLIXR_INTEGRATION ON)
+add_definitions(-DILLIXR_INTEGRATION)
+set(ILLIXR_ROOT "" CACHE PATH "Path to ILLIXR headers")
+
+pkg_check_modules(PORTAUDIO REQUIRED portaudio-2.0>=19)
+pkg_check_modules(SPATIALAUDIO REQUIRED spatialaudio)
+find_package(spdlog REQUIRED)
+find_package(SQLite3 REQUIRED)
+
+if (CMAKE_VERSION VERSION_LESS "3.30.0")
+    find_package(Boost REQUIRED COMPONENTS filesystem serialization iostreams)
+else()
+    find_package(Boost REQUIRED COMPONENTS filesystem serialization iostreams CONFIG)
+endif()
+
+add_executable(solo${ILLIXR_BUILD_SUFFIX}.exe src/main.cpp)
+add_library(plugin.audio_pipeline${ILLIXR_BUILD_SUFFIX} SHARED
+            src/audio.cpp
+            include/audio.hpp
+            src/plugin.cpp
+            include/plugin.hpp
+            src/sound.cpp
+            include/sound.hpp
+            src/realtime.cpp
+            include/realtime.hpp
+)
+include_directories(${CMAKE_INSTALL_PREFIX}/include ${PROJECT_SOURCE_DIR}/include ${ILLIXR_ROOT})
+
+if(ILLIXR_INTEGRATION)
+    target_compile_definitions(plugin.audio_pipeline${ILLIXR_BUILD_SUFFIX} PUBLIC -DAUDIO_SAMPLES=\"${CMAKE_INSTALL_PREFIX}/etc/audio_pipeline\")
+endif()
+
+target_include_directories(plugin.audio_pipeline${ILLIXR_BUILD_SUFFIX} PUBLIC ${PORTAUDIO_INCLUDE_DIRS} ${SPATIALAUDIO_INCLUDE_DIRS})
+target_link_libraries(plugin.audio_pipeline${ILLIXR_BUILD_SUFFIX} PUBLIC ${PORTAUDIO_LIBRARIES} ${SPATIALAUDIO_LIBRARIES} spdlog::spdlog sqlite3)
+
+target_link_libraries(solo${ILLIXR_BUILD_SUFFIX}.exe PUBLIC plugin.audio_pipeline${ILLIXR_BUILD_SUFFIX} pthread spdlog::spdlog Boost::serialization)
+
+install(TARGETS plugin.audio_pipeline${ILLIXR_BUILD_SUFFIX} DESTINATION lib)
+install(TARGETS solo${ILLIXR_BUILD_SUFFIX}.exe DESTINATION bin)
+install(DIRECTORY ${CMAKE_SOURCE_DIR}/samples
+        DESTINATION etc/audio_pipeline)
diff --git a/include/audio.h b/include/audio.h
deleted file mode 100644
index d40fd1d..0000000
--- a/include/audio.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#pragma once
-
-#include "sound.h"
-#include <vector>
-#include <string>
-#include <string_view>
-#include <optional>
-#include <pthread.h>
-
-namespace ILLIXR_AUDIO{
-	class ABAudio{
-
-	public:
-		// Process types
-		enum class ProcessType {
-			FULL, 			// FULL for output wav file
-			ENCODE, 		// For profiling, do file reading and encoding without file output
-			DECODE			// For profiling, do ambisonics decoding without file output
-		};
-		ABAudio(std::string outputFilePath, ProcessType processType);
-		// Process a block (1024) samples of sound
-		void processBlock();
-		// Load sound source files (predefined)
-		void loadSource();
-
-		// Buffer of most recent processed block for fast copying to audio buffer
-		short mostRecentBlockL[BLOCK_SIZE];
-		short mostRecentBlockR[BLOCK_SIZE];
-		bool buffer_ready;
-
-		// Number of blocks left to process before this stream is complete
-		unsigned long num_blocks_left;
-
-	private:
-		ProcessType processType;
-		// a list of sound sources in this audio
-		std::vector<Sound> soundSrcs;
-		// target output file
-        std::optional<std::ofstream> outputFile;
-		// decoder associated with this audio
-		CAmbisonicBinauralizer decoder;
-		// ambisonics rotator associated with this audio
-		CAmbisonicProcessor rotator;
-		// ambisonics zoomer associated with this audio
-		CAmbisonicZoomer zoomer;
-
-		int frame = 0;
-
-		// Generate dummy WAV output file header
-		void generateWAVHeader();
-		// Read in data from WAV files and encode into ambisonics
-		void readNEncode(CBFormat& sumBF);
-		// Apply rotation and zoom effects to the ambisonics sound field
-		void rotateNZoom(CBFormat& sumBF);
-		// Write out a block of samples to the output file
-		void writeFile(float** resultSample);
-
-		// Abort failed configuration
-		void configAbort(const std::string_view& compName) const;
-
-		void updateRotation();
-		void updateZoom();
-	};
-}
diff --git a/include/audio.hpp b/include/audio.hpp
new file mode 100644
index 0000000..9e3cbcc
--- /dev/null
+++ b/include/audio.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+#ifdef ILLIXR_INTEGRATION
+
+#include "illixr/switchboard.hpp"
+
+#endif
+
+#include "sound.hpp"
+
+#include <optional>
+#include <pthread.h>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace ILLIXR::audio {
+class ab_audio {
+public:
+    // Process types
+    enum class process_type {
+        FULL,            // FULL for output wav file
+        ENCODE,        // For profiling, do file reading and encoding without file output
+        DECODE            // For profiling, do ambisonics decoding without file output
+    };
+
+    ab_audio(std::string output_file_path, process_type proc_type_in);
+
+    // Process a block (1024) samples of sound
+    void process_block();
+
+    // Load sound source files (predefined)
+#ifdef ILLIXR_INTEGRATION
+    void load_source(const std::shared_ptr<ILLIXR::switchboard> &sb);
+#else
+    void load_source();
+#endif
+
+    // Buffer of most recent processed block for fast copying to audio buffer
+    short most_recent_block_L[BLOCK_SIZE];
+    short most_recent_block_R[BLOCK_SIZE];
+    bool buffer_ready;
+
+    // Number of blocks left to process before this stream is complete
+    unsigned long num_blocks_left;
+
+private:
+    // Generate dummy WAV output file header
+    void generate_wav_header();
+
+    // Read in data from WAV files and encode into ambisonics
+    void read_and_encode(CBFormat &sum_bf);
+
+    // Apply rotation and zoom effects to the ambisonics sound field
+    void rotate_and_zoom(CBFormat &sum_bf);
+
+    // Write out a block of samples to the output file
+    void write_file(float **result_sample);
+
+    // Abort failed configuration
+    void config_abort(const std::string_view &comp_name) const;
+
+    void update_rotation();
+
+    void update_zoom();
+
+    process_type                 process_type_;
+    std::vector<sound>           sound_srcs_;    //!< a list of sound sources in this audio
+    std::optional<std::ofstream> output_file_;   //!< target output file
+    CAmbisonicBinauralizer       decoder_;       //!< decoder associated with this audio
+    CAmbisonicProcessor          rotator_;       //!< ambisonics rotator associated with this audio
+    CAmbisonicZoomer             zoomer_;        //!< ambisonics zoomer associated with this audio
+    int                          frame_ = 0;
+};
+}
diff --git a/include/common b/include/common
deleted file mode 120000
index 60d3b0a..0000000
--- a/include/common
+++ /dev/null
@@ -1 +0,0 @@
-../common
\ No newline at end of file
diff --git a/include/plugin.hpp b/include/plugin.hpp
new file mode 100644
index 0000000..95aa0ba
--- /dev/null
+++ b/include/plugin.hpp
@@ -0,0 +1,47 @@
+#pragma once
+#include "audio.hpp"
+
+#include "illixr/data_format/pose.hpp"
+#include "illixr/phonebook.hpp"
+#include "illixr/relative_clock.hpp"
+#include "illixr/switchboard.hpp"
+#include "illixr/threadloop.hpp"
+
+
+namespace ILLIXR {
+
+class audio_xcoding : public threadloop {
+public:
+    audio_xcoding(phonebook *pb_, bool encoding);
+
+    void _p_thread_setup() override;
+
+    skip_option _p_should_skip() override;
+
+    void _p_one_iteration() override;
+
+private:
+    const std::shared_ptr<switchboard>          switchboard_;
+    const std::shared_ptr<relative_clock>       clock_;
+    switchboard::reader<data_format::pose_type> pose_;
+    ILLIXR::audio::ab_audio                     xcoder_;
+    time_point                                  last_time_;
+    static constexpr duration                   audio_period_{
+            freq_to_period(static_cast<double>(SAMPLERATE) / static_cast<double>(BLOCK_SIZE))};
+    bool                                        encoding_;
+};
+
+class audio_pipeline : public plugin {
+public:
+    [[maybe_unused]] audio_pipeline(const std::string &name_, phonebook *pb_)
+            : plugin{name_, pb_}, audio_encoding{pb_, true}, audio_decoding{pb_, false} {}
+
+    void start() override;
+
+    void stop() override;
+
+private:
+    audio_xcoding audio_encoding;
+    audio_xcoding audio_decoding;
+};
+}
diff --git a/include/realtime.h b/include/realtime.hpp
similarity index 86%
rename from include/realtime.h
rename to include/realtime.hpp
index 1f31d40..73002b6 100644
--- a/include/realtime.h
+++ b/include/realtime.hpp
@@ -3,10 +3,7 @@
  *
  * The realtime audio support requires the PortAudio library.
  */
-
-#ifndef REALTIME_H
-#define REALTIME_H
-
+#pragma once
 /*
  * illixr_rt_init
  *
@@ -23,6 +20,4 @@
  * This function is blocking and will not return until the audio source is exhausted.
  * Launch this in an independent thread!
  */
-void *illixr_rt_init(void *audioObj);
-
-#endif // REALTIME_H
+void *illixr_rt_init(void *audio_obj);
diff --git a/include/sound.h b/include/sound.h
deleted file mode 100644
index 69797ab..0000000
--- a/include/sound.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#pragma once
-
-#include <string>
-#include <fstream>
-#include <memory>
-#include <spatialaudio/Ambisonics.h>
-
-constexpr std::size_t SAMPLERATE {48000U};
-constexpr std::size_t BLOCK_SIZE {512U};
-constexpr std::size_t NORDER     {3U};
-constexpr std::size_t NUM_SRCS   {16U};
-
-#define NUM_CHANNELS (OrderToComponents(NORDER, true))
-
-namespace ILLIXR_AUDIO{
-	class Sound{
-	public:
-		Sound(std::string srcFile, unsigned nOrder, bool b3D);
-		// set sound src position
-		void setSrcPos(const PolarPoint& pos);
-		// set sound amplitude scale
-		void setSrcAmp(float ampScale);
-		// read sound samples from mono 16bit WAV file and encode into ambisonics format
-        std::weak_ptr<CBFormat> readInBFormat();
-	private:
-		// corresponding sound src file
-		std::fstream srcFile;
-		// sample buffer HARDCODE
-		float sample[BLOCK_SIZE];
-		// ambisonics format sound buffer
-        std::shared_ptr<CBFormat> BFormat;
-		// ambisonics encoder, containing format info, position info, etc.
-		CAmbisonicEncoderDist BEncoder;
-		// ambisonics position
-		PolarPoint srcPos;
-		// amplitude scale to avoid clipping
-		float amp;
-
-		// Abort failed configuration
-		void configAbort(const std::string_view& compName) const;
-	};
-}
diff --git a/include/sound.hpp b/include/sound.hpp
new file mode 100644
index 0000000..b02a185
--- /dev/null
+++ b/include/sound.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <fstream>
+#include <memory>
+#include <spatialaudio/Ambisonics.h>
+#include <string>
+
+constexpr std::size_t SAMPLERATE {48000U};
+constexpr std::size_t BLOCK_SIZE {512U};
+constexpr std::size_t NORDER     {3U};
+constexpr std::size_t NUM_SRCS   {16U};
+
+#define NUM_CHANNELS (OrderToComponents(NORDER, true))
+
+namespace ILLIXR::audio{
+class sound{
+public:
+    sound(std::string src_filename, unsigned n_order, bool b3D);
+
+    // set sound src position
+    void set_src_pos(const PolarPoint& pos);
+
+    // set sound amplitude scale
+    [[maybe_unused]] void set_src_amp(float amp_scale);
+
+    // read sound samples from mono 16bit WAV file and encode into ambisonics format
+    std::weak_ptr<CBFormat> read_in_b_format();
+private:
+    // Abort failed configuration
+    void config_abort(const std::string_view& comp_name) const;
+
+    std::fstream               src_file_;            //!< corresponding sound src file
+    float                      sample_[BLOCK_SIZE];  //!< sample buffer HARDCODE
+    std::shared_ptr<CBFormat>  b_format_;            //!< ambisonics format sound buffer
+    CAmbisonicEncoderDist      b_encoder_;           //!< ambisonics encoder, containing format info, position info, etc.
+    PolarPoint                 src_pos_;             //!< ambisonics position
+    float                      amp_;                 //!< amplitude scale to avoid clipping
+};
+}
diff --git a/libspatialaudio b/libspatialaudio
deleted file mode 160000
index 77a901e..0000000
--- a/libspatialaudio
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 77a901e337a63aa981745ab369ccf597834a37a5
diff --git a/portaudio b/portaudio
deleted file mode 160000
index 7e2a33c..0000000
--- a/portaudio
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 7e2a33c875c6b2b53a8925959496cc698765621f
diff --git a/src/audio.cpp b/src/audio.cpp
index 93985b1..bd37d0c 100644
--- a/src/audio.cpp
+++ b/src/audio.cpp
@@ -1,79 +1,98 @@
+#include "audio.hpp"
+
+#ifdef ILLIXR_INTEGRATION
+#include "illixr/error_util.hpp"
+#include "illixr/switchboard.hpp"
+#endif /// ILLIXR_INTEGRATION
+
 #include <iostream>
 #include <cassert>
 #include <cstdlib>
-#include "audio.h"
 
 #ifdef ILLIXR_INTEGRATION
-#include "../common/error_util.hpp"
+#include <filesystem>
 #endif /// ILLIXR_INTEGRATION
 
-std::string get_path() {
+
 #ifdef ILLIXR_INTEGRATION
-    const char* AUDIO_ROOT_c_str = std::getenv("AUDIO_ROOT");
-    if (!AUDIO_ROOT_c_str) {
-        ILLIXR::abort("Please define AUDIO_ROOT");
-    }
-    std::string AUDIO_ROOT = std::string{AUDIO_ROOT_c_str};
-    return AUDIO_ROOT + "samples/";
+std::string get_path(const std::shared_ptr<ILLIXR::switchboard>& sb) {
+    if(sb) {
+        std::string path = std::string{AUDIO_SAMPLES} + "/samples";
+        if (std::filesystem::is_directory(path))
+            return path;
+        const char *AUDIO_ROOT = sb->get_env_char("AUDIO_ROOT");
+        if (!AUDIO_ROOT)
+            throw std::runtime_error("Ausio samples not found, please define AUDIO_ROOT");
+
+        return std::string{AUDIO_ROOT} + "/samples/";
+    } else {
 #else
-    return "samples/";
-#endif /// ILLIXR_INTEGRATION
+        std::string get_path() {
+#endif
+        return "samples/";
+#ifdef ILLIXR_INTEGRATION
+    }
+#endif
 }
 
-ILLIXR_AUDIO::ABAudio::ABAudio(std::string outputFilePath, ProcessType procTypeIn)
-    : processType {procTypeIn}
-    , outputFile {
-          processType == ILLIXR_AUDIO::ABAudio::ProcessType::FULL
-          ? std::make_optional<std::ofstream>(outputFilePath, std::ios_base::out | std::ios_base::binary)
+ILLIXR::audio::ab_audio::ab_audio(std::string output_file_path, process_type proc_type_in)
+    : process_type_ {proc_type_in}
+    , output_file_ {
+          process_type_ == ILLIXR::audio::ab_audio::process_type::FULL
+          ? std::make_optional<std::ofstream>(output_file_path, std::ios_base::out | std::ios_base::binary)
           : std::nullopt
-      }
-{
-    if (processType == ILLIXR_AUDIO::ABAudio::ProcessType::FULL) {
-        generateWAVHeader();
+      } {
+    if (process_type_ == ILLIXR::audio::ab_audio::process_type::FULL) {
+        generate_wav_header();
     }
 
     unsigned int tailLength {0U};
 
     /// Binauralizer as ambisonics decoder
-    if (!decoder.Configure(NORDER, true, SAMPLERATE, BLOCK_SIZE, tailLength)) {
-        configAbort("decoder");
+    if (!decoder_.Configure(NORDER, true, SAMPLERATE, BLOCK_SIZE, tailLength)) {
+        config_abort("decoder");
     }
 
     /// Processor to rotate
-    if (!rotator.Configure(NORDER, true, BLOCK_SIZE, tailLength)) {
-        configAbort("rotator");
+    if (!rotator_.Configure(NORDER, true, BLOCK_SIZE, tailLength)) {
+        config_abort("rotator");
     }
 
     /// Processor to zoom
-    if (!zoomer.Configure(NORDER, true, tailLength)) {
-        configAbort("zoomer");
+    if (!zoomer_.Configure(NORDER, true, tailLength)) {
+        config_abort("zoomer");
     }
 
     buffer_ready = false;
     num_blocks_left = 0;
 }
 
-
-void ILLIXR_AUDIO::ABAudio::loadSource(){
-#ifndef NDEBUG
+#ifdef ILLIXR_INTEGRATION
+void ILLIXR::audio::ab_audio::load_source(const std::shared_ptr<ILLIXR::switchboard>& sb){
+#else
+void ILLIXR::audio::ab_audio::loadSource(){
+#endif
     /// Temporarily clear errno here if set (until merged with #225)
     if (errno > 0) {
         errno = 0;
     }
-#endif /// NDEBUG
 
     /// Add a bunch of sound sources
+#ifdef ILLIXR_INTEGRATION
+    const std::string samples_folder{get_path(sb)};
+#else
     const std::string samples_folder{get_path()};
-    if (processType == ILLIXR_AUDIO::ABAudio::ProcessType::FULL) {
-        soundSrcs.emplace_back(samples_folder + "lectureSample.wav", NORDER, true);
-        soundSrcs.back().setSrcPos({
+#endif
+    if (process_type_ == ILLIXR::audio::ab_audio::process_type::FULL) {
+        sound_srcs_.emplace_back(samples_folder + "lectureSample.wav", NORDER, true);
+        sound_srcs_.back().set_src_pos({
             .fAzimuth   = -0.1f,
             .fElevation = 3.14f/2,
             .fDistance  = 1
         });
 
-        soundSrcs.emplace_back(samples_folder + "radioMusicSample.wav", NORDER, true);
-        soundSrcs.back().setSrcPos({
+        sound_srcs_.emplace_back(samples_folder + "radioMusicSample.wav", NORDER, true);
+        sound_srcs_.back().set_src_pos({
             .fAzimuth   = 1.0f,
             .fElevation = 0.0f,
             .fDistance  = 5
@@ -86,12 +105,12 @@ void ILLIXR_AUDIO::ABAudio::loadSource(){
             /// it has not been set
             /// The path here is broken, we need to specify a relative path like we do in kimera
             assert(errno == 0);
-            soundSrcs.emplace_back(samples_folder + "lectureSample.wav", NORDER, true);
+            sound_srcs_.emplace_back(samples_folder + "lectureSample.wav", NORDER, true);
             assert(errno == 0);
 
-            soundSrcs.back().setSrcPos({
+            sound_srcs_.back().set_src_pos({
                 .fAzimuth   = i * -0.1f,
-                .fElevation = i * 3.14f/2,
+                .fElevation = i * 3.14f / 2,
                 .fDistance  = i * 1.0f
             });
         }
@@ -99,7 +118,7 @@ void ILLIXR_AUDIO::ABAudio::loadSource(){
 }
 
 
-void ILLIXR_AUDIO::ABAudio::processBlock() {
+void ILLIXR::audio::ab_audio::process_block() {
     float** resultSample = new float*[2];
     resultSample[0] = new float[BLOCK_SIZE];
     resultSample[1] = new float[BLOCK_SIZE];
@@ -108,18 +127,18 @@ void ILLIXR_AUDIO::ABAudio::processBlock() {
     CBFormat sumBF;
     sumBF.Configure(NORDER, true, BLOCK_SIZE);
 
-    if (processType != ILLIXR_AUDIO::ABAudio::ProcessType::DECODE) {
-        readNEncode(sumBF);
+    if (process_type_ != ILLIXR::audio::ab_audio::process_type::DECODE) {
+        read_and_encode(sumBF);
     }
 
-    if (processType != ILLIXR_AUDIO::ABAudio::ProcessType::ENCODE) {
+    if (process_type_ != ILLIXR::audio::ab_audio::process_type::ENCODE) {
         /// Processing garbage data if just decoding
-        rotateNZoom(sumBF);
-        decoder.Process(&sumBF, resultSample);
+        rotate_and_zoom(sumBF);
+        decoder_.Process(&sumBF, resultSample);
     }
 
-    if (processType == ILLIXR_AUDIO::ABAudio::ProcessType::FULL) {
-        writeFile(resultSample);
+    if (process_type_ == ILLIXR::audio::ab_audio::process_type::FULL) {
+        write_file(resultSample);
         if (num_blocks_left > 0) {
             num_blocks_left--;
         }
@@ -132,11 +151,11 @@ void ILLIXR_AUDIO::ABAudio::processBlock() {
 
 
 /// Read from WAV files and encode into ambisonics format
-void ILLIXR_AUDIO::ABAudio::readNEncode(CBFormat& sumBF) {
-    for (unsigned int soundIdx = 0U; soundIdx < soundSrcs.size(); ++soundIdx) {
+void ILLIXR::audio::ab_audio::read_and_encode(CBFormat& sumBF) {
+    for (unsigned int soundIdx = 0U; soundIdx < sound_srcs_.size(); ++soundIdx) {
         /// 'readInBFormat' now returns a weak_ptr, ensuring that we don't access
         /// or destruct a freed resource
-        std::weak_ptr<CBFormat> tempBF_weak {soundSrcs[soundIdx].readInBFormat()};
+        std::weak_ptr<CBFormat> tempBF_weak {sound_srcs_[soundIdx].read_in_b_format()};
         std::shared_ptr<CBFormat> tempBF{tempBF_weak.lock()};
 
         if (tempBF != nullptr) {
@@ -147,13 +166,13 @@ void ILLIXR_AUDIO::ABAudio::readNEncode(CBFormat& sumBF) {
             }
         } else {
             static constexpr std::string_view read_fail_msg{
-                "[ABAudio] Failed to read/encode. Sound has expired or been destroyed."
+                "[ab_audio] Failed to read/encode. Sound has expired or been destroyed."
             };
 #ifdef ILLIXR_INTEGRATION
-            ILLIXR::abort(std::string{read_fail_msg});
+            throw std::runtime_error(std::string{read_fail_msg});
 #else
             std::cerr << read_fail_msg << std::endl;
-            std::abort();
+            throw std::runtime_error(std::string{read_fail_msg});
 #endif /// ILLIXR_INTEGRATION
         }
    }
@@ -161,49 +180,49 @@ void ILLIXR_AUDIO::ABAudio::readNEncode(CBFormat& sumBF) {
 
 
 /// Simple rotation
-void ILLIXR_AUDIO::ABAudio::updateRotation() {
-    frame++;
-    Orientation head(0,0,1.0*frame/1500*3.14*2);
-    rotator.SetOrientation(head);
-    rotator.Refresh();
+void ILLIXR::audio::ab_audio::update_rotation() {
+    frame_++;
+    Orientation head(0, 0, 1.0 * frame_ / 1500 * 3.14 * 2);
+    rotator_.SetOrientation(head);
+    rotator_.Refresh();
 }
 
 
 /// Simple zoom
-void ILLIXR_AUDIO::ABAudio::updateZoom() {
-    frame++;
-    zoomer.SetZoom(sinf(frame/100));
-    zoomer.Refresh();
+void ILLIXR::audio::ab_audio::update_zoom() {
+    frame_++;
+    zoomer_.SetZoom(sinf(frame_/100));
+    zoomer_.Refresh();
 }
 
 
 /// Process some rotation and zoom effects
-void ILLIXR_AUDIO::ABAudio::rotateNZoom(CBFormat& sumBF) {
-    updateRotation();
-    rotator.Process(&sumBF, BLOCK_SIZE);
-    updateZoom();
-    zoomer.Process(&sumBF, BLOCK_SIZE);
+void ILLIXR::audio::ab_audio::rotate_and_zoom(CBFormat& sumBF) {
+    update_rotation();
+    rotator_.Process(&sumBF, BLOCK_SIZE);
+    update_zoom();
+    zoomer_.Process(&sumBF, BLOCK_SIZE);
 }
 
 
-void ILLIXR_AUDIO::ABAudio::writeFile(float** resultSample) {
+void ILLIXR::audio::ab_audio::write_file(float** resultSample) {
     /// Normalize(Clipping), then write into file
     for (std::size_t sampleIdx = 0U; sampleIdx < BLOCK_SIZE; ++sampleIdx) {
         resultSample[0][sampleIdx] = std::max(std::min(resultSample[0][sampleIdx], +1.0f), -1.0f);
         resultSample[1][sampleIdx] = std::max(std::min(resultSample[1][sampleIdx], +1.0f), -1.0f);
         int16_t tempSample0 = (int16_t)(resultSample[0][sampleIdx]/1.0 * 32767);
         int16_t tempSample1 = (int16_t)(resultSample[1][sampleIdx]/1.0 * 32767);
-        outputFile->write((char*)&tempSample0,sizeof(short));
-        outputFile->write((char*)&tempSample1,sizeof(short));
+        output_file_->write((char*)&tempSample0,sizeof(short));
+        output_file_->write((char*)&tempSample1,sizeof(short));
 
         /// Cache written block in object buffer until needed by realtime audio thread
-        mostRecentBlockL[sampleIdx] = tempSample0;
-        mostRecentBlockR[sampleIdx] = tempSample1;
+        most_recent_block_L[sampleIdx] = tempSample0;
+        most_recent_block_R[sampleIdx] = tempSample1;
     }
 }
 
 
-namespace ILLIXR_AUDIO
+namespace ILLIXR::audio
 {
     /// NOTE: WAV FILE SIZE is not correct
     typedef struct __attribute__ ((packed)) WAVHeader_t
@@ -225,20 +244,18 @@ namespace ILLIXR_AUDIO
 }
 
 
-void ILLIXR_AUDIO::ABAudio::generateWAVHeader() {
+void ILLIXR::audio::ab_audio::generate_wav_header() {
     /// Brute force wav header
     WAVHeader wavh;
-    outputFile->write((char*)&wavh, sizeof(WAVHeader));
+    output_file_->write((char*)&wavh, sizeof(WAVHeader));
 }
 
 
-void ILLIXR_AUDIO::ABAudio::configAbort(const std::string_view& compName) const
+void ILLIXR::audio::ab_audio::config_abort(const std::string_view& comp_name) const
 {
     static constexpr std::string_view cfg_fail_msg{"[ABAudio] Failed to configure "};
-#ifdef ILLIXR_INTEGRATION
-    ILLIXR::abort(std::string{cfg_fail_msg} + std::string{compName});
-#else
+#ifndef ILLIXR_INTEGRATION
     std::cerr << cfg_fail_msg << compName << std::endl;
-    std::abort();
 #endif /// ILLIXR_INTEGRATION
+    throw std::runtime_error(std::string{cfg_fail_msg} + std::string{comp_name});
 }
diff --git a/src/audio_component.cpp b/src/audio_component.cpp
deleted file mode 100644
index 78e34cf..0000000
--- a/src/audio_component.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-#include <future>
-#include <thread>
-
-#include "common/data_format.hpp"
-#include "common/phonebook.hpp"
-#include "common/relative_clock.hpp"
-#include "common/switchboard.hpp"
-#include "common/threadloop.hpp"
-
-#include <audio.h>
-
-using namespace ILLIXR;
-
-class audio_xcoding : public threadloop
-{
-public:
-    audio_xcoding(phonebook *pb_, bool encoding)
-        : threadloop{encoding ? "audio_encoding" : "audio_decoding", pb_}
-        , _m_sb{pb->lookup_impl<switchboard>()}
-        , _m_clock{pb->lookup_impl<RelativeClock>()}
-        , _m_pose{_m_sb->get_reader<pose_type>("slow_pose")}
-        , xcoder{"", encoding ? ILLIXR_AUDIO::ABAudio::ProcessType::ENCODE : ILLIXR_AUDIO::ABAudio::ProcessType::DECODE}
-        , encoding_{encoding}
-    {
-        xcoder.loadSource();
-    }
-
-    virtual void _p_thread_setup() override {
-        last_time = _m_clock->now();
-    }
-
-    virtual skip_option _p_should_skip() override {
-        last_time += audio_period;
-        std::this_thread::sleep_for(last_time - _m_clock->now());
-        return skip_option::run;
-    }
-
-    virtual void _p_one_iteration() override {
-        if (!encoding_) {
-            [[maybe_unused]] auto most_recent_pose = _m_pose.get_ro_nullable();
-        }
-        xcoder.processBlock();
-    }
-
-private:
-    const std::shared_ptr<switchboard> _m_sb;
-    const std::shared_ptr<RelativeClock> _m_clock;
-    switchboard::reader<pose_type> _m_pose;
-    ILLIXR_AUDIO::ABAudio xcoder;
-    time_point last_time;
-    static constexpr duration audio_period{freq2period(static_cast<double>(SAMPLERATE) / static_cast<double>(BLOCK_SIZE))};
-    bool encoding_;
-};
-
-class audio_pipeline : public plugin {
-public:
-    audio_pipeline(std::string name_, phonebook *pb_)
-        : plugin{name_, pb_}
-        , audio_encoding{pb_, true }
-        , audio_decoding{pb_, false}
-    { }
-
-    virtual void start() override {
-        audio_encoding.start();
-        audio_decoding.start();
-        plugin::start();
-    }
-
-    virtual void stop() override {
-        audio_encoding.stop();
-        audio_decoding.stop();
-        plugin::stop();
-    }
-
-private:
-    audio_xcoding audio_encoding;
-    audio_xcoding audio_decoding;
-};
-
-PLUGIN_MAIN(audio_pipeline)
diff --git a/src/main.cpp b/src/main.cpp
index 3318bf8..1dce50f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,11 +1,14 @@
-#include <audio.h>
+#include "illixr/switchboard.hpp"
+
+#include "audio.hpp"
+#include "realtime.hpp"
+
 #include <iostream>
-#include <realtime.h>
 #include <pthread.h>
 
 int main(int argc, char const *argv[])
 {
-    using namespace ILLIXR_AUDIO;
+    using namespace ILLIXR::audio;
 
     if (argc < 2) {
         std::cout << "Usage: " << argv[0] << " <number of size " << BLOCK_SIZE << " blocks to process> ";
@@ -15,27 +18,27 @@ int main(int argc, char const *argv[])
     }
 
     const int numBlocks = atoi(argv[1]);
-    ABAudio::ProcessType procType(ABAudio::ProcessType::FULL);
+    ab_audio::process_type procType(ab_audio::process_type::FULL);
     if (argc > 2){
         if (!strcmp(argv[2], "encode"))
-            procType = ABAudio::ProcessType::ENCODE;
+            procType = ab_audio::process_type::ENCODE;
         else
-            procType = ABAudio::ProcessType::DECODE;
+            procType = ab_audio::process_type::DECODE;
     }
 
-    ABAudio audio("output.wav", procType);
-    audio.loadSource();
+    ab_audio audio("output.wav", procType);
+    audio.load_source(std::make_shared<ILLIXR::switchboard>(nullptr));
     audio.num_blocks_left = numBlocks;
 
     // Launch realtime audio thread for audio processing
-    if (procType == ABAudio::ProcessType::FULL) {
+    if (procType == ab_audio::process_type::FULL) {
         pthread_t rt_audio_thread;
-        pthread_create(&rt_audio_thread, NULL, illixr_rt_init, (void *)&audio);
-        pthread_join(rt_audio_thread, NULL);
+        pthread_create(&rt_audio_thread, nullptr, illixr_rt_init, (void *)&audio);
+        pthread_join(rt_audio_thread, nullptr);
     }
     else {
         for (int i = 0; i < numBlocks; ++i) {
-            audio.processBlock();
+            audio.process_block();
         }
     }
 
diff --git a/src/plugin.cpp b/src/plugin.cpp
new file mode 100644
index 0000000..d952ec4
--- /dev/null
+++ b/src/plugin.cpp
@@ -0,0 +1,51 @@
+#include "../include/plugin.hpp"
+
+#include <future>
+#include <thread>
+
+
+using namespace ILLIXR;
+
+
+audio_xcoding::audio_xcoding(phonebook *pb_, bool encoding)
+        : threadloop{encoding ? "audio_encoding" : "audio_decoding", pb_},
+          switchboard_{pb_->lookup_impl<switchboard>()}, clock_{pb_->lookup_impl<relative_clock>()},
+          pose_{switchboard_->get_reader<data_format::pose_type>("slow_pose")}, xcoder_{"", encoding
+                                                                                            ? ILLIXR::audio::ab_audio::process_type::ENCODE
+                                                                                            : ILLIXR::audio::ab_audio::process_type::DECODE},
+          encoding_{encoding} {
+    xcoder_.load_source(switchboard_);
+}
+
+void audio_xcoding::_p_thread_setup() {
+    last_time_ = clock_->now();
+}
+
+threadloop::skip_option audio_xcoding::_p_should_skip() {
+    last_time_ += audio_period_;
+    std::this_thread::sleep_for(last_time_ - clock_->now());
+    return skip_option::run;
+}
+
+void audio_xcoding::_p_one_iteration() {
+    if (!encoding_) {
+        [[maybe_unused]] auto most_recent_pose = pose_.get_ro_nullable();
+    }
+    xcoder_.process_block();
+}
+
+
+void audio_pipeline::start() {
+    audio_encoding.start();
+    audio_decoding.start();
+    plugin::start();
+}
+
+void audio_pipeline::stop() {
+    audio_encoding.stop();
+    audio_decoding.stop();
+    plugin::stop();
+}
+
+
+PLUGIN_MAIN(audio_pipeline)
diff --git a/src/realtime.cpp b/src/realtime.cpp
index be29188..59c84f5 100644
--- a/src/realtime.cpp
+++ b/src/realtime.cpp
@@ -1,16 +1,16 @@
-#include <realtime.h>
-#include <stdio.h>
-#include <math.h>
-#include <sound.h>
-#include <audio.h>
-#include "portaudio.h"
+#include "sound.hpp"
+#include "audio.hpp"
+
+#include <cstdio>
+#include <portaudio.h>
+#include <realtime.hpp>
 
 #define SAMPLE_RATE ((SAMPLERATE))
 #define AUDIO_FORMAT   paInt16
 typedef unsigned short          sample_t;
 #define SILENCE       ((sample_t)0x00)
 
-using namespace ILLIXR_AUDIO;
+using namespace ILLIXR::audio;
 
 /*
  * illixr_rt_cb
@@ -20,25 +20,27 @@ using namespace ILLIXR_AUDIO;
  * When the realtime audio driver requires more buffered data, this callback
  * method is called. This is where ILLIXR feeds more audio data to the realtime audio engine.
  */
-static int illixr_rt_cb( const void *inputBuffer, void *outputBuffer,
-                           unsigned long framesPerBuffer,
-                           const PaStreamCallbackTimeInfo* timeInfo,
-                           PaStreamCallbackFlags statusFlags,
-                           void *userData ) {
-
-    sample_t *out = (sample_t*)outputBuffer;
-    ABAudio *audioObj = (ABAudio *)userData;
+static int illixr_rt_cb(const void *input_buffer, void *output_buffer,
+                        unsigned long frames_per_buffer,
+                        const PaStreamCallbackTimeInfo* time_info,
+                        PaStreamCallbackFlags status_flags,
+                        void *user_data ) {
+    (void) frames_per_buffer;
+    (void) time_info;
+    (void) status_flags;
+    auto *out = (sample_t*)output_buffer;
+    auto *audio_obj = (ab_audio *)user_data;
     int i;
-    (void) inputBuffer; /* Prevent unused variable warnings. */
+    (void) input_buffer; /* Prevent unused variable warnings. */
 
     // As this is an interrupt context, lots of data processing is ill-advised.
     // In future iterations, all processing will be handled in a separate thread with proper
     // synchronization primatives.
-    audioObj->processBlock();
+    audio_obj->process_block();
 
     for (i = 0; i < BLOCK_SIZE; i++) {
-        *out++ = audioObj->mostRecentBlockL[i];
-        *out++ = audioObj->mostRecentBlockR[i];
+        *out++ = audio_obj->most_recent_block_L[i];
+        *out++ = audio_obj->most_recent_block_R[i];
     }
 
     return 0;
@@ -46,6 +48,15 @@ static int illixr_rt_cb( const void *inputBuffer, void *outputBuffer,
 
 /*******************************************************************/
 
+void* print_err(const PaError err) {
+    Pa_Terminate();
+    fprintf( stderr, "An error occured while using the portaudio stream\n" );
+    fprintf( stderr, "Error number: %d\n", err );
+    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+    return (void *)err;
+
+}
+
 /*
  * illixr_rt_init
  *
@@ -62,64 +73,56 @@ static int illixr_rt_cb( const void *inputBuffer, void *outputBuffer,
  * This function is blocking and will not return until the audio source is exhausted.
  * Launch this in an independent thread!
  */
-void *illixr_rt_init(void *audioObj)
-{
-    PaStreamParameters  outputParameters;
+void *illixr_rt_init(void *audio_obj) {
+    PaStreamParameters  output_parameters;
     PaStream*           stream;
     PaError             err;
-    PaTime              streamOpened;
-    int                 i, totalSamps;
+    PaTime              stream_opened;
 
     printf("Initializing audio hardware...\n");
 
     err = Pa_Initialize();
     if( err != paNoError )
-        goto error;
+        return print_err(err);
 
-    outputParameters.device = Pa_GetDefaultOutputDevice(); /* Default output device. */
-    if (outputParameters.device == paNoDevice) {
-      fprintf(stderr,"Error: No default output device.\n");
-      goto error;
+    output_parameters.device = Pa_GetDefaultOutputDevice(); /* Default output device. */
+    if (output_parameters.device == paNoDevice) {
+        fprintf(stderr,"Error: No default output device.\n");
+        return print_err(err);
     }
-    outputParameters.channelCount = 2;                     /* Stereo output. */
-    outputParameters.sampleFormat = AUDIO_FORMAT;
-    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
-    outputParameters.hostApiSpecificStreamInfo = NULL;
+    output_parameters.channelCount = 2;                     /* Stereo output. */
+    output_parameters.sampleFormat = AUDIO_FORMAT;
+    output_parameters.suggestedLatency = Pa_GetDeviceInfo( output_parameters.device )->defaultLowOutputLatency;
+    output_parameters.hostApiSpecificStreamInfo = NULL;
     err = Pa_OpenStream( &stream,
                          NULL,      /* No input. */
-                         &outputParameters,
+                         &output_parameters,
                          SAMPLE_RATE,
                          BLOCK_SIZE,       /* Frames per buffer. */
                          paClipOff, /* We won't output out of range samples so don't bother clipping them. */
                          illixr_rt_cb,
-                         audioObj );
+                         audio_obj);
     if( err != paNoError )
-        goto error;
+        return print_err(err);
 
-    streamOpened = Pa_GetStreamTime( stream ); /* Time in seconds when stream was opened (approx). */
+    stream_opened = Pa_GetStreamTime( stream ); /* Time in seconds when stream was opened (approx). */
 
     printf("Launching stream!\n");
     err = Pa_StartStream( stream );
     if( err != paNoError )
-        goto error;
+        return print_err(err);
 
     // Spin until the audio marks itself as being complete
-    while( ((ABAudio *)audioObj)->num_blocks_left > 0) {
-        Pa_Sleep(0.25f);
+    while( ((ab_audio *)audio_obj)->num_blocks_left > 0) {
+        Pa_Sleep(25);
     }
 
     printf("Stopping stream\n");
 
     err = Pa_CloseStream( stream );
     if( err != paNoError )
-        goto error;
+        return print_err(err);
 
     Pa_Terminate();
     return (void *)err;
-error:
-    Pa_Terminate();
-    fprintf( stderr, "An error occured while using the portaudio stream\n" );
-    fprintf( stderr, "Error number: %d\n", err );
-    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
-    return (void *)err;
 }
diff --git a/src/sound.cpp b/src/sound.cpp
index f8bf196..c3b3aab 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -1,46 +1,42 @@
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstdlib>
-#include "sound.h"
+#include "sound.hpp"
 
 #ifdef ILLIXR_INTEGRATION
-#include "../common/error_util.hpp"
+#include "illixr/error_util.hpp"
 #endif /// ILLIXR_INTEGRATION
 
+#include <cassert>
+#include <cstddef>
 
-ILLIXR_AUDIO::Sound::Sound(
-    std::string srcFilename,
-    [[maybe_unused]] unsigned int nOrder,
-    [[maybe_unused]] bool b3D
-) : srcFile{srcFilename, std::fstream::in}
-  , BFormat{std::make_shared<CBFormat>()}
-  , amp{1.0}
-{
+
+ILLIXR::audio::sound::sound(std::string src_filename, unsigned int n_order, bool b3D)
+        : src_file_{src_filename, std::fstream::in}
+        , b_format_{std::make_shared<CBFormat>()}
+        , amp_{1.0} {
+    (void) b3D;
     /// NOTE: This is currently only accepts mono channel 16-bit depth WAV file
     /// TODO: Change brutal read from wav file
     constexpr std::size_t SRC_FILE_SIZE {44U};
     std::byte temp[SRC_FILE_SIZE];
-    srcFile.read(reinterpret_cast<char*>(temp), sizeof(temp));
+    src_file_.read(reinterpret_cast<char*>(temp), sizeof(temp));
 
     /// BFormat file initialization
-    if (!BFormat->Configure(nOrder, true, BLOCK_SIZE)) {
-        configAbort("BFormat");
+    if (!b_format_->Configure(n_order, true, BLOCK_SIZE)) {
+        config_abort("BFormat");
     }
-    BFormat->Refresh();
+    b_format_->Refresh();
 
     /// Encoder initialization
-    if (!BEncoder.Configure(nOrder, true, SAMPLERATE)) {
-        configAbort("BEncoder");
+    if (!b_encoder_.Configure(n_order, true, SAMPLERATE)) {
+        config_abort("b_encoder_");
     }
-    BEncoder.Refresh();
+    b_encoder_.Refresh();
 
-    srcPos.fAzimuth   = 0.0f;
-    srcPos.fElevation = 0.0f;
-    srcPos.fDistance  = 0.0f;
+    src_pos_.fAzimuth   = 0.0f;
+    src_pos_.fElevation = 0.0f;
+    src_pos_.fDistance  = 0.0f;
 
-    BEncoder.SetPosition(srcPos);
-    BEncoder.Refresh();
+    b_encoder_.SetPosition(src_pos_);
+    b_encoder_.Refresh();
 
     /// Clear errno, as this constructor is setting the flag (with value 2)
     /// A temporary fix.
@@ -48,43 +44,41 @@ ILLIXR_AUDIO::Sound::Sound(
 }
 
 
-void ILLIXR_AUDIO::Sound::setSrcPos(const PolarPoint& pos) {
-    srcPos.fAzimuth   = pos.fAzimuth;
-    srcPos.fElevation = pos.fElevation;
-    srcPos.fDistance  = pos.fDistance;
+void ILLIXR::audio::sound::set_src_pos(const PolarPoint& pos) {
+    src_pos_.fAzimuth   = pos.fAzimuth;
+    src_pos_.fElevation = pos.fElevation;
+    src_pos_.fDistance  = pos.fDistance;
 
-    BEncoder.SetPosition(srcPos);
-    BEncoder.Refresh();
+    b_encoder_.SetPosition(src_pos_);
+    b_encoder_.Refresh();
 }
 
 
-void ILLIXR_AUDIO::Sound::setSrcAmp(float ampScale) {
-    amp = ampScale;
+[[maybe_unused]] void ILLIXR::audio::sound::set_src_amp(float amp_scale) {
+    amp_ = amp_scale;
 }
 
 
 /// TODO: Change brutal read from wav file
-std::weak_ptr<CBFormat> ILLIXR_AUDIO::Sound::readInBFormat() {
+std::weak_ptr<CBFormat> ILLIXR::audio::sound::read_in_b_format() {
     float sampleTemp[BLOCK_SIZE];
-    srcFile.read((char*)sampleTemp, BLOCK_SIZE * sizeof(short));
+    src_file_.read((char*)sampleTemp, BLOCK_SIZE * sizeof(short));
 
     /// Normalize samples to -1 to 1 float, with amplitude scale
     constexpr float SAMPLE_DIV {(2 << 14) - 1}; /// 32767.0f == 2^14 - 1
     for (std::size_t i = 0U; i < BLOCK_SIZE; ++i) {
-        sample[i] = amp * (sampleTemp[i] / SAMPLE_DIV);
+        sample_[i] = amp_ * (sampleTemp[i] / SAMPLE_DIV);
     }
 
-    BEncoder.Process(sample, BLOCK_SIZE, BFormat.get());
-    return BFormat;
+    b_encoder_.Process(sample_, BLOCK_SIZE, b_format_.get());
+    return b_format_;
 }
 
-void ILLIXR_AUDIO::Sound::configAbort(const std::string_view& compName) const
+void ILLIXR::audio::sound::config_abort(const std::string_view& comp_name) const
 {
     static constexpr std::string_view cfg_fail_msg{"[Sound] Failed to configure "};
-#ifdef ILLIXR_INTEGRATION
-    ILLIXR::abort(std::string{cfg_fail_msg} + std::string{compName});
-#else
+#ifndef ILLIXR_INTEGRATION
     std::cerr << cfg_fail_msg << compName << std::endl;
-    std::abort();
 #endif /// ILLIXR_INTEGRATION
+    throw std::runtime_error(std::string{cfg_fail_msg} + std::string{comp_name});
 }