Merge branch 'master' of gitea.larke.org:kevin/libcw
This commit is contained in:
commit
83884b5424
13
Makefile.am
13
Makefile.am
@ -40,6 +40,8 @@ libcwSRC += src/libcw/cwUi.cpp src/libcw/cwUiTest.cpp
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
libcwHDR += src/libcw/cwKeyboard.h
|
||||||
|
libcwSRC += src/libcw/cwKeyboard.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
||||||
libcwSRC += src/libcw/cwSerialPort.cpp src/libcw/cwSerialPortSrv.cpp
|
libcwSRC += src/libcw/cwSerialPort.cpp src/libcw/cwSerialPortSrv.cpp
|
||||||
@ -56,14 +58,17 @@ libcwHDR += src/libcw/cwMidiPort.h src/libcw/cwAudioD
|
|||||||
libcwSRC += src/libcw/cwMidiPort.cpp src/libcw/cwMidiAlsa.cpp src/libcw/cwAudioDeviceAlsa.cpp src/libcw/cwAudioDeviceTest.cpp
|
libcwSRC += src/libcw/cwMidiPort.cpp src/libcw/cwMidiAlsa.cpp src/libcw/cwAudioDeviceAlsa.cpp src/libcw/cwAudioDeviceTest.cpp
|
||||||
|
|
||||||
if cwWEBSOCK
|
if cwWEBSOCK
|
||||||
libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h src/libcw/cwIoSocketChat.h src/libcw/cwIoAudioPanel.h src/libcw/cwIoAudioMidi.h
|
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/cwIoSocketChat.cpp src/libcw/cwIoAudioPanel.cpp src/libcw/cwIoAudioMidi.cpp
|
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/cwIoMidiRecordPlay.h src/libcw/cwIoAudioRecordPlay.h src/libcw/cwIoAudioMidiApp.h src/libcw/cwIoFlow.h
|
libcwHDR += src/libcw/cwIoMidiRecordPlay.h src/libcw/cwIoAudioRecordPlay.h src/libcw/cwIoAudioMidiApp.h src/libcw/cwIoFlow.h
|
||||||
libcwSRC += src/libcw/cwIoMidiRecordPlay.cpp src/libcw/cwIoAudioRecordPlay.cpp src/libcw/cwIoAudioMidiApp.cpp src/libcw/cwIoFlow.cpp
|
libcwSRC += src/libcw/cwIoMidiRecordPlay.cpp src/libcw/cwIoAudioRecordPlay.cpp src/libcw/cwIoAudioMidiApp.cpp src/libcw/cwIoFlow.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwIoPresetSelApp.h src/libcw/cwPianoScore.h src/libcw/cwPresetSel.h
|
libcwHDR += src/libcw/cwIoPresetSelApp.h src/libcw/cwPianoScore.h src/libcw/cwPresetSel.h
|
||||||
libcwSRC += src/libcw/cwIoPresetSelApp.cpp src/libcw/cwPianoScore.cpp src/libcw/cwPresetSel.cpp
|
libcwSRC += src/libcw/cwIoPresetSelApp.cpp src/libcw/cwPianoScore.cpp src/libcw/cwPresetSel.cpp
|
||||||
|
|
||||||
|
# libcwHDR += src/libcw/cwCmInterface.h src/libcw/cwScoreFollower.h
|
||||||
|
# libcwSRC += src/libcw/cwCmInterface.cpp src/libcw/cwScoreFollower.cpp
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
55
README.md
55
README.md
@ -2,6 +2,22 @@
|
|||||||
|
|
||||||
# To Do
|
# To Do
|
||||||
|
|
||||||
|
- Remove applications from the libcw folder and put them in their
|
||||||
|
own folders.
|
||||||
|
|
||||||
|
- The UI needs to be better documented. Start by giving clear names
|
||||||
|
to the various parts: Browser, UI Manager, UI Server, Application.
|
||||||
|
Maybe describe in Model,View,Controller terms?
|
||||||
|
|
||||||
|
- Document the meaning and way that id's and names/labels are used,
|
||||||
|
and intended to be used, and found by UI. As it is they are confusing.
|
||||||
|
|
||||||
|
- The UI app id map should be validated after the UI is created.
|
||||||
|
In otherwords the parent/child pairs shoud actually exists.
|
||||||
|
|
||||||
|
- Arrange the project layout so that all the UI based apps use the same ui.js.
|
||||||
|
Currently changes and improvements to one version of ui.js cannot be automatically
|
||||||
|
shared.
|
||||||
|
|
||||||
- The ui manageer should buffer the current valid value of a given control
|
- The ui manageer should buffer the current valid value of a given control
|
||||||
so that the value can be accessed synchronously. This would prevent the application
|
so that the value can be accessed synchronously. This would prevent the application
|
||||||
@ -11,14 +27,19 @@ read by the app (e.g. getUiValue( appId, valueRef)) just prior to being used.
|
|||||||
As it is the UI values that are on the interface cannot be accessed synchronously
|
As it is the UI values that are on the interface cannot be accessed synchronously
|
||||||
instead the app is forced to notice all 'value' changes and store the last legal value.
|
instead the app is forced to notice all 'value' changes and store the last legal value.
|
||||||
|
|
||||||
|
- Add an ui::appIdToUuId() that returns the first matching appId, and then
|
||||||
|
optionally looks for duplicates as an error checking scheme.
|
||||||
|
|
||||||
|
- The ui eleA[] data structure should be changed to a tree
|
||||||
|
because the current expandable array allows empty slots which need to be checked
|
||||||
|
for whenever the list is iterated. It is also very inefficient to delete from the
|
||||||
|
eleA[] because an exhaustive search is required to find all the children of the
|
||||||
|
element to be deleted.
|
||||||
|
|
||||||
- Should a warning be issued by audioBuf functions which return a set of values:
|
- Should a warning be issued by audioBuf functions which return a set of values:
|
||||||
muteFlags(),toneFlags(), gain( ... gainA) but where the size of the dest array
|
muteFlags(),toneFlags(), gain( ... gainA) but where the size of the dest array
|
||||||
does not match the actual number of channesl?
|
does not match the actual number of channesl?
|
||||||
|
|
||||||
- Document the meaning and way that id's and names/labels are used,
|
|
||||||
and intended to be used, and found by UI. As it is they are confusing.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- Any socket function which takes a IP/port address should have a version which also takes a sockaddr_in*.
|
- Any socket function which takes a IP/port address should have a version which also takes a sockaddr_in*.
|
||||||
@ -47,17 +68,7 @@ This is easy to reproduce by simply decreasing the size of the buffers in the pr
|
|||||||
- numeric_convert() d_min is NOT zero, it's smallest positive number, this fails when src == 0.
|
- numeric_convert() d_min is NOT zero, it's smallest positive number, this fails when src == 0.
|
||||||
min value is now set to zero.
|
min value is now set to zero.
|
||||||
|
|
||||||
- The UI app id map should be validated after the UI is created.
|
|
||||||
In otherwords the parent/child pairs shoud actually exists.
|
|
||||||
|
|
||||||
- Add an ui::appIdToUuId() that returns the first matching appId, and then
|
|
||||||
optionally looks for duplicates as an error checking scheme.
|
|
||||||
|
|
||||||
- The ui eleA[] data structure should be changed to a tree
|
|
||||||
because the current expandable array allows empty slots which need to be checked
|
|
||||||
for whenever the list is iterated. It is also very inefficient to delete from the
|
|
||||||
eleA[] because an exhaustive search is required to find all the children of the
|
|
||||||
element to be deleted.
|
|
||||||
|
|
||||||
- thread needs setters and getters for internal variables
|
- thread needs setters and getters for internal variables
|
||||||
|
|
||||||
@ -65,7 +76,7 @@ element to be deleted.
|
|||||||
|
|
||||||
- cwAudioBuf.cpp - the ch->fn in update() does not have the correct memory fence.
|
- cwAudioBuf.cpp - the ch->fn in update() does not have the correct memory fence.
|
||||||
|
|
||||||
- change file names to match object names
|
- Change file names to match object names
|
||||||
|
|
||||||
- Replace 24 bit read/write in cwAudioFile.cpp
|
- Replace 24 bit read/write in cwAudioFile.cpp
|
||||||
|
|
||||||
@ -90,9 +101,9 @@ The 'jsUuId' is generated by the JS client when the UI element is created.
|
|||||||
The 'uuId' is generated by the UI server when the JS client registers the control.
|
The 'uuId' is generated by the UI server when the JS client registers the control.
|
||||||
The 'appId' is assigned by the UI server when the JS client regsiters the control.
|
The 'appId' is assigned by the UI server when the JS client regsiters the control.
|
||||||
|
|
||||||
Client sends 'init' message.
|
Client sends 'init' message.
|
||||||
Server sends 'create' messages.
|
Server sends 'create' messages.
|
||||||
Client sends 'register' messages.
|
Client sends 'register' messages.
|
||||||
Server send' 'id_assign' messages.
|
Server send' 'id_assign' messages.
|
||||||
|
|
||||||
# sockaddr_in reference
|
# sockaddr_in reference
|
||||||
@ -115,10 +126,14 @@ struct in_addr {
|
|||||||
|
|
||||||
# Development Setup
|
# Development Setup
|
||||||
|
|
||||||
|
0)
|
||||||
|
```
|
||||||
|
sudo dnf install g++ fftw-devel alsa-lib-devel libubsan
|
||||||
|
```
|
||||||
1) Install libwebsockets.
|
1) Install libwebsockets.
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo dnf install g++ openssl-devel cmake
|
sudo dnf install openssl-devel cmake
|
||||||
cd sdk
|
cd sdk
|
||||||
git clone https://libwebsockets.org/repo/libwebsockets
|
git clone https://libwebsockets.org/repo/libwebsockets
|
||||||
cd libwebsockets
|
cd libwebsockets
|
||||||
@ -145,7 +160,6 @@ struct in_addr {
|
|||||||
|
|
||||||
# Flow Notes:
|
# Flow Notes:
|
||||||
|
|
||||||
- Add a version of var_register() that both registers and returns the value of the variable.
|
|
||||||
|
|
||||||
- When a variable has a variant with a numberic channel should the 'all' channel variant be removed?
|
- When a variable has a variant with a numberic channel should the 'all' channel variant be removed?
|
||||||
|
|
||||||
@ -167,6 +181,7 @@ specific types, to pass through. For example a 'selector' (n inputs, 1 output) o
|
|||||||
|
|
||||||
- Create a master cross-fader.
|
- Create a master cross-fader.
|
||||||
|
|
||||||
|
DONE: Add a version of var_register() that both registers and returns the value of the variable.
|
||||||
|
|
||||||
Flow Instance Creation:
|
Flow Instance Creation:
|
||||||
-----------------------
|
-----------------------
|
||||||
|
110
cwCmInterface.cpp
Normal file
110
cwCmInterface.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwCmInterface.h"
|
||||||
|
|
||||||
|
#include "cmGlobal.h"
|
||||||
|
#include "cmFloatTypes.h"
|
||||||
|
#include "cmRpt.h"
|
||||||
|
#include "cmErr.h"
|
||||||
|
#include "cmCtx.h"
|
||||||
|
#include "cmMem.h"
|
||||||
|
#include "cmMallocDebug.h"
|
||||||
|
#include "cmLinkedHeap.h"
|
||||||
|
#include "cmTime.h"
|
||||||
|
#include "cmMidi.h"
|
||||||
|
#include "cmSymTbl.h"
|
||||||
|
#include "cmScore.h"
|
||||||
|
#include "cmText.h"
|
||||||
|
#include "cmFileSys.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void _cm_print_info( void* arg, const char* text )
|
||||||
|
{
|
||||||
|
cwLogInfo(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cm_print_error( void* arg, const char* text )
|
||||||
|
{
|
||||||
|
cwLogError(cw::kOpFailRC,text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace cm
|
||||||
|
{
|
||||||
|
typedef struct cm_str
|
||||||
|
{
|
||||||
|
::cmCtx_t ctx;
|
||||||
|
} cm_t;
|
||||||
|
|
||||||
|
cm_t* _handleToPtr( handle_t h )
|
||||||
|
{ return handleToPtr<handle_t,cm_t>(h); }
|
||||||
|
|
||||||
|
rc_t _destroy( cm_t* p )
|
||||||
|
{
|
||||||
|
if( p != nullptr )
|
||||||
|
{
|
||||||
|
cmTsFinalize();
|
||||||
|
cmFsFinalize();
|
||||||
|
cmMdReport( kIgnoreNormalMmFl );
|
||||||
|
cmMdFinalize();
|
||||||
|
|
||||||
|
mem::release(p);
|
||||||
|
}
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::cm::create( handle_t& hRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
cm_t* p = nullptr;
|
||||||
|
bool memDebugFl = 0; //cmDEBUG_FL;
|
||||||
|
unsigned memGuardByteCnt = memDebugFl ? 8 : 0;
|
||||||
|
unsigned memAlignByteCnt = 16;
|
||||||
|
unsigned memFlags = memDebugFl ? kTrackMmFl | kDeferFreeMmFl | kFillUninitMmFl : 0;
|
||||||
|
const cmChar_t* appTitle = "cwtest";
|
||||||
|
|
||||||
|
if((rc = destroy(hRef)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
p = mem::allocZ<cm_t>();
|
||||||
|
|
||||||
|
cmCtxSetup(&p->ctx,appTitle,_cm_print_info,_cm_print_error,NULL,memGuardByteCnt,memAlignByteCnt,memFlags);
|
||||||
|
|
||||||
|
cmMdInitialize( memGuardByteCnt, memAlignByteCnt, memFlags, &p->ctx.rpt );
|
||||||
|
|
||||||
|
cmFsInitialize( &p->ctx, appTitle);
|
||||||
|
|
||||||
|
cmTsInitialize( &p->ctx );
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::cm::destroy( handle_t& hRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
cm_t* p = nullptr;
|
||||||
|
if( !hRef.isValid() )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
p = _handleToPtr(hRef);
|
||||||
|
|
||||||
|
if((rc = _destroy(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
hRef.clear();
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
::cmCtx_t* cw::cm::context( handle_t h )
|
||||||
|
{
|
||||||
|
cm_t* p = _handleToPtr(h);
|
||||||
|
return &p->ctx;
|
||||||
|
}
|
||||||
|
|
19
cwCmInterface.h
Normal file
19
cwCmInterface.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef cwCmInterface_h
|
||||||
|
#define cwCmInterface_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace cm {
|
||||||
|
|
||||||
|
extern "C" { struct cmCtx_str; }
|
||||||
|
|
||||||
|
typedef handle< struct cm_str > handle_t;
|
||||||
|
|
||||||
|
rc_t create( handle_t& hRef );
|
||||||
|
rc_t destroy( handle_t& hRef );
|
||||||
|
::cmCtx_t* context( handle_t h );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -46,7 +46,8 @@ namespace cw
|
|||||||
kTestFailRC, // 27
|
kTestFailRC, // 27
|
||||||
kInvalidStateRC, // 28
|
kInvalidStateRC, // 28
|
||||||
kTypeMismatchRC, // 29
|
kTypeMismatchRC, // 29
|
||||||
kBaseAppRC // 30
|
kNotImplementedRC, // 30
|
||||||
|
kBaseAppRC // 31
|
||||||
} cwRC_t;
|
} cwRC_t;
|
||||||
|
|
||||||
typedef unsigned rc_t;
|
typedef unsigned rc_t;
|
||||||
|
10
cwFlow.cpp
10
cwFlow.cpp
@ -137,6 +137,7 @@ namespace cw
|
|||||||
const char* type_str = nullptr;
|
const char* type_str = nullptr;
|
||||||
unsigned type_flag = 0;
|
unsigned type_flag = 0;
|
||||||
bool srcVarFl = false;
|
bool srcVarFl = false;
|
||||||
|
bool srcOptFl = false;
|
||||||
var_desc_t* vd = mem::allocZ<var_desc_t>();
|
var_desc_t* vd = mem::allocZ<var_desc_t>();
|
||||||
|
|
||||||
vd->label = var_obj->pair_label();
|
vd->label = var_obj->pair_label();
|
||||||
@ -158,7 +159,9 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the variable description
|
// get the variable description
|
||||||
if((rc = vd->cfg->getv_opt("srcFl", srcVarFl,"value",vd->val_cfg)) != kOkRC )
|
if((rc = vd->cfg->getv_opt("srcFl", srcVarFl,
|
||||||
|
"srcOptFl", srcOptFl,
|
||||||
|
"value",vd->val_cfg)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label );
|
rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label );
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -168,9 +171,10 @@ namespace cw
|
|||||||
vd->type |= type_flag;
|
vd->type |= type_flag;
|
||||||
|
|
||||||
if( srcVarFl )
|
if( srcVarFl )
|
||||||
{
|
|
||||||
vd->flags |= kSrcVarFl;
|
vd->flags |= kSrcVarFl;
|
||||||
}
|
|
||||||
|
if( srcOptFl )
|
||||||
|
vd->flags |= kSrcOptVarFl;
|
||||||
|
|
||||||
vd->link = cd->varDescL;
|
vd->link = cd->varDescL;
|
||||||
cd->varDescL = vd;
|
cd->varDescL = vd;
|
||||||
|
@ -564,7 +564,7 @@ namespace cw
|
|||||||
// print a minutes counter
|
// print a minutes counter
|
||||||
inst->durSmpN += src_abuf->frameN;
|
inst->durSmpN += src_abuf->frameN;
|
||||||
if( inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 )
|
if( inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 )
|
||||||
printf("%5.1f min\n", inst->durSmpN/(src_abuf->srate*60));
|
printf("audio file out: %5.1f min\n", inst->durSmpN/(src_abuf->srate*60));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -982,35 +982,64 @@ namespace cw
|
|||||||
namespace audio_merge
|
namespace audio_merge
|
||||||
{
|
{
|
||||||
enum {
|
enum {
|
||||||
kIn0PId,
|
|
||||||
kIn1PId,
|
|
||||||
kGainPId,
|
kGainPId,
|
||||||
kOutPId,
|
kOutPId,
|
||||||
|
kInBasePId,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
unsigned srcN;
|
||||||
} inst_t;
|
} inst_t;
|
||||||
|
|
||||||
|
|
||||||
rc_t create( instance_t* ctx )
|
rc_t create( instance_t* ctx )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const abuf_t* abuf0 = nullptr; //
|
|
||||||
const abuf_t* abuf1 = nullptr;
|
|
||||||
unsigned outChN = 0;
|
unsigned outChN = 0;
|
||||||
|
unsigned frameN = 0;
|
||||||
// get the source audio buffer
|
srate_t srate = 0;
|
||||||
if((rc = var_register_and_get(ctx, kAnyChIdx,
|
|
||||||
kIn0PId,"in0",abuf0,
|
inst_t* inst = mem::allocZ<inst_t>();
|
||||||
kIn1PId,"in1",abuf1 )) != kOkRC )
|
|
||||||
|
ctx->userPtr = inst;
|
||||||
|
|
||||||
|
for(unsigned i=0; 1; ++i)
|
||||||
{
|
{
|
||||||
goto errLabel;
|
const abuf_t* abuf = nullptr; //
|
||||||
|
|
||||||
|
char label[32];
|
||||||
|
snprintf(label,31,"in%i",i);
|
||||||
|
label[31] = 0;
|
||||||
|
|
||||||
|
// TODO: allow non-contiguous source labels
|
||||||
|
|
||||||
|
// the source labels must be contiguous
|
||||||
|
if( !var_has_value( ctx, label, kAnyChIdx ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// get the source audio buffer
|
||||||
|
if((rc = var_register_and_get(ctx, kAnyChIdx,kInBasePId+i,label,abuf )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i == 0 )
|
||||||
|
{
|
||||||
|
frameN = abuf->frameN;
|
||||||
|
srate = abuf->srate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: check srate and frameN are same as first src
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->srcN += 1;
|
||||||
|
outChN += abuf->chN;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( abuf0->frameN == abuf1->frameN );
|
//outChN = abuf0->chN + abuf1->chN;
|
||||||
|
|
||||||
outChN = abuf0->chN + abuf1->chN;
|
|
||||||
|
|
||||||
// register the gain
|
// register the gain
|
||||||
for(unsigned i=0; i<outChN; ++i)
|
for(unsigned i=0; i<outChN; ++i)
|
||||||
@ -1018,14 +1047,20 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
// create the output audio buffer
|
// create the output audio buffer
|
||||||
rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf0->srate, outChN, abuf0->frameN );
|
rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srate, outChN, frameN );
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t destroy( instance_t* ctx )
|
rc_t destroy( instance_t* ctx )
|
||||||
{ return kOkRC; }
|
{
|
||||||
|
inst_t* inst = (inst_t*)ctx->userPtr;
|
||||||
|
|
||||||
|
mem::release(inst);
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
rc_t value( instance_t* ctx, variable_t* var )
|
rc_t value( instance_t* ctx, variable_t* var )
|
||||||
{ return kOkRC; }
|
{ return kOkRC; }
|
||||||
@ -1052,6 +1087,7 @@ namespace cw
|
|||||||
return outChIdx;
|
return outChIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
rc_t exec( instance_t* ctx )
|
rc_t exec( instance_t* ctx )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -1074,6 +1110,31 @@ namespace cw
|
|||||||
|
|
||||||
assert( oChIdx == obuf->chN );
|
assert( oChIdx == obuf->chN );
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc_t exec( instance_t* ctx )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
inst_t* inst = (inst_t*)ctx->userPtr;
|
||||||
|
abuf_t* obuf = nullptr;
|
||||||
|
unsigned oChIdx = 0;
|
||||||
|
|
||||||
|
if((rc = var_get(ctx,kOutPId, kAnyChIdx, obuf)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<inst->srcN; ++i)
|
||||||
|
{
|
||||||
|
const abuf_t* ibuf = nullptr;
|
||||||
|
|
||||||
|
if((rc = var_get(ctx,kInBasePId+i, kAnyChIdx, ibuf )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
oChIdx = _exec( ctx, ibuf, obuf, oChIdx );
|
||||||
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1087,6 +1148,7 @@ namespace cw
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
@ -1013,9 +1013,10 @@ void cw::flow::class_dict_print( flow_t* p )
|
|||||||
|
|
||||||
for(; vd!=nullptr; vd=vd->link)
|
for(; vd!=nullptr; vd=vd->link)
|
||||||
{
|
{
|
||||||
const char* srcFlStr = vd->flags&kSrcVarFl ? "src" : " ";
|
const char* srcFlStr = vd->flags & kSrcVarFl ? "src" : " ";
|
||||||
|
const char* srcOptFlStr = vd->flags & kSrcOptVarFl ? "srcOpt" : " ";
|
||||||
|
|
||||||
printf(" %10s 0x%08x %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, cwStringNullGuard(vd->docText) );
|
printf(" %10s 0x%08x %s %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, srcOptFlStr, cwStringNullGuard(vd->docText) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1162,6 +1163,17 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns
|
|||||||
bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned chIdx )
|
bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned chIdx )
|
||||||
{ return _var_find_on_label_and_ch(inst,label,chIdx) != nullptr; }
|
{ return _var_find_on_label_and_ch(inst,label,chIdx) != nullptr; }
|
||||||
|
|
||||||
|
bool cw::flow::var_has_value( instance_t* inst, const char* label, unsigned chIdx )
|
||||||
|
{
|
||||||
|
variable_t* varPtr = nullptr;
|
||||||
|
rc_t rc;
|
||||||
|
|
||||||
|
if((rc = var_find( inst, label, chIdx, varPtr )) != kOkRC )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return varPtr->value != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef )
|
cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef )
|
||||||
{
|
{
|
||||||
|
@ -115,7 +115,9 @@ namespace cw
|
|||||||
typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var );
|
typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var );
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kSrcVarFl = 0x01
|
kSrcVarFl = 0x01,
|
||||||
|
kSrcOptVarFl = 0x02
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct class_members_str
|
typedef struct class_members_str
|
||||||
@ -397,6 +399,7 @@ namespace cw
|
|||||||
void _var_destroy( variable_t* var );
|
void _var_destroy( variable_t* var );
|
||||||
|
|
||||||
bool var_exists( instance_t* inst, const char* label, unsigned chIdx );
|
bool var_exists( instance_t* inst, const char* label, unsigned chIdx );
|
||||||
|
bool var_has_value( instance_t* inst, const char* label, unsigned chIdx );
|
||||||
|
|
||||||
rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& varRef );
|
rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& varRef );
|
||||||
rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& varRef );
|
rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& varRef );
|
||||||
|
99
cwIo.cpp
99
cwIo.cpp
@ -38,6 +38,14 @@ namespace cw
|
|||||||
|
|
||||||
struct io_str;
|
struct io_str;
|
||||||
|
|
||||||
|
typedef struct thread_str
|
||||||
|
{
|
||||||
|
unsigned id;
|
||||||
|
void* arg;
|
||||||
|
struct io_str* p;
|
||||||
|
struct thread_str* link;
|
||||||
|
} thread_t;
|
||||||
|
|
||||||
typedef struct timer_str
|
typedef struct timer_str
|
||||||
{
|
{
|
||||||
struct io_str* io;
|
struct io_str* io;
|
||||||
@ -85,8 +93,7 @@ namespace cw
|
|||||||
bool enableFl;
|
bool enableFl;
|
||||||
char* label;
|
char* label;
|
||||||
unsigned sockA_index;
|
unsigned sockA_index;
|
||||||
unsigned userId;
|
unsigned userId;
|
||||||
|
|
||||||
} socket_t;
|
} socket_t;
|
||||||
|
|
||||||
typedef struct io_str
|
typedef struct io_str
|
||||||
@ -102,6 +109,8 @@ namespace cw
|
|||||||
|
|
||||||
object_t* cfg;
|
object_t* cfg;
|
||||||
|
|
||||||
|
thread_t* threadL;
|
||||||
|
|
||||||
timer_t* timerA;
|
timer_t* timerA;
|
||||||
unsigned timerN;
|
unsigned timerN;
|
||||||
|
|
||||||
@ -141,6 +150,36 @@ namespace cw
|
|||||||
io_t* _handleToPtr( handle_t h )
|
io_t* _handleToPtr( handle_t h )
|
||||||
{ return handleToPtr<handle_t,io_t>(h); }
|
{ return handleToPtr<handle_t,io_t>(h); }
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Thread
|
||||||
|
//
|
||||||
|
bool _threadFunc( void* arg )
|
||||||
|
{
|
||||||
|
thread_t* t = (thread_t*)arg;
|
||||||
|
thread_msg_t tm = { .id=t->id, .arg=t->arg };
|
||||||
|
msg_t m;
|
||||||
|
|
||||||
|
m.tid = kThreadTId;
|
||||||
|
m.u.thread = &tm;
|
||||||
|
|
||||||
|
t->p->cbFunc( t->p->cbArg, &m );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _threadRelease( io_t* p )
|
||||||
|
{
|
||||||
|
thread_t* t0 = p->threadL;
|
||||||
|
for(; t0!=nullptr; t0=t0->link)
|
||||||
|
{
|
||||||
|
thread_t* t1 = t0->link;
|
||||||
|
mem::release(t0);
|
||||||
|
t0 = t1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Timer
|
// Timer
|
||||||
@ -335,7 +374,10 @@ namespace cw
|
|||||||
|
|
||||||
// get the serial port list node
|
// get the serial port list node
|
||||||
if((cfg = c->find("serial")) == nullptr)
|
if((cfg = c->find("serial")) == nullptr)
|
||||||
return cwLogError(kSyntaxErrorRC,"Unable to locate the 'serial' configuration.");
|
{
|
||||||
|
cwLogWarning("No 'serial' configuration.");
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
// the serial header values
|
// the serial header values
|
||||||
if((rc = cfg->getv("pollPeriodMs", pollPeriodMs,
|
if((rc = cfg->getv("pollPeriodMs", pollPeriodMs,
|
||||||
@ -413,10 +455,11 @@ namespace cw
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
// the service is only started if at least one serial port is enabled
|
if( p->serialPortSrvH.isValid() )
|
||||||
if( serialPort::portCount( serialPortSrv::serialHandle(p->serialPortSrvH) ) > 0 )
|
// the service is only started if at least one serial port is enabled
|
||||||
if((rc =serialPortSrv::start( p->serialPortSrvH )) != kOkRC )
|
if( serialPort::portCount( serialPortSrv::serialHandle(p->serialPortSrvH) ) > 0 )
|
||||||
rc = cwLogError(rc,"The serial port server start failed.");
|
if((rc =serialPortSrv::start( p->serialPortSrvH )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"The serial port server start failed.");
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -461,9 +504,11 @@ namespace cw
|
|||||||
|
|
||||||
// get the MIDI port cfg
|
// get the MIDI port cfg
|
||||||
if((cfg = c->find("midi")) == nullptr)
|
if((cfg = c->find("midi")) == nullptr)
|
||||||
return cwLogError(kSyntaxErrorRC,"Unable to locate the 'MIDI' configuration.");
|
{
|
||||||
|
cwLogWarning("No 'MIDI' configuration.");
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
if((rc = cfg->getv(
|
if((rc = cfg->getv(
|
||||||
"parserBufByteN", parserBufByteN )) != kOkRC )
|
"parserBufByteN", parserBufByteN )) != kOkRC )
|
||||||
{
|
{
|
||||||
@ -586,8 +631,8 @@ namespace cw
|
|||||||
// get the socket configuration node
|
// get the socket configuration node
|
||||||
if((node = cfg->find("socket")) == nullptr )
|
if((node = cfg->find("socket")) == nullptr )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"Unable to locate the 'socket' configuration node.");
|
cwLogWarning("No 'socket' configuration node.");
|
||||||
goto errLabel;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the required socket arguments
|
// get the required socket arguments
|
||||||
@ -1469,8 +1514,11 @@ namespace cw
|
|||||||
|
|
||||||
// get the audio port node
|
// get the audio port node
|
||||||
if((node = cfg->find("audio")) == nullptr )
|
if((node = cfg->find("audio")) == nullptr )
|
||||||
return cwLogError(kSyntaxErrorRC,"Unable to locate the 'audio' configuration node.");
|
{
|
||||||
|
cwLogWarning("No 'audio' configuration node.");
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
// get the meterMs value
|
// get the meterMs value
|
||||||
if((rc = node->getv("meterMs", p->audioMeterCbPeriodMs, "threadTimeOutMs", p->audioThreadTimeOutMs )) != kOkRC )
|
if((rc = node->getv("meterMs", p->audioMeterCbPeriodMs, "threadTimeOutMs", p->audioThreadTimeOutMs )) != kOkRC )
|
||||||
{
|
{
|
||||||
@ -1863,6 +1911,29 @@ void cw::io::report( handle_t h )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Thread
|
||||||
|
//
|
||||||
|
|
||||||
|
cw::rc_t cw::io::threadCreate( handle_t h, unsigned id, void* arg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
thread_t* t = mem::allocZ<thread_t>(1);
|
||||||
|
|
||||||
|
t->id = id;
|
||||||
|
t->arg = arg;
|
||||||
|
t->p = p;
|
||||||
|
t->link = p->threadL;
|
||||||
|
p->threadL = t;
|
||||||
|
|
||||||
|
if((rc = thread_mach::add( p->threadMachH, _threadFunc, t )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Thread create failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Timer
|
// Timer
|
||||||
|
13
cwIo.h
13
cwIo.h
@ -27,6 +27,7 @@ namespace cw
|
|||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
kThreadTId,
|
||||||
kTimerTId,
|
kTimerTId,
|
||||||
kSerialTId,
|
kSerialTId,
|
||||||
kMidiTId,
|
kMidiTId,
|
||||||
@ -37,6 +38,12 @@ namespace cw
|
|||||||
kUiTId
|
kUiTId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct thread_msg_str
|
||||||
|
{
|
||||||
|
unsigned id;
|
||||||
|
void* arg;
|
||||||
|
} thread_msg_t;
|
||||||
|
|
||||||
typedef struct timer_msg_str
|
typedef struct timer_msg_str
|
||||||
{
|
{
|
||||||
unsigned id;
|
unsigned id;
|
||||||
@ -121,6 +128,7 @@ namespace cw
|
|||||||
unsigned tid;
|
unsigned tid;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
thread_msg_t* thread;
|
||||||
timer_msg_t* timer;
|
timer_msg_t* timer;
|
||||||
serial_msg_t* serial;
|
serial_msg_t* serial;
|
||||||
midi_msg_t* midi;
|
midi_msg_t* midi;
|
||||||
@ -151,6 +159,11 @@ namespace cw
|
|||||||
bool isShuttingDown( handle_t h );
|
bool isShuttingDown( handle_t h );
|
||||||
void report( handle_t h );
|
void report( handle_t h );
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Thread
|
||||||
|
//
|
||||||
|
rc_t threadCreate( handle_t h, unsigned id, void* arg );
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
@ -35,9 +35,11 @@ namespace cw
|
|||||||
kMidiThruCheckId,
|
kMidiThruCheckId,
|
||||||
kCurMidiEvtCntId,
|
kCurMidiEvtCntId,
|
||||||
kTotalMidiEvtCntId,
|
kTotalMidiEvtCntId,
|
||||||
|
kMidiMuteCheckId,
|
||||||
|
|
||||||
kCurAudioSecsId,
|
kCurAudioSecsId,
|
||||||
kTotalAudioSecsId,
|
kTotalAudioSecsId,
|
||||||
|
kAudioMuteCheckId,
|
||||||
|
|
||||||
kSaveBtnId,
|
kSaveBtnId,
|
||||||
kOpenBtnId,
|
kOpenBtnId,
|
||||||
@ -66,10 +68,11 @@ namespace cw
|
|||||||
{ kPanelDivId, kMidiThruCheckId, "midiThruCheckId" },
|
{ kPanelDivId, kMidiThruCheckId, "midiThruCheckId" },
|
||||||
{ kPanelDivId, kCurMidiEvtCntId, "curMidiEvtCntId" },
|
{ kPanelDivId, kCurMidiEvtCntId, "curMidiEvtCntId" },
|
||||||
{ kPanelDivId, kTotalMidiEvtCntId, "totalMidiEvtCntId" },
|
{ kPanelDivId, kTotalMidiEvtCntId, "totalMidiEvtCntId" },
|
||||||
|
{ kPanelDivId, kMidiMuteCheckId, "midiMuteCheckId" },
|
||||||
|
|
||||||
{ kPanelDivId, kCurAudioSecsId, "curAudioSecsId" },
|
{ kPanelDivId, kCurAudioSecsId, "curAudioSecsId" },
|
||||||
{ kPanelDivId, kTotalAudioSecsId, "totalAudioSecsId" },
|
{ kPanelDivId, kTotalAudioSecsId, "totalAudioSecsId" },
|
||||||
|
{ kPanelDivId, kAudioMuteCheckId, "audioMuteCheckId" },
|
||||||
|
|
||||||
{ kPanelDivId, kSaveBtnId, "saveBtnId" },
|
{ kPanelDivId, kSaveBtnId, "saveBtnId" },
|
||||||
{ kPanelDivId, kOpenBtnId, "openBtnId" },
|
{ kPanelDivId, kOpenBtnId, "openBtnId" },
|
||||||
@ -89,7 +92,10 @@ namespace cw
|
|||||||
char* directory;
|
char* directory;
|
||||||
|
|
||||||
midi_record_play::handle_t mrpH;
|
midi_record_play::handle_t mrpH;
|
||||||
audio_record_play::handle_t arpH;
|
audio_record_play::handle_t arpH;
|
||||||
|
|
||||||
|
const object_t* midi_play_record_cfg;
|
||||||
|
|
||||||
} app_t;
|
} app_t;
|
||||||
|
|
||||||
rc_t _parseCfg(app_t* app, const object_t* cfg )
|
rc_t _parseCfg(app_t* app, const object_t* cfg )
|
||||||
@ -99,7 +105,8 @@ namespace cw
|
|||||||
if((rc = cfg->getv(
|
if((rc = cfg->getv(
|
||||||
"record_dir", app->record_dir,
|
"record_dir", app->record_dir,
|
||||||
"record_folder", app->record_folder,
|
"record_folder", app->record_folder,
|
||||||
"record_fn_ext", app->record_fn_ext)) != kOkRC )
|
"record_fn_ext", app->record_fn_ext,
|
||||||
|
"midi_play_record", app->midi_play_record_cfg)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"Audio MIDI app configuration parse failed.");
|
rc = cwLogError(kSyntaxErrorRC,"Audio MIDI app configuration parse failed.");
|
||||||
}
|
}
|
||||||
@ -172,6 +179,15 @@ namespace cw
|
|||||||
|
|
||||||
mem::release(fn);
|
mem::release(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((fn = filesys::makeFn(dir,"midi","csv",nullptr)) != nullptr )
|
||||||
|
{
|
||||||
|
if((rc0 = midi_record_play::save_csv( app->mrpH, fn )) != kOkRC )
|
||||||
|
rc0 = cwLogError(rc0,"MIDI CSV file '%s' save failed.",fn);
|
||||||
|
|
||||||
|
mem::release(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if((fn = filesys::makeFn(dir,"audio","wav",nullptr)) != nullptr )
|
if((fn = filesys::makeFn(dir,"audio","wav",nullptr)) != nullptr )
|
||||||
{
|
{
|
||||||
@ -355,6 +371,7 @@ namespace cw
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case kReportBtnId:
|
case kReportBtnId:
|
||||||
|
report( app->mrpH );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSaveBtnId:
|
case kSaveBtnId:
|
||||||
@ -374,6 +391,14 @@ namespace cw
|
|||||||
cwLogInfo("MIDI thru:%i",m.value->u.b);
|
cwLogInfo("MIDI thru:%i",m.value->u.b);
|
||||||
_set_midi_thru_state(app, m.value->u.b);
|
_set_midi_thru_state(app, m.value->u.b);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kMidiMuteCheckId:
|
||||||
|
midi_record_play::set_mute_state(app->mrpH,m.value->u.b);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kAudioMuteCheckId:
|
||||||
|
audio_record_play::set_mute_state(app->arpH,m.value->u.b);
|
||||||
|
break;
|
||||||
|
|
||||||
case kStartBtnId:
|
case kStartBtnId:
|
||||||
_on_ui_start(app);
|
_on_ui_start(app);
|
||||||
@ -518,7 +543,7 @@ cw::rc_t cw::audio_midi_app::main( const object_t* cfg )
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// create the MIDI record-play object
|
// create the MIDI record-play object
|
||||||
if((rc = midi_record_play::create(app.mrpH,app.ioH,*cfg)) != kOkRC )
|
if((rc = midi_record_play::create(app.mrpH,app.ioH,*app.midi_play_record_cfg)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"MIDI record-play object create failed.");
|
rc = cwLogError(rc,"MIDI record-play object create failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
@ -39,6 +39,8 @@ namespace cw
|
|||||||
unsigned curFrameIdx;
|
unsigned curFrameIdx;
|
||||||
bool recordFl;
|
bool recordFl;
|
||||||
bool startedFl;
|
bool startedFl;
|
||||||
|
|
||||||
|
bool mute_fl;
|
||||||
|
|
||||||
unsigned* audioInChMapA;
|
unsigned* audioInChMapA;
|
||||||
unsigned audioInChMapN;
|
unsigned audioInChMapN;
|
||||||
@ -169,8 +171,11 @@ namespace cw
|
|||||||
for(unsigned chIdx=0; chIdx<chCnt; ++chIdx)
|
for(unsigned chIdx=0; chIdx<chCnt; ++chIdx)
|
||||||
{
|
{
|
||||||
unsigned srcChIdx = p->audioInChMapA == nullptr ? chIdx : p->audioInChMapA[chIdx];
|
unsigned srcChIdx = p->audioInChMapA == nullptr ? chIdx : p->audioInChMapA[chIdx];
|
||||||
|
|
||||||
memcpy(a->audioBuf + chIdx*asrc.dspFrameCnt, asrc.iBufArray[ srcChIdx ], asrc.dspFrameCnt * sizeof(sample_t));
|
if( srcChIdx >= asrc.iBufChCnt )
|
||||||
|
cwLogError(kInvalidArgRC,"Invalid input channel map index:%i >= %i.",srcChIdx,asrc.iBufChCnt);
|
||||||
|
else
|
||||||
|
memcpy(a->audioBuf + chIdx*asrc.dspFrameCnt, asrc.iBufArray[ srcChIdx ], asrc.dspFrameCnt * sizeof(sample_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
a->chCnt = chCnt;
|
a->chCnt = chCnt;
|
||||||
@ -197,31 +202,34 @@ namespace cw
|
|||||||
void _audio_play( audio_record_play_t* p, io::audio_msg_t& adst )
|
void _audio_play( audio_record_play_t* p, io::audio_msg_t& adst )
|
||||||
{
|
{
|
||||||
unsigned adst_idx = 0;
|
unsigned adst_idx = 0;
|
||||||
|
|
||||||
while(adst_idx < adst.dspFrameCnt)
|
if( !p->mute_fl )
|
||||||
{
|
{
|
||||||
am_audio_t* a;
|
while(adst_idx < adst.dspFrameCnt)
|
||||||
unsigned sample_offs = 0;
|
|
||||||
if((a = _am_audio_from_sample_index(p, p->curFrameIdx, sample_offs )) == nullptr )
|
|
||||||
break;
|
|
||||||
|
|
||||||
unsigned n = std::min(a->dspFrameCnt - sample_offs, adst.dspFrameCnt );
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Verify that this is correct - it looks like sample_offs should have to be incremented
|
|
||||||
|
|
||||||
for(unsigned i=0; i<a->chCnt; ++i)
|
|
||||||
{
|
{
|
||||||
unsigned dstChIdx = p->audioOutChMapA != nullptr && i < p->audioOutChMapN ? p->audioOutChMapA[i] : i;
|
am_audio_t* a;
|
||||||
|
unsigned sample_offs = 0;
|
||||||
|
if((a = _am_audio_from_sample_index(p, p->curFrameIdx, sample_offs )) == nullptr )
|
||||||
|
break;
|
||||||
|
|
||||||
if( dstChIdx < adst.oBufChCnt )
|
unsigned n = std::min(a->dspFrameCnt - sample_offs, adst.dspFrameCnt );
|
||||||
memcpy( adst.oBufArray[ dstChIdx ] + adst_idx, a->audioBuf + sample_offs, n * sizeof(sample_t));
|
|
||||||
|
|
||||||
|
// TODO: Verify that this is correct - it looks like sample_offs should have to be incremented
|
||||||
|
|
||||||
|
for(unsigned i=0; i<a->chCnt; ++i)
|
||||||
|
{
|
||||||
|
unsigned dstChIdx = p->audioOutChMapA != nullptr && i < p->audioOutChMapN ? p->audioOutChMapA[i] : i;
|
||||||
|
|
||||||
|
if( dstChIdx < adst.oBufChCnt )
|
||||||
|
memcpy( adst.oBufArray[ dstChIdx ] + adst_idx, a->audioBuf + sample_offs, n * sizeof(sample_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
p->curFrameIdx += n;
|
||||||
|
adst_idx += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->curFrameIdx += n;
|
|
||||||
adst_idx += n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: zero unused channels
|
// TODO: zero unused channels
|
||||||
|
|
||||||
if( adst_idx < adst.dspFrameCnt )
|
if( adst_idx < adst.dspFrameCnt )
|
||||||
@ -415,9 +423,16 @@ namespace cw
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( m.oBufChCnt > 0 )
|
if( m.oBufChCnt > 0 )
|
||||||
|
{
|
||||||
_audio_play(p,m);
|
_audio_play(p,m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<m.oBufChCnt; ++i)
|
||||||
|
memset( m.oBufArray[i], 0, m.dspFrameCnt * sizeof(sample_t));
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -522,6 +537,22 @@ bool cw::audio_record_play::record_state( handle_t h )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::audio_record_play::set_mute_state( handle_t h, bool mute_fl )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
audio_record_play_t* p = _handleToPtr(h);
|
||||||
|
p->mute_fl = true;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cw::audio_record_play::mute_state( handle_t h )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
audio_record_play_t* p = _handleToPtr(h);
|
||||||
|
return p->mute_fl;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cw::rc_t cw::audio_record_play::save( handle_t h, const char* fn )
|
cw::rc_t cw::audio_record_play::save( handle_t h, const char* fn )
|
||||||
{
|
{
|
||||||
audio_record_play_t* p = _handleToPtr(h);
|
audio_record_play_t* p = _handleToPtr(h);
|
||||||
|
@ -17,6 +17,8 @@ namespace cw
|
|||||||
rc_t clear( handle_t h );
|
rc_t clear( handle_t h );
|
||||||
rc_t set_record_state( handle_t h, bool record_fl );
|
rc_t set_record_state( handle_t h, bool record_fl );
|
||||||
bool record_state( handle_t h );
|
bool record_state( handle_t h );
|
||||||
|
rc_t set_mute_state( handle_t h, bool mute_fl );
|
||||||
|
bool mute_state( handle_t h );
|
||||||
rc_t save( handle_t h, const char* fn );
|
rc_t save( handle_t h, const char* fn );
|
||||||
rc_t open( handle_t h, const char* fn );
|
rc_t open( handle_t h, const char* fn );
|
||||||
double duration_seconds( handle_t h );
|
double duration_seconds( handle_t h );
|
||||||
|
@ -54,6 +54,16 @@ namespace cw
|
|||||||
|
|
||||||
unsigned pedalUpHalfVelId;
|
unsigned pedalUpHalfVelId;
|
||||||
unsigned pedalUpHalfVel;
|
unsigned pedalUpHalfVel;
|
||||||
|
|
||||||
|
unsigned velHistogram[ midi::kMidiVelCnt ];
|
||||||
|
|
||||||
|
bool force_damper_down_fl;
|
||||||
|
unsigned force_damper_down_threshold;
|
||||||
|
unsigned force_damper_down_velocity;
|
||||||
|
|
||||||
|
bool damper_dead_band_enable_fl;
|
||||||
|
unsigned damper_dead_band_min_value;
|
||||||
|
unsigned damper_dead_band_max_value;
|
||||||
|
|
||||||
} midi_device_t;
|
} midi_device_t;
|
||||||
|
|
||||||
@ -89,9 +99,12 @@ namespace cw
|
|||||||
|
|
||||||
bool startedFl;
|
bool startedFl;
|
||||||
bool recordFl;
|
bool recordFl;
|
||||||
|
bool muteFl;
|
||||||
bool thruFl;
|
bool thruFl;
|
||||||
bool logInFl; // log incoming message when not in 'record' mode.
|
bool logInFl; // log incoming message when not in 'record' mode.
|
||||||
bool logOutFl; // log outgoing messages
|
bool logOutFl; // log outgoing messages
|
||||||
|
|
||||||
|
bool velHistogramEnableFl;
|
||||||
|
|
||||||
bool halfPedalFl;
|
bool halfPedalFl;
|
||||||
unsigned halfPedalState;
|
unsigned halfPedalState;
|
||||||
@ -190,12 +203,27 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if((rc = ele->getv_opt( "vel_table", velTable,
|
if((rc = ele->getv_opt(
|
||||||
"pedal", pedalRecd)) != kOkRC )
|
"vel_table", velTable,
|
||||||
|
"pedal", pedalRecd,
|
||||||
|
"force_damper_down_fl",p->midiDevA[i].force_damper_down_fl,
|
||||||
|
"force_damper_down_threshold",p->midiDevA[i].force_damper_down_threshold,
|
||||||
|
"force_damper_down_velocity", p->midiDevA[i].force_damper_down_velocity,
|
||||||
|
"damper_dead_band_enable_fl", p->midiDevA[i].damper_dead_band_enable_fl,
|
||||||
|
"damper_dead_band_min_value", p->midiDevA[i].damper_dead_band_min_value,
|
||||||
|
"damper_dead_band_max_value", p->midiDevA[i].damper_dead_band_max_value)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"MIDI record play device optional argument parsing failed.");
|
rc = cwLogError(kSyntaxErrorRC,"MIDI record play device optional argument parsing failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cwLogInfo("Force Pedal: enabled:%i thresh:%i veloc:%i dead band: enable:%i min:%i max:%i",
|
||||||
|
p->midiDevA[i].force_damper_down_fl,
|
||||||
|
p->midiDevA[i].force_damper_down_threshold,
|
||||||
|
p->midiDevA[i].force_damper_down_velocity,
|
||||||
|
p->midiDevA[i].damper_dead_band_enable_fl,
|
||||||
|
p->midiDevA[i].damper_dead_band_min_value,
|
||||||
|
p->midiDevA[i].damper_dead_band_max_value );
|
||||||
|
|
||||||
p->midiDevA[i].midiOutDevLabel = mem::duplStr( midiOutDevLabel);
|
p->midiDevA[i].midiOutDevLabel = mem::duplStr( midiOutDevLabel);
|
||||||
p->midiDevA[i].midiOutPortLabel = mem::duplStr( midiOutPortLabel);
|
p->midiDevA[i].midiOutPortLabel = mem::duplStr( midiOutPortLabel);
|
||||||
@ -254,6 +282,9 @@ namespace cw
|
|||||||
const am_midi_msg_t* _midi_store( midi_record_play_t* p, unsigned devIdx, unsigned portIdx, const time::spec_t& ts, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
const am_midi_msg_t* _midi_store( midi_record_play_t* p, unsigned devIdx, unsigned portIdx, const time::spec_t& ts, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||||
{
|
{
|
||||||
am_midi_msg_t* am = nullptr;
|
am_midi_msg_t* am = nullptr;
|
||||||
|
|
||||||
|
//if( !midi::isPedal(status,d0) )
|
||||||
|
// printf("MIDI store: %i : ch:%i st:%i d0:%i d1:%i\n",p->iMsgArrayInIdx,ch,status,d0,d1);
|
||||||
|
|
||||||
// verify that space exists in the record buffer
|
// verify that space exists in the record buffer
|
||||||
if( p->iMsgArrayInIdx < p->iMsgArrayN )
|
if( p->iMsgArrayInIdx < p->iMsgArrayN )
|
||||||
@ -281,13 +312,14 @@ namespace cw
|
|||||||
rc_t _event_callback( midi_record_play_t* p, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1, bool log_fl=true )
|
rc_t _event_callback( midi_record_play_t* p, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1, bool log_fl=true )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
// if we have arrived at the stop time
|
// if we have arrived at the stop time
|
||||||
bool after_stop_time_fl = !time::isZero(p->end_play_event_timestamp) && time::isGT(timestamp,p->end_play_event_timestamp);
|
bool after_stop_time_fl = !time::isZero(p->end_play_event_timestamp) && time::isGT(timestamp,p->end_play_event_timestamp);
|
||||||
bool after_all_off_fl = after_stop_time_fl && time::isGT(timestamp,p->all_off_timestamp);
|
bool after_all_off_fl = after_stop_time_fl && time::isGT(timestamp,p->all_off_timestamp);
|
||||||
|
|
||||||
bool is_note_on_fl = status==midi::kNoteOnMdId and d1 != 0;
|
bool is_note_on_fl = status==midi::kNoteOnMdId and d1 != 0;
|
||||||
bool supress_fl = is_note_on_fl && after_stop_time_fl;
|
bool is_damper_fl = status==midi::kCtlMdId and d0==midi::kSustainCtlMdId;
|
||||||
|
bool supress_fl = (is_note_on_fl && after_stop_time_fl) || p->muteFl;
|
||||||
|
bool is_pedal_fl = midi::isPedal( status, d0 );
|
||||||
|
|
||||||
if( after_all_off_fl )
|
if( after_all_off_fl )
|
||||||
{
|
{
|
||||||
@ -320,6 +352,19 @@ namespace cw
|
|||||||
out_d1 = p->midiDevA[i].velTableArray[ d1 ];
|
out_d1 = p->midiDevA[i].velTableArray[ d1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store the note-on velocity histogram data
|
||||||
|
if( p->velHistogramEnableFl && is_note_on_fl && out_d1 < midi::kMidiVelCnt )
|
||||||
|
p->midiDevA[i].velHistogram[ out_d1 ] += 1;
|
||||||
|
|
||||||
|
// if the damper pedal velocity is in the dead band then don't send it
|
||||||
|
if( p->midiDevA[i].damper_dead_band_enable_fl && is_pedal_fl && p->midiDevA[i].damper_dead_band_min_value <= out_d1 && out_d1 <= p->midiDevA[i].damper_dead_band_max_value )
|
||||||
|
out_d1 = 0;
|
||||||
|
|
||||||
|
// if the damper pedal velocity is over the 'forcing' threshold then force the damper down
|
||||||
|
if( p->midiDevA[i].force_damper_down_fl && is_damper_fl && out_d1>p->midiDevA[i].force_damper_down_threshold )
|
||||||
|
out_d1 = p->midiDevA[i].force_damper_down_velocity;
|
||||||
|
|
||||||
|
|
||||||
// map the pedal down velocity
|
// map the pedal down velocity
|
||||||
if( status==midi::kCtlMdId && d0 == midi::kSustainCtlMdId && p->midiDevA[i].pedalMapEnableFl )
|
if( status==midi::kCtlMdId && d0 == midi::kSustainCtlMdId && p->midiDevA[i].pedalMapEnableFl )
|
||||||
{
|
{
|
||||||
@ -331,17 +376,21 @@ namespace cw
|
|||||||
else
|
else
|
||||||
if( d1 == p->midiDevA[i].pedalDownHalfVelId )
|
if( d1 == p->midiDevA[i].pedalDownHalfVelId )
|
||||||
out_d1 = p->midiDevA[i].pedalDownHalfVel;
|
out_d1 = p->midiDevA[i].pedalDownHalfVel;
|
||||||
else
|
else
|
||||||
cwLogError(kInvalidIdRC,"Unexpected pedal down velocity (%i) during pedal velocity mapping.",d1);
|
{
|
||||||
|
cwLogError(kInvalidIdRC,"Unexpected pedal down velocity (%i) during pedal velocity mapping. Remove the 'pedal' stanza from the MIDI device cfg to prevent pedal mapping.",d1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !supress_fl )
|
if( !supress_fl )
|
||||||
|
{
|
||||||
io::midiDeviceSend( p->ioH, p->midiDevA[i].midiOutDevIdx, p->midiDevA[i].midiOutPortIdx, status + ch, d0, out_d1 );
|
io::midiDeviceSend( p->ioH, p->midiDevA[i].midiOutDevIdx, p->midiDevA[i].midiOutPortIdx, status + ch, d0, out_d1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !after_stop_time_fl and p->cb )
|
if( !after_stop_time_fl and p->cb )
|
||||||
p->cb( p->cb_arg, id, timestamp, loc, ch, status, d0, d1 );
|
p->cb( p->cb_arg, kMidiEventActionId, id, timestamp, loc, ch, status, d0, d1 );
|
||||||
|
|
||||||
if( log_fl && p->logOutFl )
|
if( log_fl && p->logOutFl )
|
||||||
{
|
{
|
||||||
@ -355,6 +404,7 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _transmit_msg( midi_record_play_t* p, const am_midi_msg_t* am, bool log_fl=true )
|
rc_t _transmit_msg( midi_record_play_t* p, const am_midi_msg_t* am, bool log_fl=true )
|
||||||
{
|
{
|
||||||
return _event_callback( p, am->id, am->timestamp, am->loc, am->ch, am->status, am->d0, am->d1, log_fl );
|
return _event_callback( p, am->id, am->timestamp, am->loc, am->ch, am->status, am->d0, am->d1, log_fl );
|
||||||
@ -442,6 +492,53 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t _am_file_read_version_0( const char* fn, file::handle_t fH, am_midi_msg_t* amMsgArray, unsigned msgN )
|
||||||
|
{
|
||||||
|
// version 0 record type
|
||||||
|
typedef struct msg_str
|
||||||
|
{
|
||||||
|
unsigned dev_idx;
|
||||||
|
unsigned port_idx;
|
||||||
|
time::spec_t timestamp;
|
||||||
|
uint8_t ch;
|
||||||
|
uint8_t st;
|
||||||
|
uint8_t d0;
|
||||||
|
uint8_t d1;
|
||||||
|
unsigned microsecs;
|
||||||
|
} zero_msg_t;
|
||||||
|
|
||||||
|
cw::rc_t rc = kOkRC;
|
||||||
|
zero_msg_t* zMsgArray = mem::allocZ<zero_msg_t>(msgN);
|
||||||
|
unsigned fileByteN = msgN * sizeof(zero_msg_t);
|
||||||
|
|
||||||
|
if((rc = file::read(fH,zMsgArray,fileByteN)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kReadFailRC,"Data read failed on Audio-MIDI file: '%s'.", fn );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned i=0; i<msgN; ++i)
|
||||||
|
{
|
||||||
|
am_midi_msg_t* am = amMsgArray + i;
|
||||||
|
zero_msg_t* zm = zMsgArray + i;
|
||||||
|
|
||||||
|
am->devIdx = zm->dev_idx;
|
||||||
|
am->portIdx = zm->port_idx;
|
||||||
|
am->microsec = zm->microsecs;
|
||||||
|
am->id = i;
|
||||||
|
am->timestamp = zm->timestamp;
|
||||||
|
am->loc = i;
|
||||||
|
am->ch = zm->ch;
|
||||||
|
am->status = zm->st;
|
||||||
|
am->d0 = zm->d0;
|
||||||
|
am->d1 = zm->d1;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
mem::release(zMsgArray);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
// Read the am_midi_msg_t records from a file written by _midi_write()
|
// Read the am_midi_msg_t records from a file written by _midi_write()
|
||||||
// If msgArrayCntRef==0 and msgArrayRef==NULL then an array will be allocated and it is up
|
// If msgArrayCntRef==0 and msgArrayRef==NULL then an array will be allocated and it is up
|
||||||
// to the caller to release it, otherwise the msgArrayCntRef should be set to the count
|
// to the caller to release it, otherwise the msgArrayCntRef should be set to the count
|
||||||
@ -450,44 +547,95 @@ namespace cw
|
|||||||
// msgArrayCntRef records will be returned.
|
// msgArrayCntRef records will be returned.
|
||||||
cw::rc_t _am_file_read( const char* fn, unsigned& msgArrayCntRef, am_midi_msg_t*& msgArrayRef )
|
cw::rc_t _am_file_read( const char* fn, unsigned& msgArrayCntRef, am_midi_msg_t*& msgArrayRef )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
|
||||||
unsigned n = 0;
|
rc_t rc = kOkRC;
|
||||||
|
unsigned recordN = 0; // count of records in the ifle
|
||||||
|
unsigned fileByteN = 0; // count of bytes in the file
|
||||||
|
int version = 0; // version id (always a negative number)
|
||||||
|
bool alloc_fl = false;
|
||||||
|
bool print_fl = false;
|
||||||
file::handle_t fH;
|
file::handle_t fH;
|
||||||
|
|
||||||
if((rc = file::open(fH,fn,file::kReadFl)) != kOkRC )
|
if((rc = file::open(fH,fn,file::kReadFl)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kOpenFailRC,"Unable to locate the AM file: '%s'.", fn );
|
rc = cwLogError(kOpenFailRC,"Unable to locate the AM file: '%s'.", fn );
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((rc = file::read(fH,n)) != kOkRC )
|
// read the first word - which is either a version id or the count of records in the file
|
||||||
|
// if this is a version 0 file
|
||||||
|
if((rc = file::read(fH,version)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kReadFailRC,"Header read failed on Audio-MIDI file: '%s'.", fn );
|
rc = cwLogError(kReadFailRC,"Version read failed on Audio-MIDI file: '%s'.", fn );
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the version is greater than 0 then this is a version 0 file (and 'version' holds the record count.
|
||||||
|
if( version > 0 )
|
||||||
|
{
|
||||||
|
recordN = (unsigned)version;
|
||||||
|
version = 0;
|
||||||
|
}
|
||||||
|
else // otherwise the second word in the file holds the size of the file
|
||||||
|
{
|
||||||
|
if((rc = file::read(fH,recordN)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kReadFailRC,"Header read failed on Audio-MIDI file: '%s'.", fn );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the output msg array was not allocated - then allocate it here
|
||||||
if( msgArrayCntRef == 0 || msgArrayRef == nullptr )
|
if( msgArrayCntRef == 0 || msgArrayRef == nullptr )
|
||||||
{
|
{
|
||||||
msgArrayRef = mem::allocZ<am_midi_msg_t>(n);
|
alloc_fl = true;
|
||||||
|
msgArrayRef = mem::allocZ<am_midi_msg_t>(recordN);
|
||||||
|
}
|
||||||
|
else // if the msg array was allocated but is too small - then decrease the count of records to be read from the file
|
||||||
|
{
|
||||||
|
if( recordN > msgArrayCntRef )
|
||||||
|
{
|
||||||
|
cwLogWarning("The count of message in Audio-MIDI file '%s' reduced from %i to %i.", fn, recordN, msgArrayCntRef );
|
||||||
|
recordN = msgArrayCntRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( version == 0 )
|
||||||
|
{
|
||||||
|
// read the version 0 file into a temporary buffer then translate to am_midi_msg_t records
|
||||||
|
if((rc = _am_file_read_version_0( fn, fH, msgArrayRef, recordN )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( n > msgArrayCntRef )
|
fileByteN = recordN * sizeof(am_midi_msg_t);
|
||||||
|
if((rc = file::read(fH,msgArrayRef,fileByteN)) != kOkRC )
|
||||||
{
|
{
|
||||||
cwLogWarning("The count of message in Audio-MIDI file '%s' reduced from %i to %i.", fn, n, msgArrayCntRef );
|
rc = cwLogError(kReadFailRC,"Data read failed on Audio-MIDI file: '%s'.", fn );
|
||||||
n = msgArrayCntRef;
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( print_fl )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<recordN; ++i)
|
||||||
|
{
|
||||||
|
am_midi_msg_t* m = msgArrayRef;
|
||||||
|
double dt = time::elapsedSecs( m[0].timestamp, m[i].timestamp );
|
||||||
|
printf("%4i %4i : %6.2f %2x %2x %2x %2x : %6.2f\n", m[i].devIdx, m[i].portIdx, dt, m[i].ch, m[i].status, m[i].d0, m[i].d1, m[i].microsec/(1000.0*1000.0) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((rc = file::read(fH,msgArrayRef,n*sizeof(am_midi_msg_t))) != kOkRC )
|
msgArrayCntRef = recordN;
|
||||||
{
|
|
||||||
rc = cwLogError(kReadFailRC,"Data read failed on Audio-MIDI file: '%s'.", fn );
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
msgArrayCntRef = n;
|
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
|
||||||
|
if( rc != kOkRC and alloc_fl )
|
||||||
|
{
|
||||||
|
mem::release(msgArrayRef);
|
||||||
|
msgArrayRef = nullptr;
|
||||||
|
msgArrayCntRef = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -497,14 +645,21 @@ namespace cw
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
|
int version;
|
||||||
file::handle_t fH;
|
file::handle_t fH;
|
||||||
|
|
||||||
if((rc = file::open(fH,fn,file::kReadFl)) != kOkRC )
|
if((rc = file::open(fH,fn,file::kReadFl)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kOpenFailRC,"Unable to locate the file: '%s'.", fn );
|
rc = cwLogError(kOpenFailRC,"Unable to locate the file: '%s'.", fn );
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((rc = file::read(fH,version)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kReadFailRC,"Version read failed on Audio-MIDI file: '%s'.", fn );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
if((rc = file::read(fH,n)) != kOkRC )
|
if((rc = file::read(fH,n)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kReadFailRC,"Header read failed on Audio-MIDI file: '%s'.", fn );
|
rc = cwLogError(kReadFailRC,"Header read failed on Audio-MIDI file: '%s'.", fn );
|
||||||
@ -539,7 +694,10 @@ namespace cw
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
file::handle_t fH;
|
file::handle_t fH;
|
||||||
|
// NOTE: version must be a small negative number to differentiate from file version that
|
||||||
|
// whose first word is the count of records in the file, rather than the version number
|
||||||
|
int version = -1;
|
||||||
|
|
||||||
if( p->iMsgArrayInIdx == 0 )
|
if( p->iMsgArrayInIdx == 0 )
|
||||||
{
|
{
|
||||||
cwLogWarning("Nothing to write.");
|
cwLogWarning("Nothing to write.");
|
||||||
@ -553,6 +711,13 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write the file version
|
||||||
|
if((rc = write(fH,version)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kWriteFailRC,"Version write to '%s' failed.",cwStringNullGuard(fn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
// write the file header
|
// write the file header
|
||||||
if((rc = write(fH,p->iMsgArrayInIdx)) != kOkRC )
|
if((rc = write(fH,p->iMsgArrayInIdx)) != kOkRC )
|
||||||
{
|
{
|
||||||
@ -696,13 +861,67 @@ namespace cw
|
|||||||
|
|
||||||
void _report_midi( midi_record_play_t* p )
|
void _report_midi( midi_record_play_t* p )
|
||||||
{
|
{
|
||||||
|
printf("omsg cnt:%i\n",p->msgArrayInIdx);
|
||||||
for(unsigned i=0; i<p->msgArrayInIdx; ++i)
|
for(unsigned i=0; i<p->msgArrayInIdx; ++i)
|
||||||
{
|
{
|
||||||
am_midi_msg_t* mm = p->msgArray + i;
|
am_midi_msg_t* mm = p->msgArray + i;
|
||||||
_print_midi_msg(mm);
|
_print_midi_msg(mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
printf("imsg cnt:%i\n",p->iMsgArrayInIdx);
|
||||||
|
for(unsigned i=0; i<p->iMsgArrayInIdx; ++i)
|
||||||
|
{
|
||||||
|
am_midi_msg_t* mm = p->iMsgArray + i;
|
||||||
|
_print_midi_msg(mm);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _write_vel_histogram( midi_record_play_t* p )
|
||||||
|
{
|
||||||
|
const char* fname = "/home/kevin/temp/vel_histogram.txt";
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( !p->velHistogramEnableFl )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
file::handle_t h;
|
||||||
|
if((rc = file::open(h,fname,file::kWriteFl)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->midiDevN; ++i)
|
||||||
|
if(p->midiDevA[i].enableFl )
|
||||||
|
{
|
||||||
|
for(unsigned j=0; j<midi::kMidiVelCnt; ++j)
|
||||||
|
if((rc = file::printf(h,"%i,",p->midiDevA[i].velHistogram[j])) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Histogram output file (%s) write failed.",fname);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
file::printf(h,"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
file::close(h);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the play buffer (msgArray) from the record buffer (iMsgArray)
|
||||||
|
void _iMsgArray_to_msgArray(midi_record_play_t* p)
|
||||||
|
{
|
||||||
|
if( p->msgArrayN < p->iMsgArrayN)
|
||||||
|
{
|
||||||
|
mem::resize(p->msgArray,p->iMsgArrayN,mem::kZeroAllFl);
|
||||||
|
p->msgArrayN = p->iMsgArrayN;
|
||||||
|
}
|
||||||
|
p->msgArrayOutIdx = 0;
|
||||||
|
p->msgArrayInIdx = p->iMsgArrayInIdx;
|
||||||
|
memcpy(p->msgArray,p->iMsgArray,p->iMsgArrayInIdx*sizeof(am_midi_msg_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _stop( midi_record_play_t* p )
|
rc_t _stop( midi_record_play_t* p )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -712,6 +931,8 @@ namespace cw
|
|||||||
time::spec_t t1;
|
time::spec_t t1;
|
||||||
time::get(t1);
|
time::get(t1);
|
||||||
|
|
||||||
|
_write_vel_histogram( p );
|
||||||
|
|
||||||
// if we were recording
|
// if we were recording
|
||||||
if( p->recordFl )
|
if( p->recordFl )
|
||||||
{
|
{
|
||||||
@ -719,9 +940,12 @@ namespace cw
|
|||||||
// set the 'microsec' value for each MIDI msg as an offset from the first message[]
|
// set the 'microsec' value for each MIDI msg as an offset from the first message[]
|
||||||
for(unsigned i=0; i<p->iMsgArrayInIdx; ++i)
|
for(unsigned i=0; i<p->iMsgArrayInIdx; ++i)
|
||||||
{
|
{
|
||||||
p->msgArray[i].microsec = time::elapsedMicros(p->iMsgArray[0].timestamp,p->iMsgArray[i].timestamp);
|
p->iMsgArray[i].microsec = time::elapsedMicros(p->iMsgArray[0].timestamp,p->iMsgArray[i].timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy the recorded messages from the input buffer to the output buffer
|
||||||
|
_iMsgArray_to_msgArray(p);
|
||||||
|
|
||||||
cwLogInfo("MIDI messages recorded: %i",p->msgArrayInIdx );
|
cwLogInfo("MIDI messages recorded: %i",p->msgArrayInIdx );
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -739,6 +963,9 @@ namespace cw
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( p->cb != nullptr )
|
||||||
|
p->cb( p->cb_arg, kPlayerStoppedActionId, kInvalidId, t1, kInvalidId, 0, 0, 0, 0 );
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,12 +980,13 @@ namespace cw
|
|||||||
// if this is a sys-ex msg
|
// if this is a sys-ex msg
|
||||||
if( pkt->msgArray == NULL )
|
if( pkt->msgArray == NULL )
|
||||||
{
|
{
|
||||||
|
cwLogError(kNotImplementedRC,"Sys-ex recording not implemented.");
|
||||||
}
|
}
|
||||||
else // this is a triple
|
else // this is a triple
|
||||||
{
|
{
|
||||||
|
|
||||||
//if( !midi::isPedal(pkt->msgArray[j].status,pkt->msgArray[j].d0) )
|
//if( !midi::isPedal(pkt->msgArray[j].status,pkt->msgArray[j].d0) )
|
||||||
//printf("IN: 0x%x 0x%x 0x%x\n", pkt->msgArray[j].status, pkt->msgArray[j].d0, pkt->msgArray[j].d1 );
|
// printf("IN: 0x%x 0x%x 0x%x\n", pkt->msgArray[j].status, pkt->msgArray[j].d0, pkt->msgArray[j].d1 );
|
||||||
|
|
||||||
if( (p->recordFl || p->logInFl) && p->startedFl )
|
if( (p->recordFl || p->logInFl) && p->startedFl )
|
||||||
{
|
{
|
||||||
@ -922,6 +1150,12 @@ cw::rc_t cw::midi_record_play::start( handle_t h, bool rewindFl, const time::spe
|
|||||||
midi_record_play_t* p = _handleToPtr(h);
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
p->startedFl = true;
|
p->startedFl = true;
|
||||||
|
|
||||||
|
if( p->velHistogramEnableFl )
|
||||||
|
for(unsigned i=0; i<p->midiDevN; ++i)
|
||||||
|
if(p->midiDevA[i].enableFl )
|
||||||
|
memset(p->midiDevA[i].velHistogram,0,sizeof(p->midiDevA[i].velHistogram));
|
||||||
|
|
||||||
|
|
||||||
// set the end play time
|
// set the end play time
|
||||||
if( end_play_event_timestamp == nullptr or time::isZero(*end_play_event_timestamp) )
|
if( end_play_event_timestamp == nullptr or time::isZero(*end_play_event_timestamp) )
|
||||||
time::setZero(p->end_play_event_timestamp);
|
time::setZero(p->end_play_event_timestamp);
|
||||||
@ -999,6 +1233,21 @@ bool cw::midi_record_play::record_state( handle_t h )
|
|||||||
return p->recordFl;
|
return p->recordFl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::midi_record_play::set_mute_state( handle_t h, bool mute_fl )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
|
p->muteFl = mute_fl;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cw::midi_record_play::mute_state( handle_t h )
|
||||||
|
{
|
||||||
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
|
return p->muteFl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::midi_record_play::set_thru_state( handle_t h, bool thru_fl )
|
cw::rc_t cw::midi_record_play::set_thru_state( handle_t h, bool thru_fl )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -1085,7 +1334,7 @@ cw::rc_t cw::midi_record_play::seek( handle_t h, time::spec_t seek_timestamp )
|
|||||||
_transmit_pedal( p, mm->ch, midi::kSostenutoCtlMdId, sost_down_fl, 0 );
|
_transmit_pedal( p, mm->ch, midi::kSostenutoCtlMdId, sost_down_fl, 0 );
|
||||||
_transmit_pedal( p, mm->ch, midi::kSoftPedalCtlMdId, soft_down_fl, 0 );
|
_transmit_pedal( p, mm->ch, midi::kSoftPedalCtlMdId, soft_down_fl, 0 );
|
||||||
|
|
||||||
cwLogInfo("damper: %s.", damp_down_fl ? "down" : "up");
|
//cwLogInfo("damper: %s.", damp_down_fl ? "down" : "up");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1198,6 +1447,20 @@ void cw::midi_record_play::enable_device( handle_t h, unsigned devIdx, bool enab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::midi_record_play::send_midi_msg( handle_t h, unsigned devIdx, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||||
|
{
|
||||||
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
if( devIdx >= p->midiDevN )
|
||||||
|
return cwLogError(kInvalidArgRC,"The MIDI record-play device index '%i' is invalid.",devIdx );
|
||||||
|
|
||||||
|
if( p->midiDevA[devIdx].enableFl )
|
||||||
|
io::midiDeviceSend( p->ioH, p->midiDevA[devIdx].midiOutDevIdx, p->midiDevA[devIdx].midiOutPortIdx, status + ch, d0, d1 );
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void cw::midi_record_play::half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs )
|
void cw::midi_record_play::half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs )
|
||||||
{
|
{
|
||||||
midi_record_play_t* p = _handleToPtr(h);
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
@ -1216,6 +1479,12 @@ cw::rc_t cw::midi_record_play::am_to_midi_file( const char* am_filename, const c
|
|||||||
unsigned msgArrayCnt = 0;
|
unsigned msgArrayCnt = 0;
|
||||||
am_midi_msg_t* msgArray = nullptr;
|
am_midi_msg_t* msgArray = nullptr;
|
||||||
|
|
||||||
|
if(!filesys::isFile(am_filename))
|
||||||
|
{
|
||||||
|
cwLogError(kOpenFailRC,"The AM file '%s' does not exist.",am_filename);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
if((rc = _am_file_read( am_filename, msgArrayCnt, msgArray )) != kOkRC )
|
if((rc = _am_file_read( am_filename, msgArrayCnt, msgArray )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Unable to read AM file '%s'.", cwStringNullGuard(am_filename));
|
rc = cwLogError(rc,"Unable to read AM file '%s'.", cwStringNullGuard(am_filename));
|
||||||
@ -1241,12 +1510,21 @@ cw::rc_t cw::midi_record_play::am_to_midi_dir( const char* inDir )
|
|||||||
filesys::dirEntry_t* dirEntryArray = nullptr;
|
filesys::dirEntry_t* dirEntryArray = nullptr;
|
||||||
unsigned dirEntryCnt = 0;
|
unsigned dirEntryCnt = 0;
|
||||||
|
|
||||||
if(( dirEntryArray = dirEntries( inDir, filesys::kDirFsFl, &dirEntryCnt )) == nullptr )
|
if(( dirEntryArray = filesys::dirEntries( inDir, filesys::kDirFsFl | filesys::kFullPathFsFl, &dirEntryCnt )) == nullptr )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
for(unsigned i=0; i<dirEntryCnt; ++i)
|
for(unsigned i=0; i<dirEntryCnt and rc==kOkRC; ++i)
|
||||||
{
|
{
|
||||||
printf("0x%x %s\n", dirEntryArray[i].flags, dirEntryArray[i].name);
|
char* am_fn = filesys::makeFn( dirEntryArray[i].name, "midi", "am", NULL);
|
||||||
|
char* midi_fn = filesys::makeFn( dirEntryArray[i].name, "midi", "mid", NULL);
|
||||||
|
|
||||||
|
cwLogInfo("0x%x AM:%s MIDI:%s", dirEntryArray[i].flags, dirEntryArray[i].name, midi_fn);
|
||||||
|
|
||||||
|
rc = am_to_midi_file( am_fn, midi_fn );
|
||||||
|
|
||||||
|
mem::release(am_fn);
|
||||||
|
mem::release(midi_fn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
@ -1284,3 +1562,9 @@ cw::rc_t cw::midi_record_play::am_to_midi_file( const object_t* cfg )
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cw::midi_record_play::report( handle_t h )
|
||||||
|
{
|
||||||
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
|
_report_midi(p);
|
||||||
|
}
|
||||||
|
@ -19,8 +19,13 @@ namespace cw
|
|||||||
uint8_t d1;
|
uint8_t d1;
|
||||||
} midi_msg_t;
|
} midi_msg_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kMidiEventActionId,
|
||||||
|
kPlayerStoppedActionId
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*event_callback_t)( void* arg, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 );
|
|
||||||
|
typedef void (*event_callback_t)( void* arg, unsigned actionId, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 );
|
||||||
|
|
||||||
|
|
||||||
rc_t create( handle_t& hRef, io::handle_t ioH, const object_t& cfg, event_callback_t cb=nullptr, void* cb_arg=nullptr );
|
rc_t create( handle_t& hRef, io::handle_t ioH, const object_t& cfg, event_callback_t cb=nullptr, void* cb_arg=nullptr );
|
||||||
@ -36,6 +41,9 @@ namespace cw
|
|||||||
rc_t set_record_state( handle_t h, bool record_fl );
|
rc_t set_record_state( handle_t h, bool record_fl );
|
||||||
bool record_state( handle_t h );
|
bool record_state( handle_t h );
|
||||||
|
|
||||||
|
rc_t set_mute_state( handle_t h, bool record_fl );
|
||||||
|
bool mute_state( handle_t h );
|
||||||
|
|
||||||
rc_t set_thru_state( handle_t h, bool record_thru );
|
rc_t set_thru_state( handle_t h, bool record_thru );
|
||||||
bool thru_state( handle_t h );
|
bool thru_state( handle_t h );
|
||||||
|
|
||||||
@ -58,6 +66,7 @@ namespace cw
|
|||||||
unsigned device_count( handle_t h );
|
unsigned device_count( handle_t h );
|
||||||
bool is_device_enabled( handle_t h, unsigned devIdx );
|
bool is_device_enabled( handle_t h, unsigned devIdx );
|
||||||
void enable_device( handle_t h, unsigned devIdx, bool enableFl );
|
void enable_device( handle_t h, unsigned devIdx, bool enableFl );
|
||||||
|
rc_t send_midi_msg( handle_t h, unsigned devIdx, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 );
|
||||||
|
|
||||||
void half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs );
|
void half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs );
|
||||||
|
|
||||||
@ -65,6 +74,8 @@ namespace cw
|
|||||||
rc_t am_to_midi_file( const char* am_filename, const char* midi_filename );
|
rc_t am_to_midi_file( const char* am_filename, const char* midi_filename );
|
||||||
rc_t am_to_midi_dir( const char* inDir );
|
rc_t am_to_midi_dir( const char* inDir );
|
||||||
rc_t am_to_midi_file( const object_t* cfg );
|
rc_t am_to_midi_file( const object_t* cfg );
|
||||||
|
|
||||||
|
void report( handle_t h );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
134
cwIoMinTest.cpp
Normal file
134
cwIoMinTest.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwKeyboard.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwObject.h"
|
||||||
|
#include "cwTime.h"
|
||||||
|
#include "cwMidiDecls.h"
|
||||||
|
#include "cwMidi.h"
|
||||||
|
#include "cwUiDecls.h"
|
||||||
|
#include "cwIo.h"
|
||||||
|
#include "cwIoMinTest.h"
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kThread0Id,
|
||||||
|
kThread1Id
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct app_str
|
||||||
|
{
|
||||||
|
unsigned n0;
|
||||||
|
unsigned n1;
|
||||||
|
io::handle_t ioH;
|
||||||
|
} app_t;
|
||||||
|
|
||||||
|
void minTestThreadCb( app_t* app, const io::thread_msg_t* tm )
|
||||||
|
{
|
||||||
|
switch( tm->id )
|
||||||
|
{
|
||||||
|
case kThread0Id:
|
||||||
|
app->n0 += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kThread1Id:
|
||||||
|
app->n1 += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main application callback
|
||||||
|
rc_t minTestCb( void* arg, const io::msg_t* m )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
app_t* app = reinterpret_cast<app_t*>(arg);
|
||||||
|
|
||||||
|
switch( m->tid )
|
||||||
|
{
|
||||||
|
case io::kThreadTId:
|
||||||
|
minTestThreadCb( app, m->u.thread );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kSerialTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kMidiTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kAudioTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kAudioMeterTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kSockTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kWebSockTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case io::kUiTId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::min_test( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
app_t app = {};
|
||||||
|
|
||||||
|
|
||||||
|
// create the io framework instance
|
||||||
|
if((rc = create(app.ioH,cfg,minTestCb,&app)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if((rc = threadCreate( app.ioH, kThread0Id, &app )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Thread 0 create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = threadCreate( app.ioH, kThread1Id, &app )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Thread 1 create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the io framework instance
|
||||||
|
if((rc = start(app.ioH)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Test app start failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("<enter> to quit.\n");
|
||||||
|
|
||||||
|
// execuite the io framework
|
||||||
|
while( !isShuttingDown(app.ioH))
|
||||||
|
{
|
||||||
|
exec(app.ioH);
|
||||||
|
sleepMs(500);
|
||||||
|
|
||||||
|
if( isKeyWaiting() )
|
||||||
|
break;
|
||||||
|
|
||||||
|
printf("%i %i\n",app.n0,app.n1);
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
destroy(app.ioH);
|
||||||
|
printf("ioMinTest Done.\n");
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
11
cwIoMinTest.h
Normal file
11
cwIoMinTest.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef cwIoMinTest_H
|
||||||
|
#define cwIoMinTest_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
rc_t min_test( const object_t* cfg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -40,6 +40,7 @@ namespace cw
|
|||||||
|
|
||||||
kStartBtnId,
|
kStartBtnId,
|
||||||
kStopBtnId,
|
kStopBtnId,
|
||||||
|
kLiveCheckId,
|
||||||
|
|
||||||
kPrintMidiCheckId,
|
kPrintMidiCheckId,
|
||||||
kPianoMidiCheckId,
|
kPianoMidiCheckId,
|
||||||
@ -69,13 +70,15 @@ namespace cw
|
|||||||
|
|
||||||
kStatusId,
|
kStatusId,
|
||||||
|
|
||||||
|
/*
|
||||||
kHalfPedalPedalVel,
|
kHalfPedalPedalVel,
|
||||||
kHalfPedalDelayMs,
|
kHalfPedalDelayMs,
|
||||||
kHalfPedalPitch,
|
kHalfPedalPitch,
|
||||||
kHalfPedalVel,
|
kHalfPedalVel,
|
||||||
kHalfPedalDurMs,
|
kHalfPedalDurMs,
|
||||||
kHalfPedalDnDelayMs,
|
kHalfPedalDnDelayMs,
|
||||||
|
*/
|
||||||
|
|
||||||
kLogId,
|
kLogId,
|
||||||
|
|
||||||
kFragListId,
|
kFragListId,
|
||||||
@ -85,6 +88,7 @@ namespace cw
|
|||||||
|
|
||||||
kFragPresetRowId,
|
kFragPresetRowId,
|
||||||
kFragPresetSelId,
|
kFragPresetSelId,
|
||||||
|
kFragPresetSeqSelId,
|
||||||
kFragPresetOrderId,
|
kFragPresetOrderId,
|
||||||
|
|
||||||
kFragInGainId,
|
kFragInGainId,
|
||||||
@ -94,14 +98,16 @@ namespace cw
|
|||||||
kFragBegPlayLocId,
|
kFragBegPlayLocId,
|
||||||
kFragEndPlayLocId,
|
kFragEndPlayLocId,
|
||||||
kFragPlayBtnId,
|
kFragPlayBtnId,
|
||||||
|
kFragPlaySeqBtnId,
|
||||||
|
kFragPlayAllBtnId,
|
||||||
kFragNoteId
|
kFragNoteId
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kPiano_MRP_DevIdx = 0,
|
kPiano_MRP_DevIdx = 1,
|
||||||
kSampler_MRP_DevIdx = 1
|
kSampler_MRP_DevIdx = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -121,6 +127,7 @@ namespace cw
|
|||||||
|
|
||||||
{ kPanelDivId, kStartBtnId, "startBtnId" },
|
{ kPanelDivId, kStartBtnId, "startBtnId" },
|
||||||
{ kPanelDivId, kStopBtnId, "stopBtnId" },
|
{ kPanelDivId, kStopBtnId, "stopBtnId" },
|
||||||
|
{ kPanelDivId, kLiveCheckId, "liveCheckId" },
|
||||||
|
|
||||||
{ kPanelDivId, kPrintMidiCheckId, "printMidiCheckId" },
|
{ kPanelDivId, kPrintMidiCheckId, "printMidiCheckId" },
|
||||||
{ kPanelDivId, kPianoMidiCheckId, "pianoMidiCheckId" },
|
{ kPanelDivId, kPianoMidiCheckId, "pianoMidiCheckId" },
|
||||||
@ -148,13 +155,14 @@ namespace cw
|
|||||||
{ kPanelDivId, kInsertBtnId, "insertBtnId" },
|
{ kPanelDivId, kInsertBtnId, "insertBtnId" },
|
||||||
{ kPanelDivId, kDeleteBtnId, "deleteBtnId" },
|
{ kPanelDivId, kDeleteBtnId, "deleteBtnId" },
|
||||||
|
|
||||||
|
/*
|
||||||
{ kPanelDivId, kHalfPedalPedalVel, "halfPedalPedalVelId" },
|
{ kPanelDivId, kHalfPedalPedalVel, "halfPedalPedalVelId" },
|
||||||
{ kPanelDivId, kHalfPedalDelayMs, "halfPedalDelayMsId" },
|
{ kPanelDivId, kHalfPedalDelayMs, "halfPedalDelayMsId" },
|
||||||
{ kPanelDivId, kHalfPedalPitch, "halfPedalPitchId" },
|
{ kPanelDivId, kHalfPedalPitch, "halfPedalPitchId" },
|
||||||
{ kPanelDivId, kHalfPedalVel, "halfPedalVelId" },
|
{ kPanelDivId, kHalfPedalVel, "halfPedalVelId" },
|
||||||
{ kPanelDivId, kHalfPedalDurMs, "halfPedalDurMsId" },
|
{ kPanelDivId, kHalfPedalDurMs, "halfPedalDurMsId" },
|
||||||
{ kPanelDivId, kHalfPedalDnDelayMs, "halfPedalDnDelayMsId" },
|
{ kPanelDivId, kHalfPedalDnDelayMs, "halfPedalDnDelayMsId" },
|
||||||
|
*/
|
||||||
|
|
||||||
{ kPanelDivId, kStatusId, "statusId" },
|
{ kPanelDivId, kStatusId, "statusId" },
|
||||||
{ kPanelDivId, kLogId, "logId" },
|
{ kPanelDivId, kLogId, "logId" },
|
||||||
@ -171,7 +179,9 @@ namespace cw
|
|||||||
{ kFragPanelId, kFragBegPlayLocId, "fragBegPlayLocId" },
|
{ kFragPanelId, kFragBegPlayLocId, "fragBegPlayLocId" },
|
||||||
{ kFragPanelId, kFragEndPlayLocId, "fragEndPlayLocId" },
|
{ kFragPanelId, kFragEndPlayLocId, "fragEndPlayLocId" },
|
||||||
{ kFragPanelId, kFragPlayBtnId, "fragPlayBtnId" },
|
{ kFragPanelId, kFragPlayBtnId, "fragPlayBtnId" },
|
||||||
{ kFragPanelId, kFragNoteId, "fragNoteId" },
|
{ kFragPanelId, kFragPlaySeqBtnId, "fragPlaySeqBtnId" },
|
||||||
|
{ kFragPanelId, kFragPlayAllBtnId, "fragPlayAllBtnId" },
|
||||||
|
{ kFragPanelId, kFragNoteId, "fragNoteId" },
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -201,6 +211,7 @@ namespace cw
|
|||||||
const object_t* midi_play_record_cfg;
|
const object_t* midi_play_record_cfg;
|
||||||
const object_t* frag_panel_cfg;
|
const object_t* frag_panel_cfg;
|
||||||
const object_t* presets_cfg;
|
const object_t* presets_cfg;
|
||||||
|
object_t* flow_proc_dict;
|
||||||
const object_t* flow_cfg;
|
const object_t* flow_cfg;
|
||||||
|
|
||||||
midi_record_play::handle_t mrpH;
|
midi_record_play::handle_t mrpH;
|
||||||
@ -210,15 +221,15 @@ namespace cw
|
|||||||
unsigned locMapN;
|
unsigned locMapN;
|
||||||
|
|
||||||
unsigned insertLoc; // last valid insert location id received from the GUI
|
unsigned insertLoc; // last valid insert location id received from the GUI
|
||||||
|
|
||||||
unsigned minLoc;
|
unsigned minLoc;
|
||||||
unsigned maxLoc;
|
unsigned maxLoc;
|
||||||
|
|
||||||
unsigned beg_play_loc;
|
|
||||||
unsigned end_play_loc;
|
|
||||||
|
|
||||||
time::spec_t beg_play_timestamp;
|
time::spec_t beg_play_timestamp;
|
||||||
time::spec_t end_play_timestamp;
|
time::spec_t end_play_timestamp;
|
||||||
|
|
||||||
|
unsigned beg_play_loc;
|
||||||
|
unsigned end_play_loc;
|
||||||
|
|
||||||
preset_sel::handle_t psH;
|
preset_sel::handle_t psH;
|
||||||
io_flow::handle_t ioFlowH;
|
io_flow::handle_t ioFlowH;
|
||||||
@ -236,11 +247,21 @@ namespace cw
|
|||||||
unsigned hpVel;
|
unsigned hpVel;
|
||||||
unsigned hpDurMs;
|
unsigned hpDurMs;
|
||||||
unsigned hpDnDelayMs;
|
unsigned hpDnDelayMs;
|
||||||
|
|
||||||
|
bool seqActiveFl; // true if the sequence is currently active (set by 'Play Seq' btn)
|
||||||
|
unsigned seqStartedFl; // set by the first seq idle callback
|
||||||
|
unsigned seqFragId; //
|
||||||
|
unsigned seqPresetIdx; //
|
||||||
|
|
||||||
|
bool useLiveMidiFl;
|
||||||
|
|
||||||
|
|
||||||
} app_t;
|
} app_t;
|
||||||
|
|
||||||
rc_t _parseCfg(app_t* app, const object_t* cfg, const object_t*& params_cfgRef )
|
rc_t _parseCfg(app_t* app, const object_t* cfg, const object_t*& params_cfgRef )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
const char* flow_proc_dict_fn = nullptr;
|
||||||
|
|
||||||
if((rc = cfg->getv( "params", params_cfgRef,
|
if((rc = cfg->getv( "params", params_cfgRef,
|
||||||
"flow", app->flow_cfg)) != kOkRC )
|
"flow", app->flow_cfg)) != kOkRC )
|
||||||
@ -253,11 +274,14 @@ namespace cw
|
|||||||
"record_fn", app->record_fn,
|
"record_fn", app->record_fn,
|
||||||
"record_fn_ext", app->record_fn_ext,
|
"record_fn_ext", app->record_fn_ext,
|
||||||
"score_fn", app->scoreFn,
|
"score_fn", app->scoreFn,
|
||||||
|
"flow_proc_dict_fn",flow_proc_dict_fn,
|
||||||
"midi_play_record", app->midi_play_record_cfg,
|
"midi_play_record", app->midi_play_record_cfg,
|
||||||
"frag_panel", app->frag_panel_cfg,
|
"frag_panel", app->frag_panel_cfg,
|
||||||
"presets", app->presets_cfg,
|
"presets", app->presets_cfg,
|
||||||
"crossFadeSrate", app->crossFadeSrate,
|
"crossFadeSrate", app->crossFadeSrate,
|
||||||
"crossFadeCount", app->crossFadeCnt)) != kOkRC )
|
"crossFadeCount", app->crossFadeCnt,
|
||||||
|
"beg_play_loc", app->beg_play_loc,
|
||||||
|
"end_play_loc", app->end_play_loc)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"Preset Select App configuration parse failed.");
|
rc = cwLogError(kSyntaxErrorRC,"Preset Select App configuration parse failed.");
|
||||||
}
|
}
|
||||||
@ -273,6 +297,12 @@ namespace cw
|
|||||||
rc = cwLogError(kInvalidArgRC,"The record directory path is invalid.");
|
rc = cwLogError(kInvalidArgRC,"The record directory path is invalid.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((rc = objectFromFile( flow_proc_dict_fn, app->flow_proc_dict )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The flow proc file '%s' parse failed.",app->flow_proc_dict);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
// verify that the output directory exists
|
// verify that the output directory exists
|
||||||
if((rc = filesys::isDir(app->record_dir)) != kOkRC )
|
if((rc = filesys::isDir(app->record_dir)) != kOkRC )
|
||||||
@ -321,6 +351,9 @@ namespace cw
|
|||||||
|
|
||||||
rc_t _free( app_t& app )
|
rc_t _free( app_t& app )
|
||||||
{
|
{
|
||||||
|
if( app.flow_proc_dict != nullptr )
|
||||||
|
app.flow_proc_dict->free();
|
||||||
|
|
||||||
mem::release((char*&)app.record_dir);
|
mem::release((char*&)app.record_dir);
|
||||||
mem::release((char*&)app.scoreFn);
|
mem::release((char*&)app.scoreFn);
|
||||||
preset_sel::destroy(app.psH);
|
preset_sel::destroy(app.psH);
|
||||||
@ -331,25 +364,35 @@ namespace cw
|
|||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _apply_preset( app_t* app, const time::spec_t& ts, unsigned loc, const preset_sel::frag_t* frag=nullptr )
|
||||||
rc_t _apply_preset( app_t* app, const time::spec_t& ts, const preset_sel::frag_t* frag=nullptr )
|
|
||||||
{
|
{
|
||||||
|
// if frag is NULL this is the beginning of a play session
|
||||||
if( frag == nullptr )
|
if( frag == nullptr )
|
||||||
preset_sel::track_timestamp( app->psH, ts, frag);
|
{
|
||||||
|
preset_sel::track_loc_reset(app->psH);
|
||||||
|
//preset_sel::track_timestamp( app->psH, ts, frag);
|
||||||
|
|
||||||
|
preset_sel::track_loc( app->psH, loc, frag);
|
||||||
|
}
|
||||||
|
|
||||||
if( frag == nullptr )
|
if( frag == nullptr )
|
||||||
cwLogInfo("No preset fragment was found for the requested timestamp.");
|
cwLogInfo("No preset fragment was found for the requested timestamp.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned preset_idx;
|
unsigned preset_idx;
|
||||||
|
|
||||||
if((preset_idx = fragment_play_preset_index(frag)) == kInvalidIdx )
|
// if the preset sequence player is active then apply the next selected seq. preset
|
||||||
|
// otherwise select the next primary preset for ths fragment
|
||||||
|
unsigned seq_idx_n = app->seqActiveFl ? app->seqPresetIdx : kInvalidIdx;
|
||||||
|
|
||||||
|
// get the preset index to play for this fragment
|
||||||
|
if((preset_idx = fragment_play_preset_index(frag,seq_idx_n)) == kInvalidIdx )
|
||||||
cwLogInfo("No preset has been assigned to the fragment at end loc. '%i'.",frag->endLoc );
|
cwLogInfo("No preset has been assigned to the fragment at end loc. '%i'.",frag->endLoc );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char* preset_label = preset_sel::preset_label(app->psH,preset_idx);
|
const char* preset_label = preset_sel::preset_label(app->psH,preset_idx);
|
||||||
|
|
||||||
cwLogInfo("Apply preset: '%s'.", preset_idx==kInvalidIdx ? "<invalid>" : preset_label);
|
_set_status(app,"Apply preset: '%s'.", preset_idx==kInvalidIdx ? "<invalid>" : preset_label);
|
||||||
|
|
||||||
if( preset_label != nullptr )
|
if( preset_label != nullptr )
|
||||||
{
|
{
|
||||||
@ -395,40 +438,99 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _midi_play_callback( void* arg, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
void _midi_play_callback( void* arg, unsigned actionId, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||||
{
|
{
|
||||||
app_t* app = (app_t*)arg;
|
app_t* app = (app_t*)arg;
|
||||||
|
switch( actionId )
|
||||||
if( app->printMidiFl )
|
{
|
||||||
{
|
case midi_record_play::kPlayerStoppedActionId:
|
||||||
const unsigned buf_byte_cnt = 256;
|
app->seqStartedFl=false;
|
||||||
char buf[ buf_byte_cnt ];
|
_set_status(app,"Done");
|
||||||
|
break;
|
||||||
|
|
||||||
// if this event is not in the score
|
case midi_record_play::kMidiEventActionId:
|
||||||
if( id == kInvalidId )
|
|
||||||
{
|
|
||||||
// TODO: print this out in the same format as event_to_string()
|
|
||||||
snprintf(buf,buf_byte_cnt,"ch:%i status:0x%02x d0:%i d1:%i",ch,status,d0,d1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
score::event_to_string( app->scoreH, id, buf, buf_byte_cnt );
|
|
||||||
printf("%s\n",buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( midi_record_play::is_started(app->mrpH) )
|
|
||||||
{
|
{
|
||||||
const preset_sel::frag_t* f = nullptr;
|
if( app->printMidiFl )
|
||||||
if( preset_sel::track_timestamp( app->psH, timestamp, f ) )
|
{
|
||||||
{
|
const unsigned buf_byte_cnt = 256;
|
||||||
//printf("NEW FRAG: id:%i loc:%i\n", f->fragId, f->endLoc );
|
char buf[ buf_byte_cnt ];
|
||||||
_apply_preset( app, timestamp, f );
|
|
||||||
|
// if this event is not in the score
|
||||||
if( f != nullptr )
|
if( id == kInvalidId )
|
||||||
_do_select_frag( app, f->guiUuId );
|
{
|
||||||
|
// TODO: print this out in the same format as event_to_string()
|
||||||
|
snprintf(buf,buf_byte_cnt,"ch:%i status:0x%02x d0:%i d1:%i",ch,status,d0,d1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
score::event_to_string( app->scoreH, id, buf, buf_byte_cnt );
|
||||||
|
printf("%s\n",buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( midi_record_play::is_started(app->mrpH) )
|
||||||
|
{
|
||||||
|
const preset_sel::frag_t* f = nullptr;
|
||||||
|
//if( preset_sel::track_timestamp( app->psH, timestamp, f ) )
|
||||||
|
|
||||||
|
|
||||||
|
// ZERO SHOULD BE A VALID LOC VALUE - MAKE -1 THE INVALID LOC VALUE
|
||||||
|
|
||||||
|
if( loc != 0 )
|
||||||
|
{
|
||||||
|
if( preset_sel::track_loc( app->psH, loc, f ) )
|
||||||
|
{
|
||||||
|
//printf("NEW FRAG: id:%i loc:%i\n", f->fragId, f->endLoc );
|
||||||
|
_apply_preset( app, timestamp, loc, f );
|
||||||
|
|
||||||
|
if( f != nullptr )
|
||||||
|
_do_select_frag( app, f->guiUuId );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _on_live_midi( app_t* app, const io::msg_t& msg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( msg.u.midi != nullptr )
|
||||||
|
{
|
||||||
|
|
||||||
|
const io::midi_msg_t& m = *msg.u.midi;
|
||||||
|
const midi::packet_t* pkt = m.pkt;
|
||||||
|
// for each midi msg
|
||||||
|
for(unsigned j=0; j<pkt->msgCnt; ++j)
|
||||||
|
{
|
||||||
|
// if this is a sys-ex msg
|
||||||
|
if( pkt->msgArray == NULL )
|
||||||
|
{
|
||||||
|
cwLogError(kNotImplementedRC,"Sys-ex recording not implemented.");
|
||||||
|
}
|
||||||
|
else // this is a triple
|
||||||
|
{
|
||||||
|
midi::msg_t* mm = pkt->msgArray + j;
|
||||||
|
time::spec_t timestamp;
|
||||||
|
unsigned id = kInvalidId;
|
||||||
|
unsigned loc = app->beg_play_loc;
|
||||||
|
|
||||||
|
time::get(timestamp);
|
||||||
|
|
||||||
|
if( midi::isChStatus(mm->status) )
|
||||||
|
{
|
||||||
|
if(midi_record_play::send_midi_msg( app->mrpH, kSampler_MRP_DevIdx, mm->status & 0x0f, mm->status & 0xf0, mm->d0, mm->d1 ) == kOkRC )
|
||||||
|
_midi_play_callback( app, midi_record_play::kMidiEventActionId, id, timestamp, loc, mm->status & 0x0f, mm->status & 0xf0, mm->d0, mm->d1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Find the closest locMap equal to or after 'loc'
|
// Find the closest locMap equal to or after 'loc'
|
||||||
loc_map_t* _find_loc( app_t* app, unsigned loc )
|
loc_map_t* _find_loc( app_t* app, unsigned loc )
|
||||||
{
|
{
|
||||||
@ -468,6 +570,7 @@ namespace cw
|
|||||||
bool rewindFl = true;
|
bool rewindFl = true;
|
||||||
loc_map_t* begMap = nullptr;
|
loc_map_t* begMap = nullptr;
|
||||||
loc_map_t* endMap = nullptr;
|
loc_map_t* endMap = nullptr;
|
||||||
|
unsigned cur_loc = 0;
|
||||||
|
|
||||||
// if the player is already playing then stop it
|
// if the player is already playing then stop it
|
||||||
if( midi_record_play::is_started(app->mrpH) )
|
if( midi_record_play::is_started(app->mrpH) )
|
||||||
@ -476,7 +579,7 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
midi_record_play::half_pedal_params( app->mrpH, app->hpDelayMs, app->hpPitch, app->hpVel, app->hpPedalVel, app->hpDurMs, app->hpDnDelayMs );
|
//midi_record_play::half_pedal_params( app->mrpH, app->hpDelayMs, app->hpPitch, app->hpVel, app->hpPedalVel, app->hpDurMs, app->hpDnDelayMs );
|
||||||
|
|
||||||
|
|
||||||
if((begMap = _find_loc(app,begLoc)) == nullptr )
|
if((begMap = _find_loc(app,begLoc)) == nullptr )
|
||||||
@ -495,7 +598,7 @@ namespace cw
|
|||||||
app->end_play_timestamp = endMap->timestamp;
|
app->end_play_timestamp = endMap->timestamp;
|
||||||
|
|
||||||
|
|
||||||
if( !time::isZero(app->beg_play_timestamp) )
|
if( !time::isZero(app->beg_play_timestamp) && !app->useLiveMidiFl )
|
||||||
{
|
{
|
||||||
// seek the player to the requested loc
|
// seek the player to the requested loc
|
||||||
if((rc = midi_record_play::seek( app->mrpH, app->beg_play_timestamp )) != kOkRC )
|
if((rc = midi_record_play::seek( app->mrpH, app->beg_play_timestamp )) != kOkRC )
|
||||||
@ -507,22 +610,27 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply the preset which is active at the start time
|
// apply the preset which is active at the start time
|
||||||
if((rc = _apply_preset( app, app->beg_play_timestamp )) != kOkRC )
|
if((rc = _apply_preset( app, app->beg_play_timestamp, begMap->loc )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Preset application failed prior to MIDI start.");
|
rc = cwLogError(rc,"Preset application failed prior to MIDI start.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the MIDI playback
|
// start the MIDI playback
|
||||||
if((rc = midi_record_play::start(app->mrpH,rewindFl,&app->end_play_timestamp)) != kOkRC )
|
if( !app->useLiveMidiFl )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"MIDI start failed.");
|
if((rc = midi_record_play::start(app->mrpH,rewindFl,&app->end_play_timestamp)) != kOkRC )
|
||||||
goto errLabel;
|
{
|
||||||
|
rc = cwLogError(rc,"MIDI start failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((cur_loc = midi_record_play::event_loc(app->mrpH)) > 0 )
|
||||||
|
{
|
||||||
|
io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), cur_loc );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), midi_record_play::event_loc(app->mrpH) );
|
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -552,6 +660,45 @@ namespace cw
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _do_seq_play_fragment( app_t* app, unsigned fragId )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( app->seqActiveFl )
|
||||||
|
{
|
||||||
|
app->seqActiveFl = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app->seqFragId = fragId;
|
||||||
|
app->seqPresetIdx = 0;
|
||||||
|
app->seqStartedFl = true;
|
||||||
|
app->seqActiveFl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that if the MIDI player is already playing
|
||||||
|
// calling '_do_play_fragment()' here will stop the player
|
||||||
|
_do_play_fragment( app, app->seqFragId );
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _do_seq_exec( app_t* app )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// if the seq player is active but currently stopped
|
||||||
|
if( app->seqActiveFl && app->seqStartedFl==false)
|
||||||
|
{
|
||||||
|
app->seqPresetIdx += 1;
|
||||||
|
app->seqStartedFl = app->seqPresetIdx < preset_sel::fragment_seq_count( app->psH, app->seqFragId );
|
||||||
|
app->seqActiveFl = app->seqStartedFl;
|
||||||
|
|
||||||
|
if( app->seqStartedFl )
|
||||||
|
_do_play_fragment( app, app->seqFragId );
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void _update_event_ui( app_t* app )
|
void _update_event_ui( app_t* app )
|
||||||
{
|
{
|
||||||
@ -637,8 +784,9 @@ namespace cw
|
|||||||
// Update each fragment preset control UI by getting it's current value from the fragment data record
|
// Update each fragment preset control UI by getting it's current value from the fragment data record
|
||||||
for(unsigned preset_idx=0; preset_idx<preset_sel::preset_count(app->psH); ++preset_idx)
|
for(unsigned preset_idx=0; preset_idx<preset_sel::preset_count(app->psH); ++preset_idx)
|
||||||
{
|
{
|
||||||
_update_frag_ui( app, fragId, preset_sel::kPresetSelectVarId, preset_idx, fragPresetRowUuId, kFragPresetSelId, preset_idx, bValue );
|
_update_frag_ui( app, fragId, preset_sel::kPresetSelectVarId, preset_idx, fragPresetRowUuId, kFragPresetSelId, preset_idx, bValue );
|
||||||
_update_frag_ui( app, fragId, preset_sel::kPresetOrderVarId, preset_idx, fragPresetRowUuId, kFragPresetOrderId, preset_idx, uValue );
|
_update_frag_ui( app, fragId, preset_sel::kPresetOrderVarId, preset_idx, fragPresetRowUuId, kFragPresetOrderId, preset_idx, uValue );
|
||||||
|
_update_frag_ui( app, fragId, preset_sel::kPresetSeqSelectVarId,preset_idx, fragPresetRowUuId, kFragPresetSeqSelId, preset_idx, bValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -666,7 +814,6 @@ namespace cw
|
|||||||
unsigned fragPanelUuId = kInvalidId;
|
unsigned fragPanelUuId = kInvalidId;
|
||||||
|
|
||||||
get_value( app->psH, fragId, preset_sel::kGuiUuIdVarId, kInvalidId, fragPanelUuId );
|
get_value( app->psH, fragId, preset_sel::kGuiUuIdVarId, kInvalidId, fragPanelUuId );
|
||||||
|
|
||||||
|
|
||||||
_update_frag_ui( app, fragId, preset_sel::kBegLocVarId, kInvalidId, fragPanelUuId, kFragBegLocId, uiChanId, uValue );
|
_update_frag_ui( app, fragId, preset_sel::kBegLocVarId, kInvalidId, fragPanelUuId, kFragBegLocId, uiChanId, uValue );
|
||||||
_update_frag_ui( app, fragId, preset_sel::kEndLocVarId, kInvalidId, fragPanelUuId, kFragEndLocId, uiChanId, uValue );
|
_update_frag_ui( app, fragId, preset_sel::kEndLocVarId, kInvalidId, fragPanelUuId, kFragEndLocId, uiChanId, uValue );
|
||||||
@ -705,20 +852,28 @@ namespace cw
|
|||||||
void _enable_frag_play_btn( app_t* app, ui_blob_t* blob, const char*, unsigned ){}
|
void _enable_frag_play_btn( app_t* app, ui_blob_t* blob, const char*, unsigned ){}
|
||||||
void _enable_frag_play_btn( app_t* app, ui_blob_t* blob, unsigned begPlayLoc, unsigned endPlayLoc )
|
void _enable_frag_play_btn( app_t* app, ui_blob_t* blob, unsigned begPlayLoc, unsigned endPlayLoc )
|
||||||
{
|
{
|
||||||
bool enableFl = begPlayLoc < endPlayLoc;
|
bool enableFl = begPlayLoc < endPlayLoc;
|
||||||
unsigned fragUuId = kInvalidId;
|
unsigned fragUuId = kInvalidId;
|
||||||
unsigned fragPlayBtnUuId = kInvalidId;
|
|
||||||
|
|
||||||
if((fragUuId = frag_to_gui_id( app->psH, blob->fragId )) != kInvalidId )
|
if((fragUuId = frag_to_gui_id( app->psH, blob->fragId )) != kInvalidId )
|
||||||
if((fragPlayBtnUuId = uiFindElementUuId( app->ioH, fragUuId, kFragPlayBtnId, blob->presetId )) != kInvalidId )
|
{
|
||||||
|
unsigned btnIdA[] = { kFragPlayBtnId, kFragPlaySeqBtnId, kFragPlayAllBtnId };
|
||||||
|
unsigned btnIdN = sizeof(btnIdA)/sizeof(btnIdA[0]);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<btnIdN; ++i)
|
||||||
{
|
{
|
||||||
uiSetEnable( app->ioH, fragPlayBtnUuId, enableFl );
|
unsigned btnUuId;
|
||||||
if( enableFl )
|
if((btnUuId = uiFindElementUuId( app->ioH, fragUuId, btnIdA[i], blob->presetId )) != kInvalidId )
|
||||||
_clear_status(app);
|
uiSetEnable( app->ioH, btnUuId, enableFl );
|
||||||
else
|
|
||||||
_set_status(app,"Invalid fragment play range.");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( enableFl )
|
||||||
|
_clear_status(app);
|
||||||
|
else
|
||||||
|
_set_status(app,"Invalid fragment play range.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _disable_frag_play_btn( app_t* app, unsigned fragBegEndUuId )
|
void _disable_frag_play_btn( app_t* app, unsigned fragBegEndUuId )
|
||||||
@ -755,11 +910,24 @@ namespace cw
|
|||||||
case preset_sel::kPresetSelectVarId:
|
case preset_sel::kPresetSelectVarId:
|
||||||
_update_frag_select_flags( app, blob->fragId);
|
_update_frag_select_flags( app, blob->fragId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case preset_sel::kPresetSeqSelectVarId:
|
||||||
|
_update_frag_select_flags( app, blob->fragId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case preset_sel::kPlayBtnVarId:
|
case preset_sel::kPlayBtnVarId:
|
||||||
_do_play_fragment( app, blob->fragId );
|
_do_play_fragment( app, blob->fragId );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case preset_sel::kPlaySeqBtnVarId:
|
||||||
|
_do_seq_play_fragment( app, blob->fragId );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case preset_sel::kPlaySeqAllBtnVarId:
|
||||||
|
_do_seq_play_fragment( app, blob->fragId );
|
||||||
|
break;
|
||||||
|
|
||||||
case preset_sel::kBegPlayLocVarId:
|
case preset_sel::kBegPlayLocVarId:
|
||||||
{
|
{
|
||||||
unsigned endPlayLoc;
|
unsigned endPlayLoc;
|
||||||
@ -818,9 +986,16 @@ namespace cw
|
|||||||
if((rc = io::uiCreateNumb( app->ioH, uuId, colUuId, nullEleName, kFragPresetOrderId, chanId, nullClass, nullptr, 0, presetN, 1, 0 )) != kOkRC )
|
if((rc = io::uiCreateNumb( app->ioH, uuId, colUuId, nullEleName, kFragPresetOrderId, chanId, nullClass, nullptr, 0, presetN, 1, 0 )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
// store a connection for the select control back to the fragment record
|
// store a connection for the order control back to the fragment record
|
||||||
_frag_set_ui_blob(app, uuId, fragId, preset_sel::kPresetOrderVarId, preset_idx );
|
_frag_set_ui_blob(app, uuId, fragId, preset_sel::kPresetOrderVarId, preset_idx );
|
||||||
|
|
||||||
|
// preset sequence select check
|
||||||
|
if((rc = io::uiCreateCheck( app->ioH, uuId, colUuId, nullEleName, kFragPresetSeqSelId, chanId, nullClass, nullptr )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// store a connection for the sequence select control back to the fragment record
|
||||||
|
_frag_set_ui_blob(app, uuId, fragId, preset_sel::kPresetSeqSelectVarId, preset_idx );
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
if(rc != kOkRC )
|
if(rc != kOkRC )
|
||||||
rc = cwLogError(rc,"Preset control index '%i' create failed.");
|
rc = cwLogError(rc,"Preset control index '%i' create failed.");
|
||||||
@ -870,14 +1045,16 @@ namespace cw
|
|||||||
|
|
||||||
|
|
||||||
// Attach blobs to the UI to allow convenient access back to the prese_sel data record
|
// Attach blobs to the UI to allow convenient access back to the prese_sel data record
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragInGainId, fragChanId), fragId, preset_sel::kInGainVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragInGainId, fragChanId), fragId, preset_sel::kInGainVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragOutGainId, fragChanId), fragId, preset_sel::kOutGainVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragOutGainId, fragChanId), fragId, preset_sel::kOutGainVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragWetDryGainId, fragChanId), fragId, preset_sel::kWetGainVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragWetDryGainId, fragChanId), fragId, preset_sel::kWetGainVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragFadeOutMsId, fragChanId), fragId, preset_sel::kFadeOutMsVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragFadeOutMsId, fragChanId), fragId, preset_sel::kFadeOutMsVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragBegPlayLocId, fragChanId), fragId, preset_sel::kBegPlayLocVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragBegPlayLocId, fragChanId), fragId, preset_sel::kBegPlayLocVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragEndPlayLocId, fragChanId), fragId, preset_sel::kEndPlayLocVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragEndPlayLocId, fragChanId), fragId, preset_sel::kEndPlayLocVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragPlayBtnId, fragChanId), fragId, preset_sel::kPlayBtnVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragPlayBtnId, fragChanId), fragId, preset_sel::kPlayBtnVarId, kInvalidId );
|
||||||
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragNoteId, fragChanId), fragId, preset_sel::kNoteVarId, kInvalidId );
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragPlaySeqBtnId, fragChanId), fragId, preset_sel::kPlaySeqBtnVarId, kInvalidId );
|
||||||
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragPlayAllBtnId, fragChanId), fragId, preset_sel::kPlaySeqAllBtnVarId, kInvalidId );
|
||||||
|
_frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragNoteId, fragChanId), fragId, preset_sel::kNoteVarId, kInvalidId );
|
||||||
|
|
||||||
|
|
||||||
// create each of the preset controls
|
// create each of the preset controls
|
||||||
@ -1064,8 +1241,8 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
unsigned midiEventN = 0;
|
unsigned midiEventN = 0;
|
||||||
bool firstLoadFl = !app->scoreH.isValid();
|
bool firstLoadFl = !app->scoreH.isValid();
|
||||||
unsigned minLoc = firstLoadFl ? 0 : app->minLoc;
|
//unsigned minLoc = firstLoadFl ? 0 : app->minLoc;
|
||||||
unsigned maxLoc = firstLoadFl ? 0 : app->maxLoc;
|
//unsigned maxLoc = firstLoadFl ? 0 : app->maxLoc;
|
||||||
|
|
||||||
// if the score is already loaded
|
// if the score is already loaded
|
||||||
//if( app->scoreH.isValid() )
|
//if( app->scoreH.isValid() )
|
||||||
@ -1075,26 +1252,41 @@ namespace cw
|
|||||||
_set_status(app,"Loading...");
|
_set_status(app,"Loading...");
|
||||||
|
|
||||||
|
|
||||||
// Load the piano score
|
// Load the piano score (this set's app->min/maxLoc)
|
||||||
if((rc = _load_piano_score(app,midiEventN)) != kOkRC )
|
if((rc = _load_piano_score(app,midiEventN)) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
|
/*
|
||||||
if( !firstLoadFl)
|
if( !firstLoadFl)
|
||||||
{
|
{
|
||||||
minLoc = std::max(minLoc,app->minLoc);
|
minLoc = std::max(minLoc,app->minLoc);
|
||||||
maxLoc = std::min(maxLoc,app->maxLoc);
|
maxLoc = std::min(maxLoc,app->maxLoc);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// reset the timestamp tracker
|
// reset the timestamp tracker
|
||||||
track_timestamp_reset( app->psH );
|
track_loc_reset( app->psH );
|
||||||
|
|
||||||
// set the range of the global play location controls
|
// set the range of the global play location controls
|
||||||
if( firstLoadFl )
|
if( firstLoadFl )
|
||||||
{
|
{
|
||||||
io::uiSetNumbRange( app->ioH, io::uiFindElementUuId(app->ioH, kBegPlayLocNumbId), app->minLoc, app->maxLoc, 1, 0, minLoc );
|
unsigned begPlayLocUuId = io::uiFindElementUuId(app->ioH, kBegPlayLocNumbId);
|
||||||
io::uiSetNumbRange( app->ioH, io::uiFindElementUuId(app->ioH, kEndPlayLocNumbId), app->minLoc, app->maxLoc, 1, 0, maxLoc );
|
unsigned endPlayLocUuId = io::uiFindElementUuId(app->ioH, kEndPlayLocNumbId);
|
||||||
|
|
||||||
|
unsigned end_play_loc = app->end_play_loc==0 ? app->maxLoc : app->end_play_loc;
|
||||||
|
unsigned beg_play_loc = app->minLoc <= app->beg_play_loc && app->beg_play_loc <= app->maxLoc ? app->beg_play_loc : app->minLoc;
|
||||||
|
|
||||||
|
io::uiSetNumbRange( app->ioH, begPlayLocUuId, app->minLoc, app->maxLoc, 1, 0, app->minLoc );
|
||||||
|
io::uiSetNumbRange( app->ioH, endPlayLocUuId, app->minLoc, app->maxLoc, 1, 0, app->maxLoc );
|
||||||
|
|
||||||
|
//io::uiSendValue( app->ioH, begPlayLocUuId, app->minLoc);
|
||||||
|
//io::uiSendValue( app->ioH, endPlayLocUuId, app->maxLoc);
|
||||||
|
|
||||||
|
|
||||||
|
io::uiSendValue( app->ioH, begPlayLocUuId, beg_play_loc);
|
||||||
|
io::uiSendValue( app->ioH, endPlayLocUuId, end_play_loc);
|
||||||
|
|
||||||
|
|
||||||
// enable the 'End Loc' number box since the score is loaded
|
// enable the 'End Loc' number box since the score is loaded
|
||||||
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kInsertLocId ), true );
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kInsertLocId ), true );
|
||||||
}
|
}
|
||||||
@ -1105,6 +1297,7 @@ namespace cw
|
|||||||
// enable the start/stop buttons
|
// enable the start/stop buttons
|
||||||
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStartBtnId ), true );
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStartBtnId ), true );
|
||||||
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStopBtnId ), true );
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStopBtnId ), true );
|
||||||
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kLiveCheckId ), true );
|
||||||
|
|
||||||
// restore the fragment records
|
// restore the fragment records
|
||||||
if( firstLoadFl )
|
if( firstLoadFl )
|
||||||
@ -1319,6 +1512,7 @@ namespace cw
|
|||||||
if( mrp_dev_idx <= midi_record_play::device_count(app->mrpH) )
|
if( mrp_dev_idx <= midi_record_play::device_count(app->mrpH) )
|
||||||
{
|
{
|
||||||
bool enableFl = midi_record_play::is_device_enabled(app->mrpH, mrp_dev_idx );
|
bool enableFl = midi_record_play::is_device_enabled(app->mrpH, mrp_dev_idx );
|
||||||
|
|
||||||
io::uiSendValue( app->ioH, uuId, enableFl );
|
io::uiSendValue( app->ioH, uuId, enableFl );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1357,6 +1551,7 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
rc_t _on_ui_half_pedal_value( app_t* app, unsigned appId, unsigned uuId, unsigned value )
|
rc_t _on_ui_half_pedal_value( app_t* app, unsigned appId, unsigned uuId, unsigned value )
|
||||||
{
|
{
|
||||||
switch( appId )
|
switch( appId )
|
||||||
@ -1391,7 +1586,7 @@ namespace cw
|
|||||||
}
|
}
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _on_echo_half_pedal( app_t* app, unsigned appId, unsigned uuId )
|
rc_t _on_echo_half_pedal( app_t* app, unsigned appId, unsigned uuId )
|
||||||
{
|
{
|
||||||
switch( appId )
|
switch( appId )
|
||||||
@ -1426,7 +1621,7 @@ namespace cw
|
|||||||
}
|
}
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
rc_t _onUiInit(app_t* app, const io::ui_msg_t& m )
|
rc_t _onUiInit(app_t* app, const io::ui_msg_t& m )
|
||||||
{
|
{
|
||||||
@ -1437,13 +1632,14 @@ namespace cw
|
|||||||
// disable start and stop buttons until a score is loaded
|
// disable start and stop buttons until a score is loaded
|
||||||
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStartBtnId ), false );
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStartBtnId ), false );
|
||||||
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStopBtnId ), false );
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStopBtnId ), false );
|
||||||
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kLiveCheckId ), false );
|
||||||
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kSaveBtnId ), false );
|
io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kSaveBtnId ), false );
|
||||||
|
|
||||||
const preset_sel::frag_t* f = preset_sel::get_fragment_base( app->psH );
|
const preset_sel::frag_t* f = preset_sel::get_fragment_base( app->psH );
|
||||||
for(; f!=nullptr; f=f->link)
|
for(; f!=nullptr; f=f->link)
|
||||||
_update_frag_ui( app, f->fragId );
|
_update_frag_ui( app, f->fragId );
|
||||||
|
|
||||||
_do_load(app);
|
//_do_load(app);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1495,6 +1691,10 @@ namespace cw
|
|||||||
_do_stop_play(app);
|
_do_stop_play(app);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kLiveCheckId:
|
||||||
|
app->useLiveMidiFl = m.value->u.b;
|
||||||
|
break;
|
||||||
|
|
||||||
case kPrintMidiCheckId:
|
case kPrintMidiCheckId:
|
||||||
app->printMidiFl = m.value->u.b;
|
app->printMidiFl = m.value->u.b;
|
||||||
break;
|
break;
|
||||||
@ -1543,6 +1743,7 @@ namespace cw
|
|||||||
_on_ui_delete_btn(app);
|
_on_ui_delete_btn(app);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
case kHalfPedalPedalVel:
|
case kHalfPedalPedalVel:
|
||||||
case kHalfPedalDelayMs:
|
case kHalfPedalDelayMs:
|
||||||
case kHalfPedalPitch:
|
case kHalfPedalPitch:
|
||||||
@ -1551,6 +1752,7 @@ namespace cw
|
|||||||
case kHalfPedalDnDelayMs:
|
case kHalfPedalDnDelayMs:
|
||||||
_on_ui_half_pedal_value( app, m.appId, m.uuId, m.value->u.u );
|
_on_ui_half_pedal_value( app, m.appId, m.uuId, m.value->u.u );
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
case kFragInGainId:
|
case kFragInGainId:
|
||||||
_on_ui_frag_value( app, m.uuId, m.value->u.d);
|
_on_ui_frag_value( app, m.uuId, m.value->u.d);
|
||||||
@ -1580,7 +1782,15 @@ namespace cw
|
|||||||
case kFragPlayBtnId:
|
case kFragPlayBtnId:
|
||||||
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kFragPlaySeqBtnId:
|
||||||
|
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kFragPlayAllBtnId:
|
||||||
|
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
||||||
|
break;
|
||||||
|
|
||||||
case kFragNoteId:
|
case kFragNoteId:
|
||||||
_on_ui_frag_value( app, m.uuId, m.value->u.s );
|
_on_ui_frag_value( app, m.uuId, m.value->u.s );
|
||||||
break;
|
break;
|
||||||
@ -1592,6 +1802,11 @@ namespace cw
|
|||||||
case kFragPresetSelId:
|
case kFragPresetSelId:
|
||||||
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kFragPresetSeqSelId:
|
||||||
|
_on_ui_frag_value( app, m.uuId, m.value->u.b );
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -1644,7 +1859,7 @@ namespace cw
|
|||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _onUiEcho(app_t* app, const io::ui_msg_t& m )
|
rc_t _onUiEcho(app_t* app, const io::ui_msg_t& m )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -1677,6 +1892,7 @@ namespace cw
|
|||||||
_on_echo_master_value( app, preset_sel::kMasterSyncDelayMsVarId, m.uuId );
|
_on_echo_master_value( app, preset_sel::kMasterSyncDelayMsVarId, m.uuId );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
case kHalfPedalPedalVel:
|
case kHalfPedalPedalVel:
|
||||||
case kHalfPedalDelayMs:
|
case kHalfPedalDelayMs:
|
||||||
case kHalfPedalPitch:
|
case kHalfPedalPitch:
|
||||||
@ -1685,7 +1901,7 @@ namespace cw
|
|||||||
case kHalfPedalDnDelayMs:
|
case kHalfPedalDnDelayMs:
|
||||||
_on_echo_half_pedal( app, m.appId, m.uuId );
|
_on_echo_half_pedal( app, m.appId, m.uuId );
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -1730,6 +1946,7 @@ namespace cw
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ui::kIdleOpId:
|
case ui::kIdleOpId:
|
||||||
|
_do_seq_exec( app );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ui::kInvalidOpId:
|
case ui::kInvalidOpId:
|
||||||
@ -1749,11 +1966,18 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
app_t* app = reinterpret_cast<app_t*>(arg);
|
app_t* app = reinterpret_cast<app_t*>(arg);
|
||||||
|
|
||||||
if( app->mrpH.isValid() )
|
if( app->mrpH.isValid() && !app->useLiveMidiFl )
|
||||||
{
|
{
|
||||||
midi_record_play::exec( app->mrpH, *m );
|
midi_record_play::exec( app->mrpH, *m );
|
||||||
if( midi_record_play::is_started(app->mrpH) )
|
if( midi_record_play::is_started(app->mrpH) )
|
||||||
io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), midi_record_play::event_loc(app->mrpH) );
|
{
|
||||||
|
unsigned cur_loc = midi_record_play::event_loc(app->mrpH);
|
||||||
|
if( cur_loc > 0 )
|
||||||
|
{
|
||||||
|
io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), cur_loc );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( app->ioFlowH.isValid() )
|
if( app->ioFlowH.isValid() )
|
||||||
@ -1771,6 +1995,8 @@ namespace cw
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case io::kMidiTId:
|
case io::kMidiTId:
|
||||||
|
if( app->useLiveMidiFl && app->mrpH.isValid() )
|
||||||
|
_on_live_midi( app, *m );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case io::kAudioTId:
|
case io::kAudioTId:
|
||||||
@ -1802,7 +2028,7 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_proc_dict )
|
cw::rc_t cw::preset_sel_app::main( const object_t* cfg )
|
||||||
{
|
{
|
||||||
|
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
@ -1837,7 +2063,7 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the IO Flow controller
|
// create the IO Flow controller
|
||||||
if(app.flow_cfg==nullptr || flow_proc_dict==nullptr || (rc = io_flow::create(app.ioFlowH,app.ioH,app.crossFadeSrate,app.crossFadeCnt,*flow_proc_dict,*app.flow_cfg)) != kOkRC )
|
if(app.flow_cfg==nullptr || app.flow_proc_dict==nullptr || (rc = io_flow::create(app.ioFlowH,app.ioH,app.crossFadeSrate,app.crossFadeCnt,*app.flow_proc_dict,*app.flow_cfg)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"The IO Flow controller create failed.");
|
rc = cwLogError(rc,"The IO Flow controller create failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -1852,9 +2078,9 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_pro
|
|||||||
|
|
||||||
|
|
||||||
// execute the io framework
|
// execute the io framework
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !io::isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
exec(app.ioH);
|
io::exec(app.ioH);
|
||||||
sleepMs(50);
|
sleepMs(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
namespace preset_sel_app
|
namespace preset_sel_app
|
||||||
{
|
{
|
||||||
rc_t main( const object_t* cfg, const object_t* flow_proc_dict );
|
rc_t main( const object_t* cfg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
304
cwKeyboard.cpp
Normal file
304
cwKeyboard.cpp
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "cwKeyboard.h"
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
struct termios new_settings;
|
||||||
|
struct termios stored_settings;
|
||||||
|
|
||||||
|
void set_keypress(void)
|
||||||
|
{
|
||||||
|
struct termios new_settings;
|
||||||
|
|
||||||
|
tcgetattr(0,&stored_settings);
|
||||||
|
new_settings = stored_settings;
|
||||||
|
new_settings.c_lflag &= (~ICANON);
|
||||||
|
new_settings.c_lflag &= (~ECHO);
|
||||||
|
new_settings.c_cc[VTIME] = 0;
|
||||||
|
|
||||||
|
//int i;
|
||||||
|
//for(i=0; i<NCCS; ++i)
|
||||||
|
// printf("%i ",new_settings.c_cc[i]);
|
||||||
|
//printf("\n");
|
||||||
|
|
||||||
|
|
||||||
|
tcgetattr(0,&stored_settings);
|
||||||
|
|
||||||
|
new_settings.c_cc[VMIN] = 1;
|
||||||
|
tcsetattr(0,TCSANOW,&new_settings);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_keypress(void)
|
||||||
|
{
|
||||||
|
tcsetattr(0,TCSANOW,&stored_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CM_KB_TBL_CNT (10)
|
||||||
|
|
||||||
|
unsigned _cmKbTbl[][CM_KB_TBL_CNT] =
|
||||||
|
{
|
||||||
|
|
||||||
|
// alt ctl code
|
||||||
|
{ 3, 27, 91, 68, 0, 0, 0, 0, 0, kLeftArrowKId },
|
||||||
|
{ 3, 27, 91, 67, 0, 0, 0, 0, 0, kRightArrowKId },
|
||||||
|
{ 3, 27, 91, 65, 0, 0, 0, 0, 0, kUpArrowKId },
|
||||||
|
{ 3, 27, 91, 66, 0, 0, 0, 0, 0, kDownArrowKId },
|
||||||
|
{ 3, 27, 79, 72, 0, 0, 0, 0, 0, kHomeKId },
|
||||||
|
{ 3, 27, 79, 70, 0, 0, 0, 0, 0, kEndKId },
|
||||||
|
{ 4, 27, 91, 53, 126, 0, 0, 0, 0, kPgUpKId },
|
||||||
|
{ 4, 27, 91, 54, 126, 0, 0, 0, 0, kPgDownKId },
|
||||||
|
{ 4, 27, 91, 50, 126, 0, 0, 0, 0, kInsertKId },
|
||||||
|
{ 4, 27, 91, 51, 126, 0, 0, 0, 0, kDeleteKId },
|
||||||
|
{ 6, 27, 91, 49, 59, 53, 68, 0, 1, kLeftArrowKId },
|
||||||
|
{ 6, 27, 91, 49, 59, 53, 67, 0, 1, kRightArrowKId },
|
||||||
|
{ 6, 27, 91, 49, 59, 53, 65, 0, 1, kUpArrowKId },
|
||||||
|
{ 6, 27, 91, 49, 59, 53, 66, 0, 1, kDownArrowKId },
|
||||||
|
{ 6, 27, 91, 53, 59, 53, 126, 0, 1, kPgUpKId },
|
||||||
|
{ 6, 27, 91, 54, 59, 53, 126, 0, 1, kPgDownKId },
|
||||||
|
{ 4, 27, 91, 51, 59, 53, 126, 0, 1, kDeleteKId },
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, kInvalidKId }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cw::keyPress( cmKbRecd* p )
|
||||||
|
{
|
||||||
|
const int bufN = 16;
|
||||||
|
char buf[bufN];
|
||||||
|
int n,j, k;
|
||||||
|
int rc;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if( p != NULL )
|
||||||
|
{
|
||||||
|
p->code = kInvalidKId;
|
||||||
|
p->ch = 0;
|
||||||
|
p->ctlFl = false;
|
||||||
|
p->altFl = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_keypress();
|
||||||
|
|
||||||
|
// block for the first character
|
||||||
|
if((rc = read(0, &c, 1 )) == 1)
|
||||||
|
buf[0]=c;
|
||||||
|
|
||||||
|
// loop in non-blocking for successive characters
|
||||||
|
new_settings.c_cc[VMIN] = 0;
|
||||||
|
tcsetattr(0,TCSANOW,&new_settings);
|
||||||
|
|
||||||
|
for(n=1; n<bufN; ++n)
|
||||||
|
if(read(0,&c,1) == 1 )
|
||||||
|
buf[n] = c;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
new_settings.c_cc[VMIN] = 1;
|
||||||
|
tcsetattr(0,TCSANOW,&new_settings);
|
||||||
|
|
||||||
|
/*
|
||||||
|
for(j=0; j<n; ++j)
|
||||||
|
printf("{%c (%i)} ",buf[j],buf[j]);
|
||||||
|
printf(" :%i\f\n",n);
|
||||||
|
fflush(stdout);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( p != NULL )
|
||||||
|
{
|
||||||
|
// translate the keypress
|
||||||
|
if( n == 1)
|
||||||
|
{
|
||||||
|
p->code = kAsciiKId;
|
||||||
|
p->ch = buf[0];
|
||||||
|
p->ctlFl = buf[0] <= 31;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(j=0; _cmKbTbl[j][0] != 0; ++j)
|
||||||
|
if( _cmKbTbl[j][0] == (unsigned)n )
|
||||||
|
{
|
||||||
|
for(k=1; k<=n; ++k)
|
||||||
|
if( _cmKbTbl[j][k] != (unsigned)buf[k-1] )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// if the key was found
|
||||||
|
if( k==n+1 )
|
||||||
|
{
|
||||||
|
p->code = _cmKbTbl[j][ CM_KB_TBL_CNT - 1 ];
|
||||||
|
p->ctlFl = _cmKbTbl[j][ CM_KB_TBL_CNT - 2 ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reset_keypress();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Based on: // From: http://www.flipcode.com/archives/_kbhit_for_Linux.shtml
|
||||||
|
|
||||||
|
int cw::isKeyWaiting()
|
||||||
|
{
|
||||||
|
static const int STDIN = 0;
|
||||||
|
static bool initialized = false;
|
||||||
|
struct timeval timeout;
|
||||||
|
fd_set rdset;
|
||||||
|
|
||||||
|
if( !initialized )
|
||||||
|
{
|
||||||
|
// Use termios to turn off line buffering
|
||||||
|
struct termios term;
|
||||||
|
tcgetattr(STDIN, &term);
|
||||||
|
term.c_lflag &= ~ICANON;
|
||||||
|
tcsetattr(STDIN, TCSANOW, &term);
|
||||||
|
setbuf(stdin, NULL);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
FD_ZERO(&rdset);
|
||||||
|
FD_SET(STDIN, &rdset);
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
// time out immediately if STDIN is not ready.
|
||||||
|
return select(STDIN + 1, &rdset, NULL, NULL, &timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int bytesWaiting;
|
||||||
|
ioctl(STDIN, FIONREAD, &bytesWaiting);
|
||||||
|
return bytesWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cw::kbTest1()
|
||||||
|
{
|
||||||
|
set_keypress();
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
int r;
|
||||||
|
printf("'q' to quit\n");
|
||||||
|
while( c != 'q' )
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("0>"); fflush(stdout);
|
||||||
|
r = read(0, &c, 1 );
|
||||||
|
printf("0: %c (%i)\r\n",(char)c,c);
|
||||||
|
|
||||||
|
|
||||||
|
new_settings.c_cc[VMIN] = 0;
|
||||||
|
tcsetattr(0,TCSANOW,&new_settings);
|
||||||
|
|
||||||
|
if( r == 1 && c == 27 )
|
||||||
|
{
|
||||||
|
r = read(0, &c, 1 );
|
||||||
|
printf("1: %c (%i)\n",(char)c,c);
|
||||||
|
|
||||||
|
if( r == 1 && c == '[' )
|
||||||
|
{
|
||||||
|
r = read(0, &c, 1 );
|
||||||
|
printf("2: %c (%i)\n",(char)c,c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
new_settings.c_cc[VMIN] = 1;
|
||||||
|
tcsetattr(0,TCSANOW,&new_settings);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_keypress();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cw::kbTest2()
|
||||||
|
{
|
||||||
|
set_keypress();
|
||||||
|
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int retval;
|
||||||
|
int c=0;
|
||||||
|
|
||||||
|
printf("'q' to quit\n");
|
||||||
|
|
||||||
|
while( c != 'q' )
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
printf(">");
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Watch stdin (fd 0) to see when it has input.
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(0, &rfds);
|
||||||
|
|
||||||
|
// don't wait
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
retval = select(1, &rfds, NULL, NULL, i==0 ? NULL : &tv);
|
||||||
|
// Don't rely on the value of tv now - it may have been overwritten by select
|
||||||
|
|
||||||
|
// if an error occurred
|
||||||
|
if (retval == -1)
|
||||||
|
perror("select()");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if data is waiting
|
||||||
|
if (retval)
|
||||||
|
{
|
||||||
|
c = getchar();
|
||||||
|
printf("%i %c (%i) ",i,(char)c,c);
|
||||||
|
++i;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
break; // no data available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_keypress();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cw::kbTest3()
|
||||||
|
{
|
||||||
|
set_keypress();
|
||||||
|
|
||||||
|
int i =0;
|
||||||
|
|
||||||
|
printf("<enter> to quit");
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
cw::sleepMs(500); // sleep milliseconds
|
||||||
|
|
||||||
|
printf("%i\n",i);
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
if( isKeyWaiting() )
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_keypress();
|
||||||
|
|
||||||
|
}
|
70
cwKeyboard.h
Normal file
70
cwKeyboard.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef cwKeyboard_H
|
||||||
|
#define cwKeyboard_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kInvalidKId,
|
||||||
|
kAsciiKId,
|
||||||
|
kLeftArrowKId,
|
||||||
|
kRightArrowKId,
|
||||||
|
kUpArrowKId,
|
||||||
|
kDownArrowKId,
|
||||||
|
kHomeKId,
|
||||||
|
kEndKId,
|
||||||
|
kPgUpKId,
|
||||||
|
kPgDownKId,
|
||||||
|
kInsertKId,
|
||||||
|
kDeleteKId,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned code;
|
||||||
|
char ch;
|
||||||
|
bool ctlFl;
|
||||||
|
bool altFl;
|
||||||
|
} cmKbRecd;
|
||||||
|
|
||||||
|
// Set 'p' to NULL if the value of the key is not required.
|
||||||
|
void keyPress( cmKbRecd* p );
|
||||||
|
|
||||||
|
|
||||||
|
// Return non-zero if a key is waiting to be read otherwise return 0.
|
||||||
|
// Use getchar() to pick up the key.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// while( 1 )
|
||||||
|
// {
|
||||||
|
// if( cmIsKeyWaiting() == 0 )
|
||||||
|
// usleep(20000);
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// char c = getchar();
|
||||||
|
// switch(c)
|
||||||
|
// {
|
||||||
|
// ....
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// TODO: Note that this function turns off line-buffering on stdin.
|
||||||
|
// It should be changed to a three function sequence.
|
||||||
|
// bool org_state = cmSetStdinLineBuffering(false);
|
||||||
|
// ....
|
||||||
|
// isKeyWaiting()
|
||||||
|
// ....
|
||||||
|
// setStdinLineBuffering(org_state)
|
||||||
|
int isKeyWaiting();
|
||||||
|
|
||||||
|
void kbTest1();
|
||||||
|
void kbTest2();
|
||||||
|
void kbTest3();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
5
cwMidi.h
5
cwMidi.h
@ -11,6 +11,7 @@ namespace cw
|
|||||||
kInvalidMidiByte = 128,
|
kInvalidMidiByte = 128,
|
||||||
kMidiNoteCnt = kInvalidMidiByte,
|
kMidiNoteCnt = kInvalidMidiByte,
|
||||||
kMidiCtlCnt = kInvalidMidiByte,
|
kMidiCtlCnt = kInvalidMidiByte,
|
||||||
|
kMidiVelCnt = kInvalidMidiByte,
|
||||||
kMidiPgmCnt = kInvalidMidiByte,
|
kMidiPgmCnt = kInvalidMidiByte,
|
||||||
kInvalidMidiPitch = kInvalidMidiByte,
|
kInvalidMidiPitch = kInvalidMidiByte,
|
||||||
kInvalidMidiVelocity = kInvalidMidiByte,
|
kInvalidMidiVelocity = kInvalidMidiByte,
|
||||||
@ -98,6 +99,10 @@ namespace cw
|
|||||||
template< typename T> bool isSostenutoPedalDown( T s, T d0, T d1) { return ( isSostenutoPedal(s,d0) && (d1)>=64 ); }
|
template< typename T> bool isSostenutoPedalDown( T s, T d0, T d1) { return ( isSostenutoPedal(s,d0) && (d1)>=64 ); }
|
||||||
template< typename T> bool isSostenutoPedalUp( T s, T d0, T d1) { return ( isSostenutoPedal(s,d0) && (d1)<64 ); }
|
template< typename T> bool isSostenutoPedalUp( T s, T d0, T d1) { return ( isSostenutoPedal(s,d0) && (d1)<64 ); }
|
||||||
|
|
||||||
|
template< typename T> bool isSoftPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSoftPedalCtlMdId ); }
|
||||||
|
template< typename T> bool isSoftPedalDown( T s, T d0, T d1) { return ( isSoftPedal(s,d0) && (d1)>=64 ); }
|
||||||
|
template< typename T> bool isSoftPedalUp( T s, T d0, T d1) { return ( isSoftPedal(s,d0) && (d1)<64 ); }
|
||||||
|
|
||||||
template< typename T> bool isPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)>=kSustainCtlMdId && (d0)<=kLegatoCtlMdId ); }
|
template< typename T> bool isPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)>=kSustainCtlMdId && (d0)<=kLegatoCtlMdId ); }
|
||||||
template< typename T> bool isPedalDown( T s, T d0, T d1 ) { return ( isPedal(s,d0) && (d1)>=64 ); }
|
template< typename T> bool isPedalDown( T s, T d0, T d1 ) { return ( isPedal(s,d0) && (d1)>=64 ); }
|
||||||
template< typename T> bool isPedalUp( T s, T d0, T d1 ) { return ( isPedal(s,d0) && (d1)<64 ); }
|
template< typename T> bool isPedalUp( T s, T d0, T d1 ) { return ( isPedal(s,d0) && (d1)<64 ); }
|
||||||
|
@ -134,12 +134,18 @@ namespace cw
|
|||||||
|
|
||||||
// if no input
|
// if no input
|
||||||
if( rc == -EAGAIN )
|
if( rc == -EAGAIN )
|
||||||
|
{
|
||||||
|
// TODO: report or at least count error
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// if input buffer overrun
|
// if input buffer overrun
|
||||||
if( rc == -ENOSPC )
|
if( rc == -ENOSPC )
|
||||||
|
{
|
||||||
|
// TODO: report or at least count error
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// get the device this event arrived from
|
// get the device this event arrived from
|
||||||
if( p->prvRcvDev==NULL || p->prvRcvDev->clientId != ev->source.client )
|
if( p->prvRcvDev==NULL || p->prvRcvDev->clientId != ev->source.client )
|
||||||
p->prvRcvDev = _cmMpClientIdToDev(p,ev->source.client);
|
p->prvRcvDev = _cmMpClientIdToDev(p,ev->source.client);
|
||||||
@ -150,7 +156,7 @@ namespace cw
|
|||||||
|
|
||||||
if( p->prvRcvDev == NULL || p->prvRcvPort == NULL )
|
if( p->prvRcvDev == NULL || p->prvRcvPort == NULL )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//printf("%i %x\n",ev->type,ev->type);
|
//printf("%i %x\n",ev->type,ev->type);
|
||||||
//printf("dev:%i port:%i ch:%i %i\n",ev->source.client,ev->source.port,ev->data.note.channel,ev->data.note.note);
|
//printf("dev:%i port:%i ch:%i %i\n",ev->source.client,ev->source.port,ev->data.note.channel,ev->data.note.note);
|
||||||
|
|
||||||
|
@ -1114,8 +1114,50 @@ namespace cw
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _testBatchConvert( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
const char* io_dir = nullptr;
|
||||||
|
const char* session_dir = nullptr;
|
||||||
|
unsigned take_begin = 0;
|
||||||
|
unsigned take_end = 0;
|
||||||
|
bool printWarningsFl = true;
|
||||||
|
if((rc = cfg->getv("io_dir",io_dir,
|
||||||
|
"session_dir",session_dir,
|
||||||
|
"take_begin",take_begin,
|
||||||
|
"take_end",take_end,
|
||||||
|
"print_warnings_flag",printWarningsFl)) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"MIDI file batch convert to CSV failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned i=take_begin; i<=take_end; ++i)
|
||||||
|
{
|
||||||
|
char take_dir[32];
|
||||||
|
snprintf(take_dir,32,"record_%i",i);
|
||||||
|
char* src_midi_fn = filesys::makeFn( io_dir, "midi", ".mid", session_dir, take_dir, nullptr );
|
||||||
|
char* dst_csv_fn = filesys::makeFn( io_dir, "midi", ".csv", session_dir, take_dir, nullptr );
|
||||||
|
|
||||||
|
char* sm_fn = filesys::expandPath( src_midi_fn );
|
||||||
|
char* dm_fn = filesys::expandPath( dst_csv_fn );
|
||||||
|
|
||||||
|
//rc = genCsvFile(mfn,cfn );
|
||||||
|
cwLogInfo("Midi to CSV: src:%s dst:%s\n", sm_fn,dm_fn);
|
||||||
|
|
||||||
|
if((rc = genCsvFile(sm_fn, dm_fn, printWarningsFl )) != kOkRC )
|
||||||
|
cwLogError(rc,"MIDI to CSV Conversion failed on %s to %s.",sm_fn,dm_fn);
|
||||||
|
|
||||||
|
mem::release(sm_fn);
|
||||||
|
mem::release(dm_fn);
|
||||||
|
|
||||||
|
mem::release(src_midi_fn);
|
||||||
|
mem::release(dst_csv_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1746,12 +1788,18 @@ void cw::midi::file::calcNoteDurations( handle_t h, unsigned flags )
|
|||||||
trackMsg_t* m0 = noteM[k];
|
trackMsg_t* m0 = noteM[k];
|
||||||
|
|
||||||
if( m0 == NULL )
|
if( m0 == NULL )
|
||||||
cwLogWarning("%i : Missing note-on instance for note-off:%s",m->uid,midi::midiToSciPitch(d0,NULL,0));
|
{
|
||||||
|
if( warningFl )
|
||||||
|
cwLogWarning("%i : Missing note-on instance for note-off:%s",m->uid,midi::midiToSciPitch(d0,NULL,0));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// a key was released - so it should not already be up
|
// a key was released - so it should not already be up
|
||||||
if( noteGateM[k]==0 )
|
if( noteGateM[k]==0 )
|
||||||
cwLogWarning("%i : Missing note-on for note-off:%s",m->uid,midi::midiToSciPitch(d0,NULL,0));
|
{
|
||||||
|
if( warningFl )
|
||||||
|
cwLogWarning("%i : Missing note-on for note-off:%s",m->uid,midi::midiToSciPitch(d0,NULL,0));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
noteGateM[k] -= 1; // update the note gate state
|
noteGateM[k] -= 1; // update the note gate state
|
||||||
@ -1783,7 +1831,7 @@ void cw::midi::file::calcNoteDurations( handle_t h, unsigned flags )
|
|||||||
if( isSustainPedalUp(m) )
|
if( isSustainPedalUp(m) )
|
||||||
{
|
{
|
||||||
// if the sustain channel is already up
|
// if the sustain channel is already up
|
||||||
if( sustGateV[ch]==0 )
|
if( warningFl && sustGateV[ch]==0 )
|
||||||
cwLogWarning("%i : The sustain pedal release message was received with no previous pedal down.",m->uid);
|
cwLogWarning("%i : The sustain pedal release message was received with no previous pedal down.",m->uid);
|
||||||
|
|
||||||
if( sustGateV[ch] >= 1 )
|
if( sustGateV[ch] >= 1 )
|
||||||
@ -1830,7 +1878,7 @@ void cw::midi::file::calcNoteDurations( handle_t h, unsigned flags )
|
|||||||
if( isSostenutoPedalUp(m) )
|
if( isSostenutoPedalUp(m) )
|
||||||
{
|
{
|
||||||
// if the sustain channel is already up
|
// if the sustain channel is already up
|
||||||
if( sostGateV[ch]==0 )
|
if( warningFl && sostGateV[ch]==0 )
|
||||||
cwLogWarning("%i : The sostenuto pedal release message was received with no previous pedal down.",m->uid);
|
cwLogWarning("%i : The sostenuto pedal release message was received with no previous pedal down.",m->uid);
|
||||||
|
|
||||||
if( sostGateV[ch] >= 1 )
|
if( sostGateV[ch] >= 1 )
|
||||||
@ -2157,7 +2205,7 @@ cw::rc_t cw::midi::file::genPlotFile( const char* midiFn, const char* outFn )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::midi::file::genCsvFile( const char* midiFn, const char* csvFn )
|
cw::rc_t cw::midi::file::genCsvFile( const char* midiFn, const char* csvFn, bool printWarningsFl)
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
handle_t mfH;
|
handle_t mfH;
|
||||||
@ -2166,7 +2214,7 @@ cw::rc_t cw::midi::file::genCsvFile( const char* midiFn, const char* csvFn )
|
|||||||
if((rc = open( mfH, midiFn )) != kOkRC )
|
if((rc = open( mfH, midiFn )) != kOkRC )
|
||||||
return cwLogError(rc,"The MIDI file object could not be opened from '%s'.",cwStringNullGuard(midiFn));
|
return cwLogError(rc,"The MIDI file object could not be opened from '%s'.",cwStringNullGuard(midiFn));
|
||||||
|
|
||||||
calcNoteDurations( mfH, 0 );
|
calcNoteDurations( mfH, printWarningsFl ? kWarningsMfFl : 0 );
|
||||||
|
|
||||||
if((rc = cw::file::open(fH, csvFn,cw::file::kWriteFl)) != kOkRC )
|
if((rc = cw::file::open(fH, csvFn,cw::file::kWriteFl)) != kOkRC )
|
||||||
{
|
{
|
||||||
@ -2351,13 +2399,23 @@ cw::rc_t cw::midi::file::test( const object_t* cfg )
|
|||||||
{
|
{
|
||||||
|
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const object_t* o;
|
|
||||||
|
|
||||||
if((o = cfg->find("rpt")) != nullptr )
|
const object_t* o;
|
||||||
rc = _testReport(o);
|
|
||||||
|
|
||||||
if((o = cfg->find("csv")) != nullptr )
|
for(unsigned i=0; i<cfg->child_count(); ++i)
|
||||||
rc = _testCsv(o);
|
{
|
||||||
|
if((o = cfg->child_ele(i)) != nullptr )
|
||||||
|
{
|
||||||
|
if( strcmp(o->pair_label(),"rpt")==0 )
|
||||||
|
rc = _testReport(o->pair_value());
|
||||||
|
|
||||||
|
if( strcmp(o->pair_label(),"csv")==0 )
|
||||||
|
rc = _testCsv(o->pair_value());
|
||||||
|
|
||||||
|
if( strcmp(o->pair_label(),"batch_convert")==0 )
|
||||||
|
rc = _testBatchConvert(o->pair_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ namespace cw
|
|||||||
|
|
||||||
rc_t genSvgFile(const char* midiFn, const char* outSvgFn, const char* cssFn, bool standAloneFl, bool panZoomFl );
|
rc_t genSvgFile(const char* midiFn, const char* outSvgFn, const char* cssFn, bool standAloneFl, bool panZoomFl );
|
||||||
|
|
||||||
rc_t genCsvFile( const char* midiFn, const char* csvFn );
|
rc_t genCsvFile( const char* midiFn, const char* csvFn, bool printWarningsFl=true );
|
||||||
|
|
||||||
// Generate a text file reportusing cmMIdiFilePrintMsgs()
|
// Generate a text file reportusing cmMIdiFilePrintMsgs()
|
||||||
rc_t report( const char* midiFn, log::handle_t logH );
|
rc_t report( const char* midiFn, log::handle_t logH );
|
||||||
|
176
cwPresetSel.cpp
176
cwPresetSel.cpp
@ -200,6 +200,56 @@ namespace cw
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool _loc_is_in_frag( const frag_t* f, unsigned loc )
|
||||||
|
{
|
||||||
|
// if f is the earliest fragment
|
||||||
|
if( f->prev == nullptr )
|
||||||
|
return loc <= f->endLoc;
|
||||||
|
|
||||||
|
// else f->prev->end_loc < loc && loc <= f->end_loc
|
||||||
|
return f->prev->endLoc < loc && loc <= f->endLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _loc_is_before_frag( const frag_t* f, unsigned loc )
|
||||||
|
{
|
||||||
|
// if loc is past f
|
||||||
|
if( loc > f->endLoc )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// loc may now only be inside or before f
|
||||||
|
|
||||||
|
// if f is the first frag then loc must be inside it
|
||||||
|
if( f->prev == nullptr )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// is loc before f
|
||||||
|
return loc <= f->prev->endLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _loc_is_after_frag( const frag_t* f, unsigned loc )
|
||||||
|
{
|
||||||
|
return loc > f->endLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan from through the fragment list to find the fragment containing loc.
|
||||||
|
frag_t* _fast_loc_to_frag( preset_sel_t* p, unsigned loc, frag_t* init_frag=nullptr )
|
||||||
|
{
|
||||||
|
frag_t* f = init_frag==nullptr ? p->fragL : init_frag;
|
||||||
|
for(; f!=nullptr; f=f->link)
|
||||||
|
if( _loc_is_in_frag(f,loc) )
|
||||||
|
return f;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rc_t _validate_preset_id( const frag_t* frag, unsigned preset_id )
|
rc_t _validate_preset_id( const frag_t* frag, unsigned preset_id )
|
||||||
@ -234,9 +284,13 @@ namespace cw
|
|||||||
case kPresetSelectVarId:
|
case kPresetSelectVarId:
|
||||||
for(unsigned i=0; i<f->presetN; ++i)
|
for(unsigned i=0; i<f->presetN; ++i)
|
||||||
f->presetA[i].playFl = f->presetA[i].preset_idx == presetId ? value : false;
|
f->presetA[i].playFl = f->presetA[i].preset_idx == presetId ? value : false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kPresetSeqSelectVarId:
|
||||||
|
if((rc = _validate_preset_id(f, presetId )) == kOkRC )
|
||||||
|
f->presetA[ presetId ].seqFl = value;
|
||||||
|
break;
|
||||||
|
|
||||||
case kPresetOrderVarId:
|
case kPresetOrderVarId:
|
||||||
if((rc = _validate_preset_id(f, presetId )) == kOkRC )
|
if((rc = _validate_preset_id(f, presetId )) == kOkRC )
|
||||||
f->presetA[ presetId ].order = value;
|
f->presetA[ presetId ].order = value;
|
||||||
@ -269,6 +323,14 @@ namespace cw
|
|||||||
case kPlayBtnVarId:
|
case kPlayBtnVarId:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kPlaySeqBtnVarId:
|
||||||
|
f->seqAllFl = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kPlaySeqAllBtnVarId:
|
||||||
|
f->seqAllFl = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case kMasterWetInGainVarId:
|
case kMasterWetInGainVarId:
|
||||||
p->master_wet_in_gain = value;
|
p->master_wet_in_gain = value;
|
||||||
break;
|
break;
|
||||||
@ -329,6 +391,11 @@ namespace cw
|
|||||||
valueRef = f->presetA[ presetId ].playFl;
|
valueRef = f->presetA[ presetId ].playFl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kPresetSeqSelectVarId:
|
||||||
|
if((rc = _validate_preset_id(f, presetId )) == kOkRC )
|
||||||
|
valueRef = f->presetA[ presetId ].seqFl;
|
||||||
|
break;
|
||||||
|
|
||||||
case kPresetOrderVarId:
|
case kPresetOrderVarId:
|
||||||
if((rc = _validate_preset_id(f, presetId )) == kOkRC )
|
if((rc = _validate_preset_id(f, presetId )) == kOkRC )
|
||||||
valueRef = f->presetA[ presetId ].order;
|
valueRef = f->presetA[ presetId ].order;
|
||||||
@ -360,6 +427,13 @@ namespace cw
|
|||||||
|
|
||||||
case kPlayBtnVarId:
|
case kPlayBtnVarId:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kPlaySeqBtnVarId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kPlaySeqAllBtnVarId:
|
||||||
|
valueRef = f->seqAllFl;
|
||||||
|
break;
|
||||||
|
|
||||||
case kMasterWetInGainVarId:
|
case kMasterWetInGainVarId:
|
||||||
valueRef = p->master_wet_in_gain;
|
valueRef = p->master_wet_in_gain;
|
||||||
@ -769,8 +843,8 @@ bool cw::preset_sel::track_timestamp( handle_t h, const time::spec_t& ts, const
|
|||||||
|
|
||||||
time::spec_t t0;
|
time::spec_t t0;
|
||||||
time::setZero(t0);
|
time::setZero(t0);
|
||||||
unsigned elapsedMs = time::elapsedMs(t0,ts);
|
//unsigned elapsedMs = time::elapsedMs(t0,ts);
|
||||||
double mins = elapsedMs / 60000.0;
|
//double mins = elapsedMs / 60000.0;
|
||||||
|
|
||||||
|
|
||||||
// if this is the first call to 'track_timestamp()'.
|
// if this is the first call to 'track_timestamp()'.
|
||||||
@ -802,15 +876,103 @@ bool cw::preset_sel::track_timestamp( handle_t h, const time::spec_t& ts, const
|
|||||||
return frag_changed_fl;
|
return frag_changed_fl;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned cw::preset_sel::fragment_play_preset_index( const frag_t* frag )
|
|
||||||
|
void cw::preset_sel::track_loc_reset( handle_t h )
|
||||||
{
|
{
|
||||||
|
preset_sel_t* p = _handleToPtr(h);
|
||||||
|
p->last_ts_frag = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cw::preset_sel::track_loc( handle_t h, unsigned loc, const cw::preset_sel::frag_t*& frag_Ref )
|
||||||
|
{
|
||||||
|
preset_sel_t* p = _handleToPtr(h);
|
||||||
|
frag_t* f = nullptr;
|
||||||
|
bool frag_changed_fl = false;
|
||||||
|
|
||||||
|
|
||||||
|
// if this is the first call to 'track_timestamp()'.
|
||||||
|
if( p->last_ts_frag == nullptr )
|
||||||
|
f = _fast_loc_to_frag(p,loc);
|
||||||
|
else
|
||||||
|
// if the 'ts' is in the same frag as previous call.
|
||||||
|
if( _loc_is_in_frag(p->last_ts_frag,loc) )
|
||||||
|
f = p->last_ts_frag;
|
||||||
|
else
|
||||||
|
// if 'ts' is in a later frag
|
||||||
|
if( _loc_is_after_frag(p->last_ts_frag,loc) )
|
||||||
|
f = _fast_loc_to_frag(p,loc,p->last_ts_frag);
|
||||||
|
else // ts is prior to 'last_ts_frag'
|
||||||
|
f = _fast_loc_to_frag(p,loc);
|
||||||
|
|
||||||
|
// 'f' will be null at this point if 'ts' is past the last preset.
|
||||||
|
// In this case we should leave 'last_ts_frag' unchanged.
|
||||||
|
|
||||||
|
// if 'f' is valid but different from 'last_ts_frag'
|
||||||
|
if( f != nullptr && f != p->last_ts_frag )
|
||||||
|
{
|
||||||
|
// don't allow the selected fragment to go backwards
|
||||||
|
if( p->last_ts_frag == nullptr || (p->last_ts_frag != nullptr && p->last_ts_frag->endLoc < f->endLoc) )
|
||||||
|
{
|
||||||
|
p->last_ts_frag = f;
|
||||||
|
frag_changed_fl = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frag_Ref = p->last_ts_frag;
|
||||||
|
|
||||||
|
return frag_changed_fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned cw::preset_sel::fragment_play_preset_index( const frag_t* frag, unsigned preset_seq_idx )
|
||||||
|
{
|
||||||
|
unsigned n = 0;
|
||||||
|
// for each preset
|
||||||
for(unsigned i=0; i<frag->presetN; ++i)
|
for(unsigned i=0; i<frag->presetN; ++i)
|
||||||
if( frag->presetA[i].playFl )
|
{
|
||||||
return frag->presetA[i].preset_idx;
|
// if 'preset_seq_idx' is not valid ...
|
||||||
|
if( preset_seq_idx==kInvalidIdx )
|
||||||
|
{
|
||||||
|
// ...then select the first preset whose 'playFl' is set.
|
||||||
|
if( frag->presetA[i].playFl )
|
||||||
|
return frag->presetA[i].preset_idx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ... otherwise select the 'nth' preset whose 'seqFl' is set
|
||||||
|
if( frag->presetA[i].seqFl || frag->seqAllFl )
|
||||||
|
{
|
||||||
|
if( n == preset_seq_idx )
|
||||||
|
return frag->presetA[i].preset_idx;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return kInvalidIdx;
|
return kInvalidIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned cw::preset_sel::fragment_seq_count( handle_t h, unsigned fragId )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
preset_sel_t* p = _handleToPtr(h);
|
||||||
|
frag_t* f = nullptr;
|
||||||
|
unsigned n = 0;
|
||||||
|
|
||||||
|
if((rc = _find_frag(p,fragId,f)) != kOkRC )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( f->seqAllFl )
|
||||||
|
return f->presetN;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<f->presetN; ++i)
|
||||||
|
if( f->presetA[i].seqFl )
|
||||||
|
++n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::preset_sel::write( handle_t h, const char* fn )
|
cw::rc_t cw::preset_sel::write( handle_t h, const char* fn )
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,7 @@ namespace cw
|
|||||||
typedef struct preset_str
|
typedef struct preset_str
|
||||||
{
|
{
|
||||||
bool playFl; // play this preset
|
bool playFl; // play this preset
|
||||||
|
bool seqFl; // play this preset during sequencing.
|
||||||
unsigned preset_idx; // preset index into preset_labelA[].
|
unsigned preset_idx; // preset index into preset_labelA[].
|
||||||
unsigned order; //
|
unsigned order; //
|
||||||
} preset_t;
|
} preset_t;
|
||||||
@ -34,6 +35,7 @@ namespace cw
|
|||||||
unsigned presetN;
|
unsigned presetN;
|
||||||
|
|
||||||
bool uiSelectFl;
|
bool uiSelectFl;
|
||||||
|
bool seqAllFl; // Set if all preset.seqFl's should be treated as though they are set to true.
|
||||||
|
|
||||||
struct frag_str* link;
|
struct frag_str* link;
|
||||||
struct frag_str* prev;
|
struct frag_str* prev;
|
||||||
@ -51,12 +53,15 @@ namespace cw
|
|||||||
kBegPlayLocVarId,
|
kBegPlayLocVarId,
|
||||||
kEndPlayLocVarId,
|
kEndPlayLocVarId,
|
||||||
kPlayBtnVarId,
|
kPlayBtnVarId,
|
||||||
|
kPlaySeqBtnVarId,
|
||||||
|
kPlaySeqAllBtnVarId,
|
||||||
kNoteVarId,
|
kNoteVarId,
|
||||||
|
|
||||||
kPresetOrderVarId, // preset order value
|
kPresetOrderVarId, // preset order value
|
||||||
kPresetSelectVarId, // select a preset to play
|
kPresetSelectVarId, // select a preset to play
|
||||||
kPlayEnableVarId, // include in the segment to play
|
kPresetSeqSelectVarId, // sequence preset selections to play
|
||||||
kDryFlVarId, // play this fragment dry
|
kPlayEnableVarId, // include in the segment to play
|
||||||
|
kDryFlVarId, // play this fragment dry
|
||||||
|
|
||||||
|
|
||||||
kBaseMasterVarId, // All 'master' variables have id's greater than kBaseMasterVarId
|
kBaseMasterVarId, // All 'master' variables have id's greater than kBaseMasterVarId
|
||||||
@ -110,8 +115,15 @@ namespace cw
|
|||||||
void track_timestamp_reset( handle_t h );
|
void track_timestamp_reset( handle_t h );
|
||||||
bool track_timestamp( handle_t h, const time::spec_t& ts, const cw::preset_sel::frag_t*& frag_Ref );
|
bool track_timestamp( handle_t h, const time::spec_t& ts, const cw::preset_sel::frag_t*& frag_Ref );
|
||||||
|
|
||||||
|
// Same as track_timestamp_???() but tracks the score 'loc' instead of timestamp.
|
||||||
|
void track_loc_reset( handle_t h );
|
||||||
|
bool track_loc( handle_t h, unsigned loc, const cw::preset_sel::frag_t*& frag_Ref );
|
||||||
|
|
||||||
// Return the preset index marked to play on this fragment.
|
// Return the preset index marked to play on this fragment.
|
||||||
unsigned fragment_play_preset_index( const frag_t* frag );
|
unsigned fragment_play_preset_index( const frag_t* frag, unsigned preset_seq_idx=kInvalidIdx );
|
||||||
|
|
||||||
|
// Return the count of presets whose 'seqFl' is set.
|
||||||
|
unsigned fragment_seq_count( handle_t h, unsigned fragId );
|
||||||
|
|
||||||
rc_t write( handle_t h, const char* fn );
|
rc_t write( handle_t h, const char* fn );
|
||||||
rc_t read( handle_t h, const char* fn );
|
rc_t read( handle_t h, const char* fn );
|
||||||
|
130
cwScoreFollower.cpp
Normal file
130
cwScoreFollower.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwText.h"
|
||||||
|
#include "cwObject.h"
|
||||||
|
#include "cwMidi.h"
|
||||||
|
#include "cwScoreFollower.h"
|
||||||
|
|
||||||
|
#include "cmGlobal.h"
|
||||||
|
#include "cmFloatTypes.h"
|
||||||
|
#include "cmRpt.h"
|
||||||
|
#include "cmErr.h"
|
||||||
|
#include "cmCtx.h"
|
||||||
|
#include "cmTime.h"
|
||||||
|
#include "cmMidi.h"
|
||||||
|
#include "cmSymTbl.h"
|
||||||
|
#include "cmScore.h"
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace score_follower
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef struct score_follower_str
|
||||||
|
{
|
||||||
|
unsigned search_area_locN;
|
||||||
|
unsigned key_wnd_locN;
|
||||||
|
char* score_csv_fname;
|
||||||
|
|
||||||
|
|
||||||
|
} score_follower_t;
|
||||||
|
|
||||||
|
score_follower_t* _handleToPtr( handle_t h )
|
||||||
|
{ return handleToPtr<handle_t,score_follower_t>(h); }
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _parse_cfg( score_follower_t* p, const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
const char* score_csv_fname;
|
||||||
|
|
||||||
|
if((rc = cfg->getv("score_csv_fname", score_csv_fname,
|
||||||
|
"search_area_locN", p->search_area_locN,
|
||||||
|
"key_wnd_locN", p->key_wnd_locN )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC, "Score follower argument parsing failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((app->score_csv_fname = filesys::expandPath( score_csv_fname )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Score follower score file expansion failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _destroy( score_follower_t* p)
|
||||||
|
{
|
||||||
|
mem::release(p->score_csv_fname);
|
||||||
|
mem::release(p);
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::score_follower::create( handle_t& hRef, const object_t* cfg, double srate )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
score_follower_t* p = nullptr;
|
||||||
|
|
||||||
|
if((rc = destroy(hRef)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
p = mem::allocZ<score_follower_t>();
|
||||||
|
|
||||||
|
if((rc = _parse_cfg(p,cfg)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, double srate, const unsigned* dynRefArray, unsigned dynRefCnt, cmScCb_t cbFunc, void* cbArg, cmSymTblH_t stH );
|
||||||
|
|
||||||
|
//cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hRef.set(p);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
{
|
||||||
|
_destroy(p);
|
||||||
|
cwLogError(rc,"Score follower create failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::score_follower::destroy( handle_t& hRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
score_follower_t* p = nullptr;
|
||||||
|
|
||||||
|
if( !hRef.isValid() )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
p = _handleToPtr(hRef);
|
||||||
|
|
||||||
|
if((rc = _destroy(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
hRef.clear();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::score_follower::reset( handle_t h, unsigned loc )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::score_follower::exec( handle_t h, unsigned smpIdx, unsigned muid, unsigned status, uint8_t d0, uint8_t d1, unsigned* scLocIdxPtr )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
21
cwScoreFollower.h
Normal file
21
cwScoreFollower.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef cwScoreFollower_h
|
||||||
|
#define cwScoreFollower_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace score_follower
|
||||||
|
{
|
||||||
|
typedef handle< struct score_follower_str > handle_t;
|
||||||
|
|
||||||
|
rc_t create( handle_t& hRef, const object_t* cfg, double srate );
|
||||||
|
|
||||||
|
rc_t destroy( handle_t& hRef );
|
||||||
|
|
||||||
|
rc_t reset( handle_t h, unsigned loc );
|
||||||
|
|
||||||
|
rc_t exec( handle_t h, unsigned smpIdx, unsigned muid, unsigned status, uint8_t d0, uint8_t d1, unsigned* scLocIdxPtr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -8,11 +8,23 @@ namespace cw
|
|||||||
typedef handle<struct thread_mach_str> handle_t;
|
typedef handle<struct thread_mach_str> handle_t;
|
||||||
typedef thread::cbFunc_t threadFunc_t;
|
typedef thread::cbFunc_t threadFunc_t;
|
||||||
|
|
||||||
|
// Create a thread machine instance.
|
||||||
|
// contextArray[ threadN ][ contextRecdByteN ] is an optional blob consisting of 'threadN' records each of size 'contextRecdByteN'.
|
||||||
|
// Each of the records then becomes the entity which is used as the 'arg' value in the callback for the first 'threadN' threads.
|
||||||
rc_t create( handle_t& hRef, threadFunc_t threadFunc=nullptr, void* contextArray=nullptr, unsigned contexRecdByteN=0, unsigned threadN=0 );
|
rc_t create( handle_t& hRef, threadFunc_t threadFunc=nullptr, void* contextArray=nullptr, unsigned contexRecdByteN=0, unsigned threadN=0 );
|
||||||
rc_t destroy( handle_t& hRef );
|
rc_t destroy( handle_t& hRef );
|
||||||
|
|
||||||
|
// Create an additional thread. Note that the additional thread will be started by the next
|
||||||
|
// call to 'start()'.
|
||||||
rc_t add( handle_t h, threadFunc_t threadFunc, void* arg );
|
rc_t add( handle_t h, threadFunc_t threadFunc, void* arg );
|
||||||
|
|
||||||
|
// Start all threads
|
||||||
rc_t start( handle_t h );
|
rc_t start( handle_t h );
|
||||||
|
|
||||||
|
// Stop all threads.
|
||||||
rc_t stop( handle_t h );
|
rc_t stop( handle_t h );
|
||||||
|
|
||||||
|
// Check if all threads are shutdown.
|
||||||
bool is_shutdown( handle_t h );
|
bool is_shutdown( handle_t h );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
195
cwUi.cpp
195
cwUi.cpp
@ -89,6 +89,7 @@ namespace cw
|
|||||||
char* recvBuf;
|
char* recvBuf;
|
||||||
unsigned recvBufN;
|
unsigned recvBufN;
|
||||||
unsigned recvBufIdx;
|
unsigned recvBufIdx;
|
||||||
|
unsigned recvShiftN;
|
||||||
|
|
||||||
unsigned* sessA; // sessA[ sessN ] array of wsSessId's
|
unsigned* sessA; // sessA[ sessN ] array of wsSessId's
|
||||||
unsigned sessN;
|
unsigned sessN;
|
||||||
@ -1047,7 +1048,54 @@ namespace cw
|
|||||||
{
|
{
|
||||||
return _setPropertyValue( h, propertyStr,uuId,enableFl ? 1 : 0 );
|
return _setPropertyValue( h, propertyStr,uuId,enableFl ? 1 : 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _copy_msg_to_recv_buffer( ui_t* p, const void* msg, unsigned msgByteN )
|
||||||
|
{
|
||||||
|
if( msg == nullptr || msgByteN == 0)
|
||||||
|
return kOkRC;
|
||||||
|
|
||||||
|
if( p->recvBufIdx + msgByteN > p->recvBufN )
|
||||||
|
return cwLogError(kBufTooSmallRC,"The UI input buffer (%i) is too small.", p->recvBufN);
|
||||||
|
|
||||||
|
memcpy(p->recvBuf + p->recvBufIdx, msg, msgByteN );
|
||||||
|
|
||||||
|
p->recvBufIdx += msgByteN;
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _get_msg_from_recv_buffer( ui_t* p )
|
||||||
|
{
|
||||||
|
const char* msg = nullptr;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
// shift off the previous msg
|
||||||
|
if( p->recvShiftN > 0 )
|
||||||
|
{
|
||||||
|
assert( p->recvBufIdx >= p->recvShiftN );
|
||||||
|
|
||||||
|
memmove(p->recvBuf, p->recvBuf+p->recvShiftN, p->recvBufIdx - p->recvShiftN );
|
||||||
|
p->recvBufIdx -= p->recvShiftN;
|
||||||
|
p->recvShiftN = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// locate the end of the next msg.
|
||||||
|
if( p->recvBufIdx > 0 )
|
||||||
|
{
|
||||||
|
for(i=0; p->recvBuf[i]!=0 and i<p->recvBufIdx; ++i)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// if the end of the next msg was found
|
||||||
|
if( i<p->recvBufIdx && p->recvBuf[i] == 0 )
|
||||||
|
{
|
||||||
|
p->recvShiftN = i+1;
|
||||||
|
msg = p->recvBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1089,6 +1137,7 @@ cw::rc_t cw::ui::create(
|
|||||||
p->recvBuf = mem::allocZ<char>(fmtBufByteN);
|
p->recvBuf = mem::allocZ<char>(fmtBufByteN);
|
||||||
p->recvBufN = fmtBufByteN;
|
p->recvBufN = fmtBufByteN;
|
||||||
p->recvBufIdx = 0;
|
p->recvBufIdx = 0;
|
||||||
|
p->recvShiftN = 0;
|
||||||
|
|
||||||
// create the root element
|
// create the root element
|
||||||
if((ele = _createBaseEle(p, nullptr, kRootAppId, kInvalidId, "uiDivId" )) == nullptr || ele->uuId != kRootUuId )
|
if((ele = _createBaseEle(p, nullptr, kRootAppId, kInvalidId, "uiDivId" )) == nullptr || ele->uuId != kRootUuId )
|
||||||
@ -1191,12 +1240,14 @@ cw::rc_t cw::ui::onDisconnect( handle_t h, unsigned wsSessId )
|
|||||||
|
|
||||||
cw::rc_t cw::ui::onReceive( handle_t h, unsigned wsSessId, const void* void_msg, unsigned msgByteN )
|
cw::rc_t cw::ui::onReceive( handle_t h, unsigned wsSessId, const void* void_msg, unsigned msgByteN )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
ui_t* p = _handleToPtr(h);
|
ui_t* p = _handleToPtr(h);
|
||||||
opId_t opId = kInvalidOpId;
|
opId_t opId = kInvalidOpId;
|
||||||
value_t value;
|
ele_t* ele = nullptr;
|
||||||
ele_t* ele;
|
const char* msg = nullptr;
|
||||||
|
value_t value;
|
||||||
|
|
||||||
|
/*
|
||||||
const char* src_msg = (const char*)void_msg;
|
const char* src_msg = (const char*)void_msg;
|
||||||
const char* msg = src_msg;
|
const char* msg = src_msg;
|
||||||
|
|
||||||
@ -1233,80 +1284,90 @@ cw::rc_t cw::ui::onReceive( handle_t h, unsigned wsSessId, const void* void_msg,
|
|||||||
// the message is being processed so the buffer will end up empty
|
// the message is being processed so the buffer will end up empty
|
||||||
// (if it was being used)
|
// (if it was being used)
|
||||||
p->recvBufIdx = 0;
|
p->recvBufIdx = 0;
|
||||||
|
*/
|
||||||
// parse the 'opId' from the message
|
|
||||||
opId = _labelToOpId(msg);
|
|
||||||
|
|
||||||
|
// buffer the incoming msg
|
||||||
switch( opId )
|
if((rc = _copy_msg_to_recv_buffer( p, void_msg, msgByteN )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// remove and and act on each buffered msg
|
||||||
|
while( (msg = _get_msg_from_recv_buffer(p)) != NULL )
|
||||||
{
|
{
|
||||||
case kInitOpId:
|
|
||||||
// if the app cfg included a reference to a UI resource file then instantiate it here
|
// parse the 'opId' from the message
|
||||||
_onNewRemoteUi( p, wsSessId );
|
opId = _labelToOpId(msg);
|
||||||
|
|
||||||
|
|
||||||
|
switch( opId )
|
||||||
|
{
|
||||||
|
case kInitOpId:
|
||||||
|
// if the app cfg included a reference to a UI resource file then instantiate it here
|
||||||
|
_onNewRemoteUi( p, wsSessId );
|
||||||
|
|
||||||
// Pass on the 'init' msg to the app.
|
// Pass on the 'init' msg to the app.
|
||||||
p->uiCbFunc( p->uiCbArg, wsSessId, opId, kInvalidId, kInvalidId, kInvalidId, kInvalidId, nullptr );
|
p->uiCbFunc( p->uiCbArg, wsSessId, opId, kInvalidId, kInvalidId, kInvalidId, kInvalidId, nullptr );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kValueOpId:
|
case kValueOpId:
|
||||||
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
|
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
|
||||||
cwLogError(kOpFailRC,"UI 'value' message parse failed.");
|
cwLogError(kOpFailRC,"UI 'value' message parse failed.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kCorruptOpId:
|
case kCorruptOpId:
|
||||||
if((ele = _parse_corrupt_msg(p, (const char*)msg )) == nullptr )
|
if((ele = _parse_corrupt_msg(p, (const char*)msg )) == nullptr )
|
||||||
cwLogError(kOpFailRC,"UI 'corrupt' message parse failed.");
|
cwLogError(kOpFailRC,"UI 'corrupt' message parse failed.");
|
||||||
else
|
else
|
||||||
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case kClickOpId:
|
case kClickOpId:
|
||||||
if((ele = _parse_click_msg(p, (const char*)msg )) == nullptr )
|
if((ele = _parse_click_msg(p, (const char*)msg )) == nullptr )
|
||||||
cwLogError(kOpFailRC,"UI 'click' message parse failed.");
|
cwLogError(kOpFailRC,"UI 'click' message parse failed.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSelectOpId:
|
case kSelectOpId:
|
||||||
if((ele = _parse_select_msg(p, value, (const char*)msg )) == nullptr )
|
if((ele = _parse_select_msg(p, value, (const char*)msg )) == nullptr )
|
||||||
cwLogError(kOpFailRC,"UI 'select' message parse failed.");
|
cwLogError(kOpFailRC,"UI 'select' message parse failed.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId, &value );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kEchoOpId:
|
case kEchoOpId:
|
||||||
if((ele = _parse_echo_msg(p,(const char*)msg)) == nullptr )
|
if((ele = _parse_echo_msg(p,(const char*)msg)) == nullptr )
|
||||||
cwLogError(kOpFailRC,"UI Echo message parse failed.");
|
cwLogError(kOpFailRC,"UI Echo message parse failed.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId,nullptr );
|
p->uiCbFunc( p->uiCbArg, wsSessId, opId, ele->logical_parent->appId, ele->uuId, ele->appId, ele->chanId,nullptr );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kIdleOpId:
|
case kIdleOpId:
|
||||||
p->uiCbFunc( p->uiCbArg, kInvalidId, opId, kInvalidId, kInvalidId, kInvalidId, kInvalidId, nullptr );
|
p->uiCbFunc( p->uiCbArg, kInvalidId, opId, kInvalidId, kInvalidId, kInvalidId, kInvalidId, nullptr );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kInvalidOpId:
|
case kInvalidOpId:
|
||||||
cwLogError(kInvalidIdRC,"The UI received a NULL op. id.");
|
cwLogError(kInvalidIdRC,"The UI received a NULL op. id.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cwLogError(kInvalidIdRC,"The UI received an unknown op. id.");
|
cwLogError(kInvalidIdRC,"The UI received an unknown op. id.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} // switch opId
|
} // switch opId
|
||||||
|
}
|
||||||
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
cwUiDecls.h
34
cwUiDecls.h
@ -13,27 +13,27 @@ namespace cw
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
kInvalidOpId,
|
kInvalidOpId, // 0
|
||||||
kConnectOpId, // A new remote user interface was connected
|
kConnectOpId, // 1 A new remote user interface was connected
|
||||||
kInitOpId, // A remote user interface instance was created and is available. It needs to be updated with the current state of the UI from the server.
|
kInitOpId, // 2 A remote user interface instance was created and is available. It needs to be updated with the current state of the UI from the server.
|
||||||
kValueOpId, // The value of a remote user interface control changed. Send this value to the application engine.
|
kValueOpId, // 3 The value of a remote user interface control changed. Send this value to the application engine.
|
||||||
kCorruptOpId, // The value of the remote user interface is invalid or corrupt.
|
kCorruptOpId, // 4 The value of the remote user interface is invalid or corrupt.
|
||||||
kClickOpId, // A element on a remote user interface was clicked.
|
kClickOpId, // 5 A element on a remote user interface was clicked.
|
||||||
kSelectOpId, // An element on a remote user interface was is 'selected' or 'deselected'.
|
kSelectOpId, // 6 An element on a remote user interface was is 'selected' or 'deselected'.
|
||||||
kEchoOpId, // A remote user interface is requesting an application engine value. The the current value of a ui element must be sent to the remote UI.
|
kEchoOpId, // 7 A remote user interface is requesting an application engine value. The the current value of a ui element must be sent to the remote UI.
|
||||||
kIdleOpId, // The application (UI server) is idle and waiting for the next event from a remote UI.
|
kIdleOpId, // 8 The application (UI server) is idle and waiting for the next event from a remote UI.
|
||||||
kDisconnectOpId // A reemot user interface was disconnected.
|
kDisconnectOpId // 9 A remote user interface was disconnected.
|
||||||
} opId_t;
|
} opId_t;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
kInvalidTId,
|
kInvalidTId, // 0
|
||||||
kBoolTId,
|
kBoolTId, // 1
|
||||||
kIntTId,
|
kIntTId, // 2
|
||||||
kUIntTId,
|
kUIntTId, // 3
|
||||||
kFloatTId,
|
kFloatTId, // 4
|
||||||
kDoubleTId,
|
kDoubleTId, // 5
|
||||||
kStringTId
|
kStringTId // 6
|
||||||
} dtypeId_t;
|
} dtypeId_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
check:{ name: midiThruCheckId, title:"MIDI Thru" },
|
check:{ name: midiThruCheckId, title:"MIDI Thru" },
|
||||||
numb_disp: { name: curMidiEvtCntId, title:"Current" },
|
numb_disp: { name: curMidiEvtCntId, title:"Current" },
|
||||||
numb_disp: { name: totalMidiEvtCntId, title:"Total" },
|
numb_disp: { name: totalMidiEvtCntId, title:"Total" },
|
||||||
|
check:{ name: midiMuteCheckId, title:"Mute" },
|
||||||
},
|
},
|
||||||
|
|
||||||
row: {
|
row: {
|
||||||
@ -33,6 +34,7 @@
|
|||||||
check:{ name: audioThroughCheckId, title:"Audio Thru" },
|
check:{ name: audioThroughCheckId, title:"Audio Thru" },
|
||||||
numb_disp: { name: curAudioSecsId, title:"Current:", decpl:1 },
|
numb_disp: { name: curAudioSecsId, title:"Current:", decpl:1 },
|
||||||
numb_disp: { name: totalAudioSecsId, title:"Total:", decpl:1 },
|
numb_disp: { name: totalAudioSecsId, title:"Total:", decpl:1 },
|
||||||
|
check: { name: audioMuteCheckId, title:"Mute:" },
|
||||||
},
|
},
|
||||||
|
|
||||||
row: {
|
row: {
|
||||||
|
@ -21,10 +21,20 @@
|
|||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fragPanelRow {
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-left: 15px;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
.fragPresetCtl {
|
.fragPresetCtl {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fragPresetCtl:nth-of-type(even){
|
||||||
|
border: 1px solid Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
.fragPresetCtl .uiNumber {
|
.fragPresetCtl .uiNumber {
|
||||||
border: 1px solid LightSteelBlue;
|
border: 1px solid LightSteelBlue;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
|
@ -467,7 +467,9 @@ function ui_create_check( parent_ele, d )
|
|||||||
ele.onclick = function() { ui_send_bool_value(this,dom_get_checkbox(this.id)); }
|
ele.onclick = function() { ui_send_bool_value(this,dom_get_checkbox(this.id)); }
|
||||||
|
|
||||||
if( !d.hasOwnProperty('value') )
|
if( !d.hasOwnProperty('value') )
|
||||||
|
{
|
||||||
ui_send_echo(ele)
|
ui_send_echo(ele)
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dom_set_checkbox(ele.id, d.value );
|
dom_set_checkbox(ele.id, d.value );
|
||||||
@ -870,8 +872,6 @@ function ui_create_list( parent_ele, d )
|
|||||||
|
|
||||||
function ui_set_value( d )
|
function ui_set_value( d )
|
||||||
{
|
{
|
||||||
//console.log(d)
|
|
||||||
|
|
||||||
var eleId = d.uuId.toString()
|
var eleId = d.uuId.toString()
|
||||||
var ele = dom_id_to_ele(eleId)
|
var ele = dom_id_to_ele(eleId)
|
||||||
|
|
||||||
@ -1089,7 +1089,9 @@ function ui_create( d )
|
|||||||
var parent_ele = ui_get_parent(d.parentUuId);
|
var parent_ele = ui_get_parent(d.parentUuId);
|
||||||
var ele = null;
|
var ele = null;
|
||||||
|
|
||||||
if( parent_ele != null )
|
if( parent_ele == null )
|
||||||
|
console.log("Parent ele not found.",d)
|
||||||
|
else
|
||||||
{
|
{
|
||||||
switch( d.type )
|
switch( d.type )
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
button:{ name: stopBtnId, title:"Stop" },
|
button:{ name: stopBtnId, title:"Stop" },
|
||||||
number:{ name: begLocNumbId, title:"Loc:", min:0, max:100000, step:1, decpl:0 },
|
number:{ name: begLocNumbId, title:"Loc:", min:0, max:100000, step:1, decpl:0 },
|
||||||
number:{ name: endLocNumbId, title:"End:", min:0, max:100000, step:1, decpl:0 },
|
number:{ name: endLocNumbId, title:"End:", min:0, max:100000, step:1, decpl:0 },
|
||||||
|
check: { name: liveCheckId, title:"Live" },
|
||||||
},
|
},
|
||||||
|
|
||||||
row: {
|
row: {
|
||||||
@ -49,6 +50,7 @@
|
|||||||
button:{ name: deleteBtnId, title:"Delete", enable: false },
|
button:{ name: deleteBtnId, title:"Delete", enable: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
row: {
|
row: {
|
||||||
number:{ name: halfPedalDelayMsId, title:"DelayMs:", min:0, max:5000, step:1, decpl:0 },
|
number:{ name: halfPedalDelayMsId, title:"DelayMs:", min:0, max:5000, step:1, decpl:0 },
|
||||||
number:{ name: halfPedalPedalVelId, title:"PVel:", min:0, max:127, step:1, decpl:0 },
|
number:{ name: halfPedalPedalVelId, title:"PVel:", min:0, max:127, step:1, decpl:0 },
|
||||||
@ -57,6 +59,7 @@
|
|||||||
number:{ name: halfPedalDurMsId, title:"DurMs:", min:0, max:5000, step:1, decpl:0 },
|
number:{ name: halfPedalDurMsId, title:"DurMs:", min:0, max:5000, step:1, decpl:0 },
|
||||||
number:{ name: halfPedalDnDelayMsId, title:"DownMs:", min:0, max:5000, step:1, decpl:0 },
|
number:{ name: halfPedalDnDelayMsId, title:"DownMs:", min:0, max:5000, step:1, decpl:0 },
|
||||||
},
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
row: {
|
row: {
|
||||||
str_disp:{ name: statusId, title:"Status:", value: "" },
|
str_disp:{ name: statusId, title:"Status:", value: "" },
|
||||||
|
Loading…
Reference in New Issue
Block a user