Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/WavWriter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
set(FIRMWARE_NAME WavWriter)
set(FIRMWARE_SOURCES WavWriter.cpp)
include(DaisyProject)
14 changes: 14 additions & 0 deletions examples/WavWriter/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Project Name
TARGET = WavWriter

# Sources
CPP_SOURCES = WavWriter.cpp

USE_FATFS=1

# Library Locations
LIBDAISY_DIR = ../..

# Core location, and generic Makefile.
SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core
include $(SYSTEM_FILES_DIR)/Makefile
91 changes: 91 additions & 0 deletions examples/WavWriter/WavWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/** Generation of a simple Audio signal */
#include "daisy_seed.h"
#include <cmath>

/** This prevents us from having to type "daisy::" in front of a lot of things. */
using namespace daisy;

static constexpr float kTargetSr = 48000.f;
static constexpr size_t kTransferSize = 16384;

/** Global Hardware access */
DaisySeed hw;
SdmmcHandler sdmmc;
FatFSInterface fsi;
WavWriter<kTransferSize> wav_writer;

/** Basic Fixed-frequency oscillator */
struct SimpleOsc
{
static constexpr float kTargetFreq = 220.f;
static constexpr float kSignalIncrement
= (M_TWOPI * kTargetFreq) * (1.f / kTargetSr);
float phs_;
SimpleOsc() : phs_(0.f) {}

inline float RenderSample()
{
float signal = sin(phs_) * 0.5f;
phs_ += kSignalIncrement;
if(phs_ > M_TWOPI)
phs_ -= M_TWOPI;
return signal;
}
};

int main(void)
{
/** Initialize our hardware */
hw.Init();

/** Set up SD Card */
SdmmcHandler::Config sd_cfg;
sd_cfg.Defaults();
sd_cfg.width = SdmmcHandler::BusWidth::BITS_1;
sdmmc.Init(sd_cfg);
FatFSInterface::Config fsi_cfg;
fsi_cfg.media = FatFSInterface::Config::MEDIA_SD;
fsi.Init(fsi_cfg);
if(f_mount(&fsi.GetSDFileSystem(), "/", 0) != FR_OK)
{
while(1)
{
hw.SetLed((System::GetNow() & 127) > 63);
}
}
hw.SetLed(true);

/** Set up WAV File */
WavWriter<kTransferSize>::Config cfg;
cfg.bitspersample = 16;
cfg.channels = 2;
cfg.samplerate = kTargetSr;
wav_writer.Init(cfg);

/** Prepare to record a 1s 220Hz Audio File */
SimpleOsc oscillator;
size_t duration_sec = 1;
size_t duration_in_samps = duration_sec * kTargetSr;

wav_writer.OpenFile("ExampleWavFile.wav");
for(size_t i = 0; i < duration_in_samps; i++)
{
// If recording Realtime Audio:
// The rendering/sampling should occur in the realtime audio interrupt
float sample = oscillator.RenderSample();
float samps_to_write[2] = {sample, sample};
wav_writer.Sample(samps_to_write);

// The actual DiskIO should happen outside of the realtime audio interrupt
// For offline-rendering, it is okay to do this check on every sample.
wav_writer.Write();
}
// Flush and Close
wav_writer.SaveFile();

while(1)
{
// Blink Afterwards to show success
hw.SetLed((System::GetNow() & 511) > 255);
}
}
34 changes: 17 additions & 17 deletions src/util/WavWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
namespace daisy
{
/** Audio Recording Module
**
** Record audio into a working buffer that is gradually written to a WAV file on an SD Card.
**
** Recordings are made with floating point input, and will be converted to the
** specified bits per sample internally
** Record audio into a working buffer that is gradually written to a WAV file on an SD Card.
**
** Recordings are made with floating point input, and will be converted to the
** specified bits per sample internally
**
** For now only 16-bit and 32-bit (signed int) formats are supported
** f32 and s24 formats will be added next
Expand All @@ -18,7 +18,7 @@ namespace daisy
** effect on the performance of the streaming behavior of the WavWriter.
** Memory use can be calculated as: (2 * transfer_size) bytes
** Performance optimal with sizes: 16384, 32768
**
**
** To use:
** 1. Create a WavWriter<size> object (e.g. WavWriter<32768> writer)
** 2. Configure the settings as desired by creating a WavWriter<32768>::Config struct and setting the settings.
Expand All @@ -27,7 +27,7 @@ namespace daisy
** 5. Write to it within your audio callback using: writer.Sample(value)
** 6. Fill the Wav File on the SD Card with data from your main loop by running: writer.Write()
** 7. When finished with the recording finalize, and close the file with: writer.SaveFile();
**
**
** */
template <size_t transfer_size>
class WavWriter
Expand All @@ -52,7 +52,7 @@ class WavWriter
int32_t bitspersample;
};

/** State of the internal Writing mechanism.
/** State of the internal Writing mechanism.
** When the buffer is a certain amount full one section will write its contents
** while the other is still being written to. This is performed circularly
** so that audio will be uninterrupted during writing. */
Expand Down Expand Up @@ -87,12 +87,12 @@ class WavWriter
}

/** Records the current sample into the working buffer,
** queues writes to media when necessary.
**
** queues writes to media when necessary.
**
** \param in should be a pointer to an array of samples */
void Sample(const float *in)
{
for(size_t i = 0; i < cfg_.channels; i++)
for(int i = 0; i < cfg_.channels; i++)
{
switch(cfg_.bitspersample)
{
Expand Down Expand Up @@ -145,28 +145,28 @@ class WavWriter
recording_ = false;

// Flush remaining data in the transfer buffer
if (wptr_ > 0) // Check if there is unwritten data in the buffer
if(wptr_ > 0) // Check if there is unwritten data in the buffer
{
uint32_t remaining_size = wptr_ * (cfg_.bitspersample / 8);
// Ensure remaining_size does not exceed the buffer size
if (remaining_size > sizeof(transfer_buff))
if(remaining_size > sizeof(transfer_buff))
{
remaining_size = sizeof(transfer_buff);
}
f_write(&fp_, transfer_buff, remaining_size, &bw);
}

wavheader_.FileSize = CalcFileSize();
f_lseek(&fp_, 0);
f_write(&fp_, &wavheader_, sizeof(wavheader_), &bw);
f_close(&fp_);

// Clear the transfer buffer and reset the buffer state
memset(transfer_buff, 0, sizeof(transfer_buff));
bstate_ = BufferState::IDLE;
wptr_ = 0; // Reset the write pointer
num_samps_ = 0; // Reset the number of samples
recording_ = false; // Ensure recording is inactive
bstate_ = BufferState::IDLE;
wptr_ = 0; // Reset the write pointer
num_samps_ = 0; // Reset the number of samples
recording_ = false; // Ensure recording is inactive
}

/** Opens a file for writing. Writes the initial WAV Header, and gets ready for stream-based recording. */
Expand Down
Loading