From 6327cc9a766b4eab3d1f581d549e6f2f42d0ff57 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 14 Dec 2024 09:57:01 -0500 Subject: [PATCH] cwIoAudioMidi.h/cpp,Makefile.am : Remove cwIoAudioMidi.h/cpp because it is not being used. --- Makefile.am | 4 +- cwIoAudioMidi.cpp | 1048 --------------------------------------------- cwIoAudioMidi.h | 18 - 3 files changed, 2 insertions(+), 1068 deletions(-) delete mode 100644 cwIoAudioMidi.cpp delete mode 100644 cwIoAudioMidi.h diff --git a/Makefile.am b/Makefile.am index 051ecf2..fa1ead4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,8 +68,8 @@ libcwSRC += src/libcw/cwAudioDeviceAlsa.cpp src/libcw/cwAudioDeviceFile.cpp src/ if cwWEBSOCK -libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h src/libcw/cwIoMinTest.h src/libcw/cwIoSocketChat.h src/libcw/cwIoAudioPanel.h src/libcw/cwIoAudioMidi.h -libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp src/libcw/cwIoMinTest.cpp src/libcw/cwIoSocketChat.cpp src/libcw/cwIoAudioPanel.cpp src/libcw/cwIoAudioMidi.cpp +libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h src/libcw/cwIoMinTest.h src/libcw/cwIoSocketChat.h src/libcw/cwIoAudioPanel.h +libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp src/libcw/cwIoMinTest.cpp src/libcw/cwIoSocketChat.cpp src/libcw/cwIoAudioPanel.cpp libcwHDR += src/libcw/cwIoMidiRecordPlay.h src/libcw/cwIoAudioRecordPlay.h src/libcw/cwIoAudioMidiApp.h src/libcw/cwIoFlow.h src/libcw/cwIoFlowCtl.h libcwSRC += src/libcw/cwIoMidiRecordPlay.cpp src/libcw/cwIoAudioRecordPlay.cpp src/libcw/cwIoAudioMidiApp.cpp src/libcw/cwIoFlow.cpp src/libcw/cwIoFlowCtl.cpp diff --git a/cwIoAudioMidi.cpp b/cwIoAudioMidi.cpp deleted file mode 100644 index 0cb23b0..0000000 --- a/cwIoAudioMidi.cpp +++ /dev/null @@ -1,1048 +0,0 @@ -//| Copyright: (C) 2020-2024 Kevin Larke -//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. -#include "cwCommon.h" -#include "cwLog.h" -#include "cwCommonImpl.h" -#include "cwTest.h" -#include "cwMem.h" -#include "cwObject.h" -#include "cwFileSys.h" -#include "cwFile.h" -#include "cwTime.h" -#include "cwMidiDecls.h" -#include "cwMidi.h" -#include "cwUiDecls.h" -#include "cwIo.h" -#include "cwIoAudioMidi.h" -#include "cwAudioFile.h" - -/* - -TODO: -0. Check for leaks with valgrind -1. Add audio recording -2. Add audio metering panel -3. Turn into a reusable component. - - - */ - - -namespace cw -{ - namespace io - { - namespace audio_midi - { - - // Application Id's for UI elements - enum - { - // Resource Based elements - kPanelDivId = 1000, - kQuitBtnId, - kIoReportBtnId, - kReportBtnId, - kRecordCheckId, - kStartBtnId, - kStopBtnId, - kClearBtnId, - kMsgCntId, - - kAudioRecordCheckId, - kAudioSecsId, - - kSaveBtnId, - kOpenBtnId, - kFnStringId - }; - - enum - { - kAmMidiTimerId - }; - - - // Application Id's for the resource based UI elements. - ui::appIdMap_t mapA[] = - { - { ui::kRootAppId, kPanelDivId, "panelDivId" }, - { kPanelDivId, kQuitBtnId, "quitBtnId" }, - { kPanelDivId, kIoReportBtnId, "ioReportBtnId" }, - { kPanelDivId, kReportBtnId, "reportBtnId" }, - - { kPanelDivId, kRecordCheckId, "recordCheckId" }, - { kPanelDivId, kAudioRecordCheckId, "audioRecordCheckId" }, - { kPanelDivId, kStartBtnId, "startBtnId" }, - { kPanelDivId, kStopBtnId, "stopBtnId" }, - { kPanelDivId, kClearBtnId, "clearBtnId" }, - { kPanelDivId, kMsgCntId, "msgCntId" }, - - { kPanelDivId, kAudioRecordCheckId, "audioRecordCheckId" }, - { kPanelDivId, kAudioSecsId, "audioSecsId" }, - - { kPanelDivId, kSaveBtnId, "saveBtnId" }, - { kPanelDivId, kOpenBtnId, "openBtnId" }, - { kPanelDivId, kFnStringId, "filenameId" }, - - }; - - unsigned mapN = sizeof(mapA)/sizeof(mapA[0]); - - typedef struct am_audio_str - { - time::spec_t timestamp; - unsigned chCnt; - unsigned dspFrameCnt; - struct am_audio_str* link; - sample_t audioBuf[]; // [[ch0:dspFramCnt][ch1:dspFrmCnt]] total: chCnt*dspFrameCnt samples - } am_audio_t; - - typedef struct am_midi_msg_str - { - unsigned devIdx; - unsigned portIdx; - time::spec_t timestamp; - uint8_t ch; - uint8_t status; - uint8_t d0; - uint8_t d1; - - unsigned microsec; - - } am_midi_msg_t; - - typedef struct app_str - { - const char* record_dir; - const char* record_fn; - const char* record_fn_ext; - am_midi_msg_t* midiMsgArray; - unsigned midiMsgArrayN; - unsigned midiMsgArrayInIdx; - unsigned midiMsgArrayOutIdx; - unsigned midi_timer_period_micro_sec; - - const char* midiOutDevLabel; - const char* midiOutPortLabel; - unsigned midiOutDevIdx; - unsigned midiOutPortIdx; - - time::spec_t play_time; - char* filename; - - time::spec_t start_time; - unsigned midiFilterCnt; - - am_audio_t* audioBeg; // first in a chain of am_audio_t audio buffers - am_audio_t* audioEnd; // last in a chain of am_audio_t audio buffers - - am_audio_t* audioFile; // one large audio buffer holding the last loaded audio file - - double audioSrate; - bool audioRecordFl; - unsigned audioSmpIdx; - - bool recordFl; - bool startedFl; - - io::handle_t ioH; - } app_t; - - rc_t _parseCfg(app_t* app, const object_t* cfg ) - { - rc_t rc = kOkRC; - - if((rc = cfg->getv( - "record_dir", app->record_dir, - "record_fn", app->record_fn, - "record_fn_ext", app->record_fn_ext, - "max_midi_msg_count", app->midiMsgArrayN, - "midi_timer_period_micro_sec", app->midi_timer_period_micro_sec, - "midi_out_device", app->midiOutDevLabel, - "midi_out_port", app->midiOutPortLabel)) != kOkRC ) - { - rc = cwLogError(kSyntaxErrorRC,"Audio MIDI app configuration parse failed."); - } - - // allocate the MIDI msg buffer - app->midiMsgArray = mem::allocZ( app->midiMsgArrayN ); - - // verify that the output directory exists - filesys::makeDir(app->record_dir); - - return rc; - } - - void _free( app_t& app ) - { - mem::release(app.midiMsgArray); - mem::release(app.filename); - } - - rc_t _resolve_midi_device_port_index( app_t* app ) - { - rc_t rc = kOkRC; - - if((app->midiOutDevIdx = io::midiDeviceIndex(app->ioH,app->midiOutDevLabel)) == kInvalidIdx ) - { - rc = cwLogError(kInvalidArgRC,"The MIDI output device: '%s' was not found.", cwStringNullGuard(app->midiOutDevLabel) ); - } - - if((app->midiOutPortIdx = io::midiDevicePortIndex(app->ioH,app->midiOutDevIdx,false,app->midiOutPortLabel)) == kInvalidIdx ) - { - rc = cwLogError(kInvalidArgRC,"The MIDI output port: '%s' was not found.", cwStringNullGuard(app->midiOutPortLabel) ); - } - - - return rc; - } - - void _set_midi_msg_next_index( app_t* app, unsigned next_idx ) - { - app->midiMsgArrayInIdx = next_idx; - - io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kMsgCntId), app->midiMsgArrayInIdx ); - - } - - void _set_midi_msg_next_play_index(app_t* app, unsigned next_idx) - { - app->midiMsgArrayOutIdx = next_idx; - } - - - void _on_start_btn( app_t* app ) - { - app->startedFl = true; - - time::get(app->start_time); - - if( app->recordFl ) - { - app->midiFilterCnt = 0; - - _set_midi_msg_next_index(app, 0 ); - } - else - { - _set_midi_msg_next_play_index(app,0); - io::timerStart( app->ioH, io::timerIdToIndex(app->ioH, kAmMidiTimerId) ); - time::get(app->play_time); - } - - if( app->audioRecordFl ) - { - } - else - { - app->audioSmpIdx = 0; - } - - } - - void _on_stop_btn( app_t* app ) - { - app->startedFl = false; - - time::spec_t t1; - time::get(t1); - - if( app->recordFl ) - { - - // set the 'microsec' value for each MIDI msg - for(unsigned i=0; imidiMsgArrayInIdx; ++i) - { - app->midiMsgArray[i].microsec = time::elapsedMicros(app->midiMsgArray[0].timestamp,app->midiMsgArray[i].timestamp); - } - - cwLogInfo("MIDI messages recorded: %i filtered: %i\n",app->midiMsgArrayInIdx, app->midiFilterCnt ); - - } - else - { - io::timerStop( app->ioH, io::timerIdToIndex(app->ioH, kAmMidiTimerId) ); - } - - cwLogInfo("Runtime: %5.2f seconds.", time::elapsedMs(app->start_time,t1)/1000.0 ); - } - - rc_t _midi_read( app_t* app ) - { - rc_t rc = kOkRC; - char* fn = filesys::makeFn( app->record_dir, app->filename, NULL, NULL ); - file::handle_t fH; - unsigned n = 0; - - if((rc = file::open(fH,fn,file::kReadFl)) != kOkRC ) - { - rc = cwLogError(kOpenFailRC,"Unable to locate the file: '%s'.", fn ); - goto errLabel; - } - - if((rc = file::read(fH,n)) != kOkRC ) - { - rc = cwLogError(kReadFailRC,"Header read failed on Audio-MIDI file: '%s'.", fn ); - goto errLabel; - } - - if( n > app->midiMsgArrayN ) - { - cwLogWarning("The count of message in Audio-MIDI file '%s' reduced from %i to %i.", fn, n, app->midiMsgArrayN ); - n = app->midiMsgArrayN; - } - - if((rc = file::read(fH,app->midiMsgArray,n*sizeof(am_midi_msg_t))) != kOkRC ) - { - rc = cwLogError(kReadFailRC,"Data read failed on Audio-MIDI file: '%s'.", fn ); - goto errLabel; - } - - _set_midi_msg_next_index(app, n ); - - cwLogInfo("Read %i from '%s'.",n,fn); - - errLabel: - mem::release(fn); - - return rc; - } - - rc_t _midi_write( app_t* app ) - { - rc_t rc = kOkRC; - char* fn = nullptr; - file::handle_t fH; - - if( app->midiMsgArrayInIdx == 0 ) - { - cwLogWarning("Nothing to write."); - return rc; - } - - // form the filename - if((fn = filesys::makeVersionedFn( app->record_dir, app->record_fn, app->record_fn_ext, NULL )) == nullptr ) - { - rc = cwLogError(kOpFailRC,"Unable to form versioned filename in '%s' with prefix: '%s' and extension: '%s'.", - cwStringNullGuard(app->record_dir), - cwStringNullGuard(app->record_fn), - cwStringNullGuard(app->record_fn_ext)); - } - - // open the file - if((rc = file::open(fH,fn,file::kWriteFl)) != kOkRC ) - { - rc = cwLogError(kOpenFailRC,"Unable to create the file '%s'.",cwStringNullGuard(fn)); - goto errLabel; - } - - // write the file header - if((rc = write(fH,app->midiMsgArrayInIdx)) != kOkRC ) - { - rc = cwLogError(kWriteFailRC,"Header write to '%s' failed.",cwStringNullGuard(fn)); - goto errLabel; - } - - // write the file data - if((rc = write(fH,app->midiMsgArray,sizeof(am_midi_msg_t)*app->midiMsgArrayInIdx)) != kOkRC ) - { - rc = cwLogError(kWriteFailRC,"Data write to '%s' failed.",cwStringNullGuard(fn)); - goto errLabel; - } - - // update UI msg count - io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kMsgCntId), app->midiMsgArrayInIdx ); - - file::close(fH); - - cwLogInfo("Saved %i events to '%s'.", app->midiMsgArrayInIdx, fn ); - - errLabel: - mem::release(fn); - return rc; - } - - void _print_midi_msg( const am_midi_msg_t* mm ) - { - printf("%i %i : %10i : %2i 0x%02x 0x%02x 0x%02x\n", mm->devIdx, mm->portIdx, mm->microsec, mm->ch, mm->status, mm->d0, mm->d1 ); - } - - void _report_midi( app_t* app ) - { - for(unsigned i=0; imidiMsgArrayInIdx; ++i) - { - am_midi_msg_t* mm = app->midiMsgArray + i; - _print_midi_msg(mm); - } - } - - am_audio_t* _am_audio_alloc( unsigned dspFrameCnt, unsigned chCnt ) - { - unsigned sample_byte_cnt = chCnt * dspFrameCnt * sizeof(sample_t); - void* vp = mem::alloc( sizeof(am_audio_t) + sample_byte_cnt ); - am_audio_t* a = (am_audio_t*)vp; - - a->chCnt = chCnt; - a->dspFrameCnt = dspFrameCnt; - - return a; - } - - am_audio_t* _am_audio_from_sample_index( app_t* app, unsigned sample_idx, unsigned& sample_offs_ref ) - { - unsigned n = 0; - am_audio_t* a = app->audioBeg; - - if( app->audioBeg == nullptr ) - return nullptr; - - for(; a!=nullptr; a=a->link) - { - if( n < sample_idx ) - { - sample_offs_ref = sample_idx - n; - return a; - } - - n += a->dspFrameCnt; - } - - return nullptr; - } - - void _audio_file_buffer( app_t* app, io::audio_msg_t& adst ) - { - unsigned sample_offs = 0; - am_audio_t* a = _am_audio_from_sample_index(app, app->audioSmpIdx, sample_offs ); - unsigned copy_n_0 = std::min(a->dspFrameCnt - sample_offs, adst.dspFrameCnt ); - unsigned chN = std::min(a->chCnt, adst.oBufChCnt ); - - for(unsigned i=0; iaudioBuf + sample_offs, copy_n_0 * sizeof(sample_t)); - - app->audioSmpIdx += copy_n_0; - - if( copy_n_0 < adst.dspFrameCnt ) - { - a = _am_audio_from_sample_index(app, app->audioSmpIdx, sample_offs ); - - unsigned copy_n_1 = std::min(a->dspFrameCnt - sample_offs, adst.dspFrameCnt - copy_n_0 ); - - for(unsigned i=0; iaudioBuf + sample_offs, copy_n_1 * sizeof(sample_t)); - } - } - - void _audio_record( app_t* app, const io::audio_msg_t& asrc ) - { - am_audio_t* a = _am_audio_alloc(asrc.dspFrameCnt,asrc.iBufChCnt); - - for(unsigned chIdx=0; chIdxaudioBuf + chIdx*asrc.dspFrameCnt, asrc.iBufArray[chIdx], asrc.dspFrameCnt * sizeof(sample_t)); - - app->audioEnd->link = a; // link the new audio record to the end of the audio sample buffer chain - app->audioEnd = a; // make the new audio record the last ele. of the chain - - // if this is the first ele of the chain - if( app->audioBeg == nullptr ) - { - app->audioBeg = a; - app->audioSrate = asrc.srate; - } - } - - void _audio_play( app_t* app, io::audio_msg_t& adst ) - { - if( app->audioFile == nullptr ) - return; - - if( app->audioSmpIdx >= app->audioFile->dspFrameCnt ) - return; - - unsigned chCnt = std::min( adst.oBufChCnt, app->audioFile->chCnt ); - unsigned copy_n = std::min( adst.dspFrameCnt, app->audioFile->dspFrameCnt - app->audioSmpIdx); - unsigned extra_n = adst.dspFrameCnt - copy_n; - unsigned i; - - for(i=0; iaudioFile->audioBuf + i*app->audioFile->dspFrameCnt, copy_n * sizeof(sample_t)); - memset(adst.oBufArray + i*adst.dspFrameCnt + copy_n, 0, extra_n * sizeof(sample_t)); - } - } - - void _audio_through( app_t* app, io::audio_msg_t& m ) - { - unsigned chN = std::min(m.iBufChCnt,m.oBufChCnt); - unsigned byteCnt = m.dspFrameCnt * sizeof(sample_t); - - // Copy the input to the output - for(unsigned i=0; iaudioBeg == nullptr ) - return rc; - - // form the filename - if((fn = filesys::makeVersionedFn( app->record_dir, app->record_fn, "wav", NULL )) == nullptr ) - { - rc = cwLogError(kOpFailRC,"Unable to form versioned filename in '%s' with prefix: '%s' and extension: '%s'.", - cwStringNullGuard(app->record_dir), - cwStringNullGuard(app->record_fn), - cwStringNullGuard("wav")); - } - - // create an audio file - if((rc = audiofile::create( afH, fn, app->audioSrate, 16, app->audioBeg->chCnt )) != kOkRC ) - { - cwLogError(rc,"Audio file create failed."); - goto errLabel; - } - - // write each buffer - for(am_audio_t* a=app->audioBeg; a!=nullptr; a=a->link) - { - float* chBufArray[ a->chCnt ]; - for(unsigned i=0; ichCnt; ++i) - chBufArray[i] = a->audioBuf + (i*a->dspFrameCnt); - - if((rc = writeFloat( afH, a->dspFrameCnt, a->chCnt, (const float**)chBufArray )) != kOkRC ) - { - cwLogError(rc,"An error occurred while writing and audio buffer."); - goto errLabel; - } - } - - errLabel: - - // close the audio file - if((rc == audiofile::close(afH)) != kOkRC ) - { - cwLogError(rc,"Audio file close failed."); - goto errLabel; - } - - mem::free(fn); - return rc; - } - - rc_t _audio_write_buffer_times( app_t* app ) - { - rc_t rc = kOkRC; - char* fn = nullptr; - am_audio_t* a0 = app->audioBeg; - file::handle_t fH; - - // if there is no audio to write - if( app->audioBeg == nullptr ) - return rc; - - // form the filename - if((fn = filesys::makeVersionedFn( app->record_dir, app->record_fn, "txt", NULL )) == nullptr ) - { - rc = cwLogError(kOpFailRC,"Unable to form versioned filename in '%s' with prefix: '%s' and extension: '%s'.", - cwStringNullGuard(app->record_dir), - cwStringNullGuard(app->record_fn), - cwStringNullGuard("wav")); - } - - // create the file - if((rc = file::open(fH,fn,file::kWriteFl)) != kOkRC ) - { - cwLogError(rc,"Create audio buffer time file failed."); - goto errLabel; - } - - file::print(fH,"{ [\n"); - - // write each buffer - for(am_audio_t* a=app->audioBeg; a!=nullptr; a=a->link) - { - unsigned elapsed_us = time::elapsedMicros( a0->timestamp, a->timestamp ); - file::printf(fH,"{ elapsed_us:%i chCnt:%i frameCnt:%i }\n", elapsed_us, a->chCnt, a->dspFrameCnt ); - a0 = a; - } - - file::print(fH,"] }\n"); - - // close the file - if((rc = file::close(fH)) != kOkRC ) - { - cwLogError(rc,"Close the audio buffer time file."); - goto errLabel; - } - - errLabel: - mem::release(fn); - - return rc; - } - - rc_t _audio_read( app_t* app ) - { - rc_t rc = kOkRC; - char* fn = nullptr; - filesys::pathPart_t* pp = nullptr; - audiofile::handle_t afH; - audiofile::info_t af_info; - - - if((fn = filesys::makeFn( app->record_dir, app->filename, NULL, NULL )) != nullptr ) - { - rc = cwLogError(kOpFailRC,"Unable to form the audio file:%s",fn); - goto errLabel; - } - - if((pp = filesys::pathParts(fn)) != nullptr ) - { - rc = cwLogError(kOpFailRC,"Unable to parse audio file name:%s",fn); - goto errLabel; - } - - mem::release(fn); - - if((fn = filesys::makeFn( app->record_dir, pp->fnStr, "wav", NULL )) != nullptr ) - { - rc = cwLogError(kOpFailRC,"Unable form audio file wav name:%s",fn); - goto errLabel; - } - - if((rc = audiofile::open(afH, fn, &af_info)) != kOkRC ) - { - rc = cwLogError(kOpFailRC,"Audio file '%s' open failed.",fn); - goto errLabel; - } - - if((app->audioFile = _am_audio_alloc(af_info.frameCnt,af_info.chCnt)) != nullptr ) - { - rc = cwLogError(kOpFailRC,"Allocate audio buffer (%i samples) failed.",af_info.frameCnt*af_info.chCnt); - goto errLabel; - } - else - { - unsigned audioFrameCnt = 0; - float* chArray[ af_info.chCnt ]; - - for(unsigned i=0; iaudioFile->audioBuf + (i*af_info.frameCnt); - - if((rc = audiofile::readFloat(afH, af_info.frameCnt, 0, af_info.chCnt, chArray, &audioFrameCnt)) != kOkRC ) - { - rc = cwLogError(kOpFailRC,"Audio file read failed."); - goto errLabel; - } - - double audioSecs = (double)af_info.frameCnt / af_info.srate; - io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kAudioSecsId), audioSecs ); - - } - - errLabel: - if((rc = audiofile::close(afH)) != kOkRC ) - { - rc = cwLogError(kOpFailRC,"Audio file close failed."); - goto errLabel; - } - - mem::release(pp); - mem::release(fn); - return rc; - } - - rc_t _onUiInit(app_t* app, const ui_msg_t& m ) - { - rc_t rc = kOkRC; - - return rc; - } - - rc_t _onUiValue(app_t* app, const ui_msg_t& m ) - { - rc_t rc = kOkRC; - - switch( m.appId ) - { - case kQuitBtnId: - io::stop( app->ioH ); - break; - - case kIoReportBtnId: - io::report( app->ioH ); - break; - - case kReportBtnId: - _report_midi(app); - break; - - case kSaveBtnId: - _midi_write(app); - _audio_write_as_wav(app); - _audio_write_buffer_times(app); - break; - - case kOpenBtnId: - printf("open btn\n"); - _midi_read(app); - _audio_read(app); - break; - - case kRecordCheckId: - cwLogInfo("Record:%i",m.value->u.b); - app->recordFl = m.value->u.b; - break; - - case kAudioRecordCheckId: - cwLogInfo("Audio Record:%i",m.value->u.b); - app->audioRecordFl = m.value->u.b; - break; - - case kStartBtnId: - cwLogInfo("Start"); - _on_start_btn(app); - break; - - case kStopBtnId: - cwLogInfo("Stop"); - _on_stop_btn(app); - break; - - case kClearBtnId: - cwLogInfo("Clear"); - _set_midi_msg_next_index(app, 0 ); - break; - - case kFnStringId: - mem::release(app->filename); - app->filename = mem::duplStr(m.value->u.s); - printf("filename:%s\n",app->filename); - break; - } - - return rc; - } - - rc_t _onUiEcho(app_t* app, const ui_msg_t& m ) - { - rc_t rc = kOkRC; - return rc; - } - - rc_t uiCb( app_t* app, const ui_msg_t& m ) - { - rc_t rc = kOkRC; - - switch( m.opId ) - { - case ui::kConnectOpId: - cwLogInfo("UI Connected: wsSessId:%i.",m.wsSessId); - break; - - case ui::kDisconnectOpId: - cwLogInfo("UI Disconnected: wsSessId:%i.",m.wsSessId); - break; - - case ui::kInitOpId: - _onUiInit(app,m); - break; - - case ui::kValueOpId: - _onUiValue( app, m ); - break; - - case ui::kEchoOpId: - _onUiEcho( app, m ); - break; - - case ui::kIdleOpId: - break; - - case ui::kInvalidOpId: - // fall through - default: - assert(0); - break; - - } - - return rc; - } - - - rc_t timerCb(app_t* app, timer_msg_t& m) - { - rc_t rc = kOkRC; - - // if the MIDI player is started and in 'play' mode and msg remain to be played - if( app->startedFl && (app->recordFl==false) && (app->midiMsgArrayOutIdx < app->midiMsgArrayInIdx)) - { - time::spec_t t; - time::get(t); - - unsigned cur_time_us = time::elapsedMicros(app->play_time,t); - - while( app->midiMsgArray[ app->midiMsgArrayOutIdx ].microsec <= cur_time_us ) - { - - am_midi_msg_t* mm = app->midiMsgArray + app->midiMsgArrayOutIdx; - - //_print_midi_msg(mm); - - io::midiDeviceSend( app->ioH, app->midiOutDevIdx, app->midiOutPortIdx, mm->status + mm->ch, mm->d0, mm->d1 ); - - _set_midi_msg_next_play_index(app, app->midiMsgArrayOutIdx+1 ); - - // if all MIDI messages have been played - if( app->midiMsgArrayOutIdx >= app->midiMsgArrayInIdx ) - { - _on_stop_btn(app); - break; - } - } - } - - return rc; - } - - bool _midi_filter( const midi::msg_t* mm ) - { - //bool drop_fl = (mm->status & 0xf0) == midi::kCtlMdId && (64 <= mm->d0) && (mm->d0 <= 67) && (mm->d1 < 25); - //return drop_fl; - return false; - } - - rc_t midiCb( app_t* app, const midi_msg_t& m ) - { - rc_t rc = kOkRC; - const midi::packet_t* pkt = m.pkt; - - // for each midi msg - for(unsigned j=0; jmsgCnt; ++j) - { - - // if this is a sys-ex msg - if( pkt->msgArray == NULL ) - { - // this is a sys ex msg use: pkt->sysExMsg[j] - } - else // this is a triple - { - if( app->recordFl && app->startedFl ) - { - - // verify that space exists in the record buffer - if( app->midiMsgArrayInIdx >= app->midiMsgArrayN ) - { - _on_stop_btn(app); - rc = cwLogError(kBufTooSmallRC,"MIDI message record buffer is full. % messages.",app->midiMsgArrayN); - goto errLabel; - } - else - { - // copy the msg into the record buffer - am_midi_msg_t* am = app->midiMsgArray + app->midiMsgArrayInIdx; - midi::msg_t* mm = pkt->msgArray + j; - - if( _midi_filter(mm) ) - { - app->midiFilterCnt++; - } - else - { - am->devIdx = pkt->devIdx; - am->portIdx = pkt->portIdx; - am->timestamp = mm->timeStamp; - am->ch = mm->ch; - am->status = mm->status; - am->d0 = mm->d0; - am->d1 = mm->d1; - - app->midiMsgArrayInIdx += 1; - - // send msg count - io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kMsgCntId), app->midiMsgArrayInIdx ); - } - } - } - } - - /* - if( pkt->msgArray == NULL ) - printf("io midi cb: 0x%x ",pkt->sysExMsg[j]); - else - { - if( !_midi_filter(pkt->msgArray + j) ) - printf("io midi cb: %ld %ld 0x%x %i %i\n", pkt->msgArray[j].timeStamp.tv_sec, pkt->msgArray[j].timeStamp.tv_nsec, pkt->msgArray[j].status, pkt->msgArray[j].d0, pkt->msgArray[j].d1); - } - */ - } - - errLabel: - return rc; - } - - rc_t audioCb( app_t* app, audio_msg_t& m ) - { - rc_t rc = kOkRC; - - if( app->startedFl ) - { - if( app->audioRecordFl ) - { - if( m.iBufChCnt > 0 ) - _audio_record(app,m); - - if( m.oBufChCnt > 0 ) - _audio_play(app,m); - } - - - } - - - return rc; - } - - - // The main application callback - rc_t ioCb( void* arg, const msg_t* m ) - { - rc_t rc = kOkRC; - app_t* app = reinterpret_cast(arg); - - switch( m->tid ) - { - case kTimerTId: - if( m->u.timer != nullptr ) - rc = timerCb(app,*m->u.timer); - break; - - case kSerialTId: - break; - - case kMidiTId: - if( m->u.midi != nullptr ) - rc = midiCb(app,*m->u.midi); - break; - - case kAudioTId: - if( m->u.audio != nullptr ) - rc = audioCb(app,*m->u.audio); - break; - - case kAudioMeterTId: - break; - - case kSockTId: - break; - - case kWebSockTId: - break; - - case kUiTId: - rc = uiCb(app,m->u.ui); - break; - - default: - assert(0); - - } - - return rc; - } - } - } -} - - -cw::rc_t cw::io::audio_midi::main( const object_t* cfg ) -{ - - rc_t rc; - app_t app = {}; - bool asyncFl = true; - - if((rc = _parseCfg(&app,cfg)) != kOkRC ) - goto errLabel; - - // create the io framework instance - if((rc = create(app.ioH,cfg,ioCb,&app,mapA,mapN)) != kOkRC ) - return rc; - - // create the MIDI playback timer - if((rc = timerCreate( app.ioH, "am_timer", kAmMidiTimerId, app.midi_timer_period_micro_sec, asyncFl)) != kOkRC ) - { - cwLogError(rc,"Audio-MIDI timer create failed."); - goto errLabel; - } - - //report(app.ioH); - - // start the io framework instance - if((rc = start(app.ioH)) != kOkRC ) - { - rc = cwLogError(rc,"Audio-MIDI app start failed."); - goto errLabel; - - } - else - { - - // resolve the MIDI out dev/port indexes from the MIDI out dev/port labels - rc_t rc0 = _resolve_midi_device_port_index(&app); - - - // resolve the audio group index from the lavel - rc_t rc1 = kOkRC; - unsigned devIdx; - - if( (devIdx = audioDeviceLabelToIndex(app.ioH, "main")) == kInvalidIdx ) - rc1 = cwLogError(kOpFailRC, "Unable to locate the requested audio device."); - - if(rcSelect(rc0,rc1) != kOkRC ) - goto errLabel; - } - - // execute the io framework - while( !isShuttingDown(app.ioH)) - { - const unsigned wsTimeOutMs = 50; - time::spec_t t0 = time::current_time(); - - exec(app.ioH,wsTimeOutMs); - - time::spec_t t1 = time::current_time(); - unsigned dMs = time::elapsedMs(t0,t1); - - if( dMs < wsTimeOutMs ) - sleepMs(wsTimeOutMs-dMs); - } - - errLabel: - _free(app); - destroy(app.ioH); - printf("Audio-MIDI Done.\n"); - return rc; - -} diff --git a/cwIoAudioMidi.h b/cwIoAudioMidi.h deleted file mode 100644 index af8770d..0000000 --- a/cwIoAudioMidi.h +++ /dev/null @@ -1,18 +0,0 @@ -//| Copyright: (C) 2020-2024 Kevin Larke -//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. -#ifndef cwIoAudioMidi_H -#define cwIoAudioMidi_H - -namespace cw -{ - namespace io - { - namespace audio_midi - { - rc_t main( const object_t* cfg ); - } - } -} - - -#endif