arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
JupyterAudio.h
1#pragma once
3#include "AudioTools/CoreAudio/AudioStreams.h"
4#include "AudioTools/CoreAudio/AudioOutput.h"
5#include "AudioTools/AudioCodecs/CodecWAV.h"
6#include <string.h>
7#include <iostream>
8#include <fstream>
9#include <filesystem>
10#include <stdio.h>
11#include "nlohmann/json.hpp"
12#include "xtl/xbase64.hpp"
13
14namespace audio_tools {
15
19class FileOutput : public Print {
20public:
21 FileOutput(std::fstream &stream){
22 p_audio_stream = &stream;
23 }
24 size_t write(const uint8_t *data, size_t len) override {
25 p_audio_stream->write((const char*)data,len);
26 return len;
27 }
28 int availableForWrite() override {
29 return 1024;
30 }
31protected:
32 std::fstream *p_audio_stream=nullptr;
33};
34
35
40template <typename T>
41class ChartT {
42public:
43 void setup(std::string fName, int channelCount, int channelNo) {
44 this->fname = fName;
45 this->channels = channelCount;
46 if (this->channels==0){
47 LOGE("Setting channels to 0");
48 }
49 this->channel = channelNo;
50 }
51
52 int getChannels() {
53 return this->channels;
54 }
55
56 int getChannel() {
57 return this->channel;
58 }
59
61 const std::string chartData() {
62 str.clear();
63 str.str("");
64 // reset buffer;
65 if (channel<channels){
66 ifstream is;
67 is.open(fname, is.binary);
68 is.seekg(wav_header_size, is.beg);
69 std::list<int16_t> audioList;
70 T buffer[channels];
71 size_t rec_size = channels*sizeof(T);
72 while(is.read((char *)buffer, rec_size)){
73 audioList.push_back(transform(buffer[channel]));
74 }
75 string str_size = "102400"; //std::to_string(audioList.size());
76 str << "<style>div.x-svg {width: "<< str_size <<"px; }</style>";
77 str << "<div class='x-svg'><svg viewBox='0 0 "<< str_size << " 100'> <polyline fill='none' stroke='blue' stroke-width='1' points ='";
78 // copy data from input stream
79 size_t idx = 0;
80 for(int16_t sample: audioList){
81 str << idx++ << "," << sample << " ";
82 }
83 str << "'/></svg></div>";
84 } else {
85 str << "<p>Channel " << channel << " of " << channels << " does not exist!</p>";
86 }
87 return str.str();
88 }
89
90protected:
91 std::stringstream str;
92 std::string fname;
93 const int wav_header_size = 44;
94 int channels=0;
95 int channel=0;
96
97 int transform(int x){
98 int result = x / 1000; // scale -32 to 32
99 result += 60; // shift down
100 return result;
101 }
102};
103
104using Chart = ChartT<int16_t>;
105
110template <typename T>
112public:
113
114 JupyterAudioT(const char* fileName, AudioStream &stream, int bufferCount=20, int bufferSize=1024) {
115 buffer_count = bufferCount;
116 p_audio_stream = &stream;
117 cfg = stream.audioInfo();
118 copier.resize(bufferSize);
119 fname = fileName;
120 if (fileExists()){
121 remove(fileName);
122 }
123 }
124
125 ChartT<T> &chart(int channel=0) {
126 createWAVFile();
127 assert(cfg.channels>0);
128 chrt.setup(fname, cfg.channels, channel);
129 return chrt;
130 }
131
132 // provide the file name
133 const std::string &name() const {
134 return fname;
135 }
136
137 // provides the absolute file path as string
138 const std::string path() const {
139 std::filesystem::path p = fname;
140 std::string result = std::filesystem::absolute(p);
141 return result;
142 }
143
144 // fills a wav file with data once, the first time it was requested
145 void createWAVFile(){
146 try{
147 if (!fileExists()){
148 std::fstream fstream(fname, fstream.binary | fstream.trunc | fstream.out);
149 FileOutput fp(fstream);
150 wave_encoder.setAudioInfo(audioInfo());
151 out.setOutput(&fp);
152 out.setEncoder(&wave_encoder);
153 out.begin(); // output to decoder
154 copier.begin(out, *p_audio_stream);
155 copier.copyN(buffer_count);
156 fstream.close();
157 }
158 } catch(const std::exception& ex){
159 std::cerr << ex.what();
160 }
161 }
162
163 bool fileExists() {
164 ifstream f(fname.c_str());
165 return f.good();
166 }
167
168 int bufferCount(){
169 return buffer_count;
170 }
171
172 // provides the wav data as bas64 encded string
173 std::string audio() {
174 std::ifstream fin(fname, std::ios::binary);
175 std::stringstream m_buffer;
176 m_buffer << fin.rdbuf();
177 return xtl::base64encode(m_buffer.str());
178 }
179
180 // Provides the audion information
182 return cfg;
183 }
184
185protected:
186 AudioStream *p_audio_stream=nullptr;
187 ChartT<T> chrt;
188 WAVEncoder wave_encoder;
190 StreamCopyT<T> copier;
191 AudioInfo cfg;
192 string fname;
193 size_t buffer_count=0;
194};
195
196using JupyterAudio = JupyterAudioT<int16_t>;
197
198} // namespace audio_tools
199
201nl::json mime_bundle_repr(Chart &in) {
202 auto bundle = nl::json::object();
203 bundle["text/html"] = in.chartData();
204 return bundle;
205}
206
208nl::json mime_bundle_repr(JupyterAudio &in) {
209 auto bundle = nl::json::object();
210 in.createWAVFile();
211 bundle["text/html"] = "<audio controls "
212 "src='data:audio/wav;base64," +
213 in.audio() + "'/>";
214 return bundle;
215}
216
If you want to use the framework w/o Arduino you need to provide the implementation of a couple of cl...
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:119
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition BaseStream.h:150
Displays audio in a Jupyter as chart Just wrapps a stream to provide the chart data.
Definition JupyterAudio.h:41
const std::string chartData()
Provides data as svg polyline.
Definition JupyterAudio.h:61
A more natural Print class to process encoded data (aac, wav, mp3...). Just define the output and the...
Definition AudioEncoded.h:21
void setOutput(Print &outputStream) override
Defines/Changes the output target.
Definition AudioEncoded.h:97
bool begin() override
Starts the processing - sets the status to active.
Definition AudioEncoded.h:137
Simple layer for Print object to write to a c++ file.
Definition JupyterAudio.h:19
Output to Jupyter. We write the data just to a file from where we can load the data again for differe...
Definition JupyterAudio.h:111
AudioInfo audioInfo()
provides the actual input AudioInfo
Definition JupyterAudio.h:181
Definition NoArduino.h:62
Typed Stream Copy which supports the conversion from channel to 2 channels. We make sure that we allw...
Definition StreamCopy.h:24
A simple WAV file encoder. If no AudioEncoderExt is specified the WAV file contains PCM data,...
Definition CodecWAV.h:469
virtual void setAudioInfo(AudioInfo from) override
Update actual WAVAudioInfo.
Definition CodecWAV.h:513
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57