Rev 2097 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* recorder.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include "main.h"
#include "recorder.h"
#include "wav.h"
#include "audio.h"
#include "checkbutton.h"
#include "chrono.h"
#include "label.h"
#include "console.h"
#include "ui_list.h"
#include "menu.h"
#ifdef __WINDOWS_DS__
#include <windows.h>
#include <direct.h>
#include <shlobj.h>
#include <tchar.h>
#endif
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
extern ofstream dlog;
extern char BUFFER [];
recorder::recorder () : fname ("din.wav") {
buffer_size = 0;
saved = 1;
samples_buffer = 0;
stop_rec = stop_mins = stop_secs = 0;
}
void recorder::add (float* sample_buffer, int sample_buffer_size, int num_samples, checkbutton& cb_record1, checkbutton& cb_record2) {
if (saving_started) return;
float* recbuf = new float [num_samples];
if (recbuf == 0) {
cons << console::red << "Recorder ran out of memory!" << eol;
return;
}
memcpy (recbuf, sample_buffer, sample_buffer_size);
record_buffers.push_back (recbuf);
buffer_size += sample_buffer_size;
rec_time_add += clk.delta_secs;
sprintf (BUFFER, "Recorded %02d:%02d", rec_time_add.mins, rec_time_add.secs);
cb_record1.set_text (BUFFER);
cb_record2.set_text (BUFFER);
if (stop_rec) {
if (rec_time_add.mins >= stop_mins && rec_time_add.secs >= stop_secs) stop ();
}
saved = 0;
}
void recorder::start_saving () {
if (saving_started || (buffer_size == 0)) return;
#ifdef __WINDOWS_DS__
TCHAR desktop[MAX_PATH]={0};
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE, NULL, 0, desktop)));
std::basic_ostringstream<TCHAR> file_path;
file_path << desktop << _TEXT("\\") << fname.c_str();
file.open(file_path.str().c_str(), ios::binary);
cons << file_path.str().c_str() << eol;
#else
string home = getenv ("HOME");
string desktop ("/Desktop/");
folder = home + desktop;
string full_fname (folder + fname);
file.open (full_fname.c_str(), ios::binary);
#endif
write_wav_header<float> (file, SAMPLE_RATE, aout.num_channels, buffer_size);
iter = record_buffers.begin ();
jter = record_buffers.end ();
samples_buffer = new float [aout.samples_per_buffer];
saving_started = 1;
}
int recorder::save_some (checkbutton& cb) {
if (iter != jter) {
float* recbuf = *iter;
float* L = recbuf, *R = recbuf + aout.samples_per_channel; // separate L and R channels
for (int i = 0, j = aout.samples_per_channel, k = 0; i < j; ++i) { // interleave L and R channels
samples_buffer[k++] = L[i];
samples_buffer[k++] = R[i];
}
file.write ((const char*) samples_buffer, aout.samples_buffer_size); // write to disk!
++iter;
rec_time_save += clk.delta_secs;
sprintf (BUFFER, "Saved %02d:%02d of %02d:%02d", rec_time_save.mins, rec_time_save.secs, rec_time_add.mins, rec_time_add.secs);
cb.set_text (BUFFER);
return 1;
} else {
delete [] samples_buffer;
file.close ();
samples_buffer = 0;
saved = 1;
saving_started = 0;
rec_time_save.reset ();
return 0;
}
}
void recorder::clear () {
if (buffer_size && !saving_started) {
for (list<float*>::iterator citer = record_buffers.begin (), cjter = record_buffers.end (); citer != cjter; ++citer) delete[] *citer;
record_buffers.clear ();
buffer_size = 0;
rec_time_add.reset ();
saved = 1;
}
if (samples_buffer) delete[] samples_buffer;
}
recorder::~recorder () {
clear ();
dlog << "-- destroyed recorder --" << endl;
}
void recorder::set_fname (const string& _fname) {
fname = _fname;
}
void recorder::set_stop_at (int m, int s) {
stop_rec = 1;
stop_mins = m;
stop_secs = s;
}
void recorder::start () {
uis.cb_record.turn_on ();
MENU.cb_record.turn_on ();
}
void recorder::stop () {
uis.cb_record.turn_off ();
MENU.cb_record.turn_off ();
cons ("stopped-recording");
}
void recorder::normalise () {
float lmin, lmax;
float rmin, rmax;
lmin = rmin = lmax = rmax = 0;
for (list<float*>::iterator start = record_buffers.begin (), end = record_buffers.end (); start != end; ++start) {
float* recbuf = *start;
float* L = recbuf, *R = recbuf + aout.samples_per_channel;
for (int i = 0, j = aout.samples_per_channel; i < j; ++i) {
float li = L[i], ri = R[i];
if (li > lmax) lmax = li; else if (li < lmin) lmin = li;
if (ri > rmax) rmax = ri; else if (ri < rmin) rmin = ri;
}
}
float ldco = -(lmax + lmin)/2, rdco = -(rmin+rmax)/2;
cons << "lmin/max: " << lmin <<'/'<<lmax << " rmin/rmax: " << rmin <<'/'<<rmax<<eol;
cons <<"ldco="<<ldco<<",rdco="<<rdco<<eol;
lmin += ldco; rmin += rdco;
lmax += ldco; rmax += rdco;
float dl = lmax - lmin, dr = rmax - rmin;
float nmin = -1, nmax = 1, dn = nmax - nmin, dn_dl = dn / dl, dn_dr = dn / dr;
for (list<float*>::iterator start = record_buffers.begin (), end = record_buffers.end (); start != end; ++start) {
float* recbuf = *start;
float* L = recbuf, *R = recbuf + aout.samples_per_channel;
for (int i = 0, j = aout.samples_per_channel; i < j; ++i) {
float li = L[i]+ldco, ri = R[i]+rdco;
float lo = nmin + (li - lmin) * dn_dl, ro = nmin + (ri - rmin) * dn_dr;
L[i] = lo;
R[i] = ro;
}
}
}