diff --git a/Makefile.am b/Makefile.am index bd20888..df15925 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,8 +28,8 @@ libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQu libcwHDR += src/libcw/cwNbMpScQueue.h libcwSRC += src/libcw/cwNbMpScQueue.cpp -libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwMidiFile.h src/libcw/cwWaveTableBank.h -libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwMidiFile.cpp src/libcw/cwWaveTableBank.cpp +libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwMidiFile.h src/libcw/cwWaveTableBank.h src/libcw/cwWaveTableNotes.h +libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwMidiFile.cpp src/libcw/cwWaveTableBank.cpp src/libcw/cwWaveTableNotes.cpp libcwHDR += src/libcw/cwAudioFileOps.h src/libcw/cwAudioTransforms.h src/libcw/cwDspTransforms.h src/libcw/cwAudioFileProc.h src/libcw/cwPvAudioFileProc.h libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwDspTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.cpp diff --git a/cwWaveTableNotes.cpp b/cwWaveTableNotes.cpp new file mode 100644 index 0000000..0dd9301 --- /dev/null +++ b/cwWaveTableNotes.cpp @@ -0,0 +1,293 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwTest.h" +#include "cwMem.h" +#include "cwFile.h" +#include "cwText.h" +#include "cwObject.h" +#include "cwFileSys.h" +#include "cwAudioFile.h" +#include "cwMath.h" +#include "cwVectOps.h" +#include "cwMidi.h" +#include "cwDspTypes.h" +#include "cwDsp.h" +#include "cwAudioTransforms.h" +#include "cwWaveTableBank.h" +#include "cwWaveTableNotes.h" + +cw::rc_t cw::wt_note::gen_note( wt_bank::handle_t wtbH, + unsigned instr_idx, + unsigned midi_pitch, + unsigned velocity, + srate_t srate, + sample_t** audioChA, + unsigned audioChN, + unsigned audioFrmN ) +{ + rc_t rc = kOkRC; + unsigned chN = audioChN; // output audio channels + const wt_bank::multi_ch_wt_seq_t* mcs = nullptr; // wave table ptr + sample_t* aM = nullptr; // temp. audio buffer + const unsigned kDspFrmN = 64; // default frame request count + unsigned reqFrmN = 0; // count of sample frames requestdd + unsigned retFrmN = 0; // countof sample frames returned + unsigned audioChFrmIdx = 0; // current audio frame index into audioChA[] + audiofile::handle_t afH; + + // multi-channel wave table oscillator + struct dsp::multi_ch_wt_seq_osc::obj_str osc; + + // get the requested wave table + if((rc = wt_bank::get_wave_table( wtbH, instr_idx, midi_pitch, velocity, mcs )) != kOkRC ) + { + goto errLabel; + } + + // if the wave table has fewer channels than the output audio buffer + if( mcs->chN < chN ) + chN = mcs->chN; + + // TODO: VERIFY srate == SAMPLE RATE OF WAVETABLES + // mcs->valid_srate(srate) + + // allocate and setup xthe oscillator + if((rc = create(&osc,chN,mcs)) != kOkRC ) + { + rc = cwLogError(rc,"multi-ch-wt-seq-osc create failed."); + goto errLabel; + } + + // allocate a tempory audio buffer + aM = mem::allocZ(chN*kDspFrmN); + + // for each sample in the output signal + while( retFrmN==reqFrmN && audioChFrmIdx < audioFrmN ) + { + // calc. the count of requested output audio frames on this iteration + reqFrmN = std::min(kDspFrmN,audioFrmN-audioChFrmIdx); + + // generate reqFrmN output samples with the oscillator + if((rc = process(&osc, aM, chN, reqFrmN, retFrmN)) != kOkRC ) + goto errLabel; + + // copy the generated signals into the output signal + for(unsigned i=0; idelta_sec; + + unsigned beg_frm_idx = (unsigned)floor(secs*srate); + unsigned dur_frm_cnt = (unsigned)floor(n->dur_sec*srate); + + if( beg_frm_idx > outFrmN ) + { + // TODO: + assert(0); + } + + if( beg_frm_idx + dur_frm_cnt > outFrmN ) + { + // TODO: + assert(0); + } + + for(unsigned j=0; jinstr_idx, n->pitch, n->velocity, srate, chA, outChN, dur_frm_cnt)) != kOkRC ) + { + rc = cwLogError(rc,"Generate note failed on 'instr:%i pitch:%i vel:%i.",n->instr_idx, n->pitch, n->velocity); + goto errLabel; + } + + } + +errLabel: + cwLogInfo("Generated %6.1f seconds of audio.",secs); + return rc; +} + +cw::rc_t cw::wt_note::gen_notes( wt_bank::handle_t wtbH, + const note_t* noteA, + unsigned noteN, + srate_t srate, + unsigned audioChN, + const char* out_audio_fname, + unsigned audio_bits) +{ + rc_t rc = kOkRC; + unsigned audioFrmN = 0; + sample_t* audioM = nullptr; + double max_sec = 0; + sample_t* chA[ audioChN ]; + + double secs = 0; + for(unsigned i=0; i max_sec ) + max_sec = secs+noteA[i].dur_sec; + } + + cwLogInfo("Allocated %i notes in %6.1f seconds of audio.",noteN,max_sec); + + audioFrmN = (unsigned)ceil( max_sec * srate ); + audioM = mem::allocZ( audioFrmN * audioChN ); + + for(unsigned i=0; i max_pitch ) + { + rc = cwLogError(kInvalidArgRC,"The min pitch:%i is greater than the max pitch:%i.",min_pitch,max_pitch); + goto errLabel; + } + + if((rc = wt_bank::create(wtbH,2,wtb_json_fname)) != kOkRC ) + { + goto errLabel; + } + + if(!filesys::isDir(out_dir)) + filesys::makeDir(out_dir); + + for(unsigned midi_pitch=min_pitch; midi_pitch<=max_pitch; ++midi_pitch) + { + unsigned velA[ midi::kMidiVelCnt ]; + unsigned velCnt = 0; + double secs = 0; + const unsigned fnameN = 32; + char fname[fnameN+1]; + + // get the sampled velocities for the instr_idx/midi_pitch + if((rc = wt_bank::instr_pitch_velocities( wtbH, instr_idx, midi_pitch, velA, midi::kMidiVelCnt, velCnt )) != kOkRC ) + { + goto errLabel; + } + + // allocate the note records array + noteA = mem::resizeZ(noteA,velCnt); + + // fill in the note record array with one note for each sampled velocity + for(unsigned i=0; i