It’s been a while, but
I’m back with VW working on a I’m aiming to interface
to a C++ midi library written by via a C wrapper API written by
Ben Swift https://github.com/benswift/rtmidi-c-api
I’ve had a little experience in compiling C and the DLLCC, but I’m
running into a lot of problems. After spending days on this I’d very much
appreciate any help on this! The rig is: VW 7.9.1 on Mac OS X 10.7.3. I’ve compiled a test midi out program in C++ and that (more or
less) works fine. I’ve compiled the shared C library, and I can open it
and retrieve lists of I’ve tried all sorts of combinations drawn from the DLLC manual, the
THAPI example, the net, Siren, and Jun. The main problems I’m having is passing the portName
to openOutPort, and passing the message contents to sendMessage: rtErr openOutPort( outDevice* dev, int64_t portNumber, char* portName ){ try { std::string name(portName); dev->ptr->openPort(portNumber, name); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } }; My understanding is that the DLLCC machinery should take a String and
convert it to a null terminated string pointer. I’ve tried copying to
heap, asFixed… etc. What is the correct way to
pass this String in from Smalltalk? The send message uses a relatively new type that is apparently
guaranteed to be of fixed width. I just want to pass a ByteArray
of the form #[144 94 127]. This gets loaded to a vector and shunted
off to the C++ library. I’ve tried using char * and int
* copyToHeap, creating CTypes
etc. When the call works, I end up with random numbers that sometime stay the
same between calls. Again this fails the first time, and then “work”
subsequently. rtErr sendMessage( outDevice* dev, int64_t messageLength, uint8_t* message ){ try { std::vector<uint8_t> msgVector; for (int i = 0; i < (int)messageLength; ++i) { msgVector.push_back(message[i]); } dev->ptr->sendMessage(&msgVector); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } };
What is the correct way of passing in a ByteArray into this function?
Any help appreciated!
Thanks,
Stewart
_______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
OK, I’ve done some further testing and it looks like my first
problem is with converting the pointer passed in from DLLCC to a string within
the C function. Please see below for comparative test runs – the first
fails, the second works fine. This indicates that the pointer string can be dereferenced ok within C. When I create a string pointer locally within the C function, it
works fine. With the string pointer from DLLCC, it terminates with a “0x95ff4b12
std::__throw_logic_error(char const*) + 121” Any help in explaining this behaviour appreciated…. 1) Failing
Scenario….Smalltalk code… testOutput " | if | RtMidiExternalInterface unloadLibraries. (if := self new) open. [if openOutputPort: 1;
“<<<fails here…” testOutput]
ensure: [interface close] “ | msg
msgPointer | RtMidiExternalInterface unloadLibraries. msg :=
#[144 94 127] copy. msgPointer := msg gcCopyToHeap. interface sendMessage:
outputDevice with: msg size
with: msgPointer. External interface…. openOutPort: dev with: portNumber
with: portName <C: rtErr openOutPort(outDevice * dev, int64_t portNumber, char * portName)> ^self externalAccessFailedWith: _errorCode C
Code… rtErr openOutPort( outDevice* dev,
int64_t portNumber, char* portName
){
try {
std::cout << "openOutPort\n";
//const char *s =
"Hello, World!"; // works ok with these
//std::string
name(s);
std::string name(portName); //<<<<<< fails here
std::cout << "Pre openPort\n";
dev->ptr->openPort(portNumber, name);
std::cout << "Pre RTMIDI_NOERROR\n";
return RTMIDI_NOERROR;
}
catch ( RtError &error ) {
error.printMessage();
return RTMIDI_ERROR;
} }; Console
output…. newMidiInDevice getInPortCount getInPortName getInPortName getInPortName newMidiOutDevice getOutPortCount getOutPortName getOutPortName openOutPort terminate called throwing an exceptionAbort trap: 6 Error log… 8 libstdc++.6.dylib
0x95ff4b12 std::__throw_logic_error(char const*) + 121 9 libstdc++.6.dylib
0x9601edb5 char* std::string::_S_construct<char const*>(char const*,
char const*, std::allocator<char> const&, std::forward_iterator_tag) + 163 10 libstdc++.6.dylib 0x9601ee76 std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(char
const*, std::allocator<char> const&) + 60 11 librtmidi.dylib 0x0a76e859 openOutPort + 121 12 com.cincom.vw7.9.1 0x00077da9 pdCallC +
2545 (unx86CallC.c:368) 13
com.cincom.vw7.9.1
0x00006a26
primCallVarArgC + 332 (exCallC.c:512) 14
com.cincom.vw7.9.1
0x0005ee2b
rtPrimGlueVarArgMany + 43 2) This works fine…Smalltalk
code… testChar | msg msgPointer
| " 100 timesRepeat: [self new testChar]. " RtMidiExternalInterface unloadLibraries. interface := RtMidiExternalInterface
new. msg := 'Take me to the C'. msgPointer := msg. interface testChar:
msg size with: msgPointer. msg := #[144 94 127] copy. msgPointer := msg. interface testChar: msg
size with: msgPointer. External
interface…. testChar: messageLength with: message <C: rtErr testChar(int messageLength,
char* message)> ^self externalAccessFailedWith: _errorCode C
Code….. rtErr testChar(int messageLength, char* message ){
std::cout << "testChar\n";
std::cout << message;
std::cout << "\nPre for loop\n";
for (int i = 0; i
< (int)messageLength; ++i)
{ std::cout << "Each:\n";
printf("dec: %d char: %c\n", message[i], message[i]);
}
return RTMIDI_NOERROR; }; Console
output, all good… testChar Take me to the C Pre for loop Each: dec: 84
char: T Each: dec: 97
char: a Each: dec: 107
char: k Each: dec: 101
char: e Each: dec: 32
char: Each: dec: 109
char: m Each: dec: 101
char: e Each: dec: 32
char: Each: dec: 116
char: t Each: dec: 111
char: o Each: dec: 32
char: Each: dec: 116
char: t Each: dec: 104
char: h Each: dec: 101
char: e Each: dec: 32
char: Each: dec: 67
char: C testChar ?^ Pre for loop Each: dec: -112
char: ? Each: dec: 94
char: ^ Each: dec: 127
char: -----Original Message----- It’s been a while, but
I’m back with VW working on a I’m aiming to interface
to a C++ midi library written by via a C wrapper API written by Ben Swift https://github.com/benswift/rtmidi-c-api
I’ve had a little experience in compiling C and the DLLCC, but
I’m running into a lot of problems. After spending days on this I’d
very much appreciate any help on this! The rig is: VW 7.9.1 on Mac OS X 10.7.3. I’ve compiled a test midi out program in C++ and that (more or
less) works fine. I’ve compiled the shared C library, and I can open it
and retrieve lists of I’ve tried all sorts of combinations drawn from the DLLC manual,
the THAPI example, the net, Siren, and Jun. The main problems I’m having is passing the portName to
openOutPort, and passing the message contents to sendMessage: rtErr openOutPort( outDevice* dev, int64_t portNumber, char* portName ){ try { std::string name(portName); dev->ptr->openPort(portNumber, name); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } }; My understanding is that the DLLCC machinery should take a String and
convert it to a null terminated string pointer. I’ve tried copying to
heap, asFixed… etc. What is the correct way to pass this String in from
Smalltalk? The send message uses a relatively new type that is apparently
guaranteed to be of fixed width. I just want to pass a ByteArray of the form
#[144 94 127]. This gets loaded to
a vector and shunted off to the C++ library. I’ve tried using char * and
int * copyToHeap, creating CTypes etc. When the call works, I end up with
random numbers that sometime stay the same between calls. Again this fails the
first time, and then “work” subsequently. rtErr sendMessage( outDevice* dev, int64_t messageLength, uint8_t* message ){ try { std::vector<uint8_t> msgVector; for (int i = 0; i < (int)messageLength; ++i) { msgVector.push_back(message[i]); } dev->ptr->sendMessage(&msgVector); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } };
What is the correct way of passing in a ByteArray into this function?
Any help appreciated!
Thanks,
Stewart
_______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
This wouldn’t be a String of length divisible by 4, and an instance of a platform-specific class like MSCP1252String rather than ByteString? I reported a bug for those years back, but its AR was rejected: Case 358800: AR 47137: ExternalMethod call with MSCP1252 string of size multiples of 4 is changed The bug was that the string was somehow corrupted when a multiple of 4. Internally VW has string sizes padded to 4 bytes, and thus if the size is not divisible by 4 it’s easy to set the next padding byte to 0x00, to be the C string terminator. But for strings already filled to the end of their last 4 byte segment with characters, whatever VW was doing (or not doing) to add the 0x00 terminator was resulting in a corrupt string. The AR was rejected because this should have been obvious to DLLCC users J. However, it seems to have been fixed at least for Windows in VW 7.7. All the best, Steve From: [hidden email] [mailto:[hidden email]] On Behalf Of Stewart MacLean OK, I’ve done some further testing and it looks like my first problem is with converting the pointer passed in from DLLCC to a string within the C function. Please see below for comparative test runs – the first fails, the second works fine. This indicates that the pointer string can be dereferenced ok within C. When I create a string pointer locally within the C function, it works fine. With the string pointer from DLLCC, it terminates with a “0x95ff4b12 std::__throw_logic_error(char const*) + 121” Any help in explaining this behaviour appreciated…. 1) Failing Scenario….Smalltalk code… testOutput " | if | RtMidiExternalInterface unloadLibraries. (if := self new) open. [if openOutputPort: 1; “<<<fails here…” testOutput] ensure: [interface close] “ | msg msgPointer | RtMidiExternalInterface unloadLibraries. msg := #[144 94 127] copy. msgPointer := msg gcCopyToHeap. interface sendMessage: outputDevice with: msg size with: msgPointer. External interface…. openOutPort: dev with: portNumber with: portName <C: rtErr openOutPort(outDevice * dev, int64_t portNumber, char * portName)> ^self externalAccessFailedWith: _errorCode C Code… rtErr openOutPort( outDevice* dev, int64_t portNumber, char* portName ){ try { std::cout << "openOutPort\n"; //const char *s = "Hello, World!"; // works ok with these //std::string name(s); std::string name(portName); //<<<<<< fails here std::cout << "Pre openPort\n"; dev->ptr->openPort(portNumber, name); std::cout << "Pre RTMIDI_NOERROR\n"; return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } }; Console output…. newMidiInDevice getInPortCount getInPortName getInPortName getInPortName newMidiOutDevice getOutPortCount getOutPortName getOutPortName openOutPort terminate called throwing an exceptionAbort trap: 6 Error log… 8 libstdc++.6.dylib 0x95ff4b12 std::__throw_logic_error(char const*) + 121 9 libstdc++.6.dylib 0x9601edb5 char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) + 163 10 libstdc++.6.dylib 0x9601ee76 std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) + 60 11 librtmidi.dylib 0x0a76e859 openOutPort + 121 12 com.cincom.vw7.9.1 0x00077da9 pdCallC + 2545 (unx86CallC.c:368) 13 com.cincom.vw7.9.1 0x00006a26 primCallVarArgC + 332 (exCallC.c:512) 14 com.cincom.vw7.9.1 0x0005ee2b rtPrimGlueVarArgMany + 43 2) This works fine…Smalltalk code… testChar | msg msgPointer | " 100 timesRepeat: [self new testChar]. " RtMidiExternalInterface unloadLibraries. interface := RtMidiExternalInterface new. msg := 'Take me to the C'. msgPointer := msg. interface testChar: msg size with: msgPointer. msg := #[144 94 127] copy. msgPointer := msg. interface testChar: msg size with: msgPointer. External interface…. testChar: messageLength with: message <C: rtErr testChar(int messageLength, char* message)> ^self externalAccessFailedWith: _errorCode C Code….. rtErr testChar(int messageLength, char* message ){ std::cout << "testChar\n"; std::cout << message; std::cout << "\nPre for loop\n"; for (int i = 0; i < (int)messageLength; ++i) { std::cout << "Each:\n"; printf("dec: %d char: %c\n", message[i], message[i]); } return RTMIDI_NOERROR; }; Console output, all good… testChar Take me to the C Pre for loop Each: dec: 84 char: T Each: dec: 97 char: a Each: dec: 107 char: k Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 109 char: m Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 116 char: t Each: dec: 111 char: o Each: dec: 32 char: Each: dec: 116 char: t Each: dec: 104 char: h Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 67 char: C testChar ?^ Pre for loop Each: dec: -112 char: ? Each: dec: 94 char: ^ Each: dec: 127 char: -----Original Message----- It’s been a while, but I’m back with VW working on a MIDI project (makes a change from Accounting!). I’m aiming to interface to a C++ midi library written by Gary P. Scavone http://www.music.mcgill.ca/~gary/rtmidi/ via a C wrapper API written by Ben Swift https://github.com/benswift/rtmidi-c-api I’ve had a little experience in compiling C and the DLLCC, but I’m running into a lot of problems. After spending days on this I’d very much appreciate any help on this! The rig is: VW 7.9.1 on Mac OS X 10.7.3. I’ve compiled a test midi out program in C++ and that (more or less) works fine. I’ve compiled the shared C library, and I can open it and retrieve lists of Midi ports from Smalltalk. This works most of the time with the odd failure. I’ve also been able to open ports, but this seems to always fail the first time, and work afterwards (depending on whether I use g++ or clang++ - clang++ faults). I’ve also been able to send a message, but the data being received in the API is random, and bears no relation to what I’m sending. (not sure, but maybe an encoding problem). I’m starting from the command line and writing to cout to debug. I’ve tried all sorts of combinations drawn from the DLLC manual, the THAPI example, the net, Siren, and Jun. The main problems I’m having is passing the portName to openOutPort, and passing the message contents to sendMessage: rtErr openOutPort( outDevice* dev, int64_t portNumber, char* portName ){ try { std::string name(portName); dev->ptr->openPort(portNumber, name); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } }; My understanding is that the DLLCC machinery should take a String and convert it to a null terminated string pointer. I’ve tried copying to heap, asFixed… etc. What is the correct way to pass this String in from Smalltalk? The send message uses a relatively new type that is apparently guaranteed to be of fixed width. I just want to pass a ByteArray of the form #[144 94 127]. This gets loaded to a vector and shunted off to the C++ library. I’ve tried using char * and int * copyToHeap, creating CTypes etc. When the call works, I end up with random numbers that sometime stay the same between calls. Again this fails the first time, and then “work” subsequently. rtErr sendMessage( outDevice* dev, int64_t messageLength, uint8_t* message ){ try { std::vector<uint8_t> msgVector; for (int i = 0; i < (int)messageLength; ++i) { msgVector.push_back(message[i]); } dev->ptr->sendMessage(&msgVector); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } };
What is the correct way of passing in a ByteArray into this function?
Any help appreciated!
Thanks,
Stewart _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Stew MacLean
In addition to Steve’s notes, hopefully some of the following
rambling will be of use. In no particular order… I. msg := 'Take me to the C'. msgPointer := msg. interface testChar: msg size with: msgPointer. I think this works because DLLCC automatically appends the null
terminator when passing a Smalltalk ByteString. (If you pass a ByteArray instead, DLLCC has no inclination to
append a null, and the C function will interpret all the ensuing chars up to
the first zero byte valued character, wherever that occurs, as the intended
string. This can cause all sorts of trouble.) > msg := #[144 94 127] copy. > msgPointer := msg. > > interface testChar: msg size with: msgPointer. I don't think the above will include the null terminator, so
it's good that you use the loop in this case. I'm a little surprised that the
cout<< call works in the C function--perhaps the next char on the heap is
a zero byte. II. > [if > openOutputPort: 1; “<<<fails here…” > testOutput] ensure: [interface close] I'm probably missing something, but here it looks like you're
not passing the other required parameters to the call. I assume there's another
Smalltalk method which fills in the missing parameters and makes the actuall
DLLCC call using, say: openOutPort: dev with:
portNumber with: portName Eg., you'd want something like: if openOutPort: 1 with: 115 with: 'abc'. or if openOutPort: 1 with: 115 with: 'abc' copyToHeap. (You can test this by inspecting: ('abc' copyToHeap) copyCStringFromHeap Note that I wouldn't use gcCopy variants at first because they
can involve garbage collection surprise issues. For example, if the DLL expects
to use the pointer later, you don't want it to be GC'd. This can be tricky with
thapi. Also, structs that contain gcMalloc'd objects do not (iirc) know enough
to tell the GC to stay away from their member objects. So, a held reference to
a struct will not prevent its internal gcMalloc'd members from disappearing.
Later, replace malloc with gcMalloc and see what needs tweaking. (This development
approach is okay as long as your development image can tolerate some buildup of
un-freed pointers.) III. > msg := #[144 94 127] copy. > msgPointer := msg gcCopyToHeap. > > interface sendMessage: outputDevice with: msg size with:
msgPointer. I’m not sure why this fails. In your C function, you appear to
be successfully appending the characters to an empty Vector. Assuming that the
receiver of the Vector object knows how to deal with it, things should work. IV. On a minor note, you might also want to check that the type,
int64_t is declared to be a long long (assuming it's 64-bits). Eg., here’s an example from MySQLInterface, my_ulonglong <C: typedef unsigned long long
my_ulonglong> Hth, -Dave From: [hidden email]
[mailto:[hidden email]] On Behalf Of Stewart MacLean OK,
I’ve done some further testing and it looks like my first problem is with
converting the pointer passed in from DLLCC to a string within the C function.
Please see below for comparative test runs – the first fails, the second works
fine. This indicates that the pointer string can be dereferenced ok within C. When
I create a string pointer locally within the C function, it works fine. With
the string pointer from DLLCC, it terminates with a “0x95ff4b12
std::__throw_logic_error(char const*) + 121” Any
help in explaining this behaviour appreciated…. 1) Failing
Scenario….Smalltalk code… testOutput " | if | RtMidiExternalInterface unloadLibraries. (if := self new) open. [if openOutputPort: 1; “<<<fails
here…” testOutput] ensure: [interface close] “ | msg msgPointer | RtMidiExternalInterface unloadLibraries. msg := #[144 94 127] copy. msgPointer := msg gcCopyToHeap. interface
sendMessage: outputDevice with: msg size with: msgPointer. External interface…. openOutPort: dev with: portNumber with:
portName <C: rtErr
openOutPort(outDevice * dev, int64_t portNumber, char * portName)> ^self
externalAccessFailedWith: _errorCode C Code… rtErr openOutPort( outDevice* dev, int64_t portNumber, char*
portName ){ try
{
std::cout << "openOutPort\n";
//const char *s = "Hello, World!"; // works ok with
these
//std::string name(s);
std::string name(portName); //<<<<<< fails
here
std::cout << "Pre openPort\n";
dev->ptr->openPort(portNumber, name);
std::cout << "Pre
RTMIDI_NOERROR\n";
return RTMIDI_NOERROR; } catch
( RtError &error ) {
error.printMessage();
return RTMIDI_ERROR; } }; Console
output…. newMidiInDevice getInPortCount getInPortName getInPortName getInPortName newMidiOutDevice getOutPortCount getOutPortName getOutPortName openOutPort terminate
called throwing an exceptionAbort trap: 6 Error log… 8 libstdc++.6.dylib
0x95ff4b12 std::__throw_logic_error(char const*) + 121 9 libstdc++.6.dylib
0x9601edb5 char* std::string::_S_construct<char const*>(char
const*, char const*, std::allocator<char> const&,
std::forward_iterator_tag) + 163 10 libstdc++.6.dylib
0x9601ee76 std::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(char const*,
std::allocator<char> const&) + 60 11 librtmidi.dylib
0x0a76e859 openOutPort + 121 12 com.cincom.vw7.9.1
0x00077da9 pdCallC + 2545
(unx86CallC.c:368) 13 com.cincom.vw7.9.1
0x00006a26 primCallVarArgC + 332
(exCallC.c:512) 14 com.cincom.vw7.9.1
0x0005ee2b rtPrimGlueVarArgMany + 43 2) This works fine…Smalltalk code… testChar | msg msgPointer | " 100 timesRepeat: [self new
testChar]. " RtMidiExternalInterface
unloadLibraries. interface :=
RtMidiExternalInterface new. msg := 'Take me to the C'. msgPointer := msg. interface testChar: msg
size with: msgPointer. msg := #[144 94 127] copy. msgPointer := msg. interface
testChar: msg size with: msgPointer. External interface…. testChar: messageLength
with: message <C: rtErr testChar(int
messageLength, char* message)> ^self
externalAccessFailedWith: _errorCode C Code….. rtErr testChar(int
messageLength, char* message
){
std::cout << "testChar\n";
std::cout << message;
std::cout << "\nPre for loop\n";
for (int
i = 0; i < (int)messageLength;
++i)
{ std::cout << "Each:\n";
printf("dec:
%d char: %c\n", message[i], message[i]);
}
return RTMIDI_NOERROR; }; Console
output, all good… testChar Take me to the C Pre for loop Each: dec: 84 char: T Each: dec: 97 char: a Each: dec: 107 char: k Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 109 char: m Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 116 char: t Each: dec: 111 char: o Each: dec: 32 char: Each: dec: 116 char: t Each: dec: 104 char: h Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 67 char: C testChar ?^ Pre for loop Each: dec: -112 char: ? Each: dec: 94 char: ^ Each: dec: 127 char: -----Original
Message----- It’s
been a while, but I’m back with VW working on a MIDI project (makes a change
from Accounting!). I’m
aiming to interface to a C++ midi library written by Gary
P. Scavone http://www.music.mcgill.ca/~gary/rtmidi/ via a C wrapper API written by Ben Swift https://github.com/benswift/rtmidi-c-api
I’ve had a little experience in compiling C
and the DLLCC, but I’m running into a lot of problems. After spending days on
this I’d very much appreciate any help on this! The rig is: VW 7.9.1 on Mac OS X 10.7.3. I’ve compiled a test midi out program in
C++ and that (more or less) works fine. I’ve compiled the shared C library, and
I can open it and retrieve lists of Midi ports from Smalltalk. This works most
of the time with the odd failure. I’ve also been able to open ports, but this
seems to always fail the first time, and work afterwards (depending on whether
I use g++ or clang++ - clang++ faults). I’ve also been able to send a message,
but the data being received in the API is random, and bears no relation to what
I’m sending. (not sure, but maybe an encoding problem). I’m starting from the command
line and writing to cout to debug. I’ve tried all sorts of combinations drawn
from the DLLC manual, the THAPI example, the net, Siren, and Jun. The main problems I’m having is passing the
portName to openOutPort, and passing the message contents to sendMessage: rtErr openOutPort( outDevice* dev, int64_t portNumber, char* portName ){ try { std::string name(portName); dev->ptr->openPort(portNumber, name); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } }; My understanding is that the DLLCC
machinery should take a String and convert it to a null terminated string
pointer. I’ve tried copying to heap, asFixed… etc. What is the correct way to
pass this String in from Smalltalk? The send message uses a relatively new type
that is apparently guaranteed to be of fixed width. I just want to pass a
ByteArray of the form #[144 94 127]. This gets loaded to a vector and shunted
off to the C++ library. I’ve tried using char * and int * copyToHeap, creating
CTypes etc. When the call works, I end up with random numbers that sometime
stay the same between calls. Again this fails the first time, and then “work”
subsequently. rtErr sendMessage( outDevice* dev, int64_t messageLength, uint8_t* message ){ try { std::vector<uint8_t> msgVector; for (int i = 0; i < (int)messageLength; ++i) { msgVector.push_back(message[i]); } dev->ptr->sendMessage(&msgVector); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } };
What is the correct way of passing in a ByteArray into this function?
Any help appreciated!
Thanks,
Stewart
_______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Hi Guys, It wasn’t the bug “ExternalMethod call with MSCP1252 string of size
multiples of 4 is changed”. It was actually David’s “minor note”
that put me right, re the int64_t type. I document it below for any other DLLCC
newbies… I was focusing on the wrong parameter, as the String was manifesting the
error. I think the pointer to the string was misaligned due to the previous
parameter declaration being a pointer type, and DLLCC was just passing the
integer. In order to make it work as is, I guess I
should have passed a pointer to the integer? I’m curious, should DLLCC have parsed int64_t as David suggested?: my_ulonglong <C: typedef unsigned long long my_ulonglong> Having subsequently browsed through the DLLCCTest
classes (which doesn’t appear to work) I don’t
see any of the “uintN_t” types. I guess
DLLCC is showing signs of age? Thanks heaps for the help –
I can now send midi data with no errors. Next challenge is to get midi in via
the callback to work. Cheers, Stewart =============================================================================================== The interface builder had parsed: Header file: rtErr openOutPort( outDevice*
dev, int64_t portNumber, char* portName
); c
wrapper function: rtErr openOutPort( outDevice* dev,
int64_t portNumber, char* portName
){ try {
std::string
name(portName);
dev->ptr->openPort(portNumber, name);
return RTMIDI_NOERROR; } catch ( RtError &error ) {
error.printMessage();
return RTMIDI_ERROR; } }; Type Declaration
generated: int64_t <C: typedef void * int64_t> DLL procedure: openOutPort: dev with: portNumber with: portName <C: rtErr openOutPort(outDevice * dev, int64_t portNumber, char * portName)> ^self externalAccessFailedWith: _errorCode Called with: outputPortNumber
= 1, no copying to heap or making pointers openOutputPort: outputPortNumber | return msg msgPointer | msg :=
'An msgPointer := msg. (return
:= interface openOutPort: outputDevice with: outputPortNumber with: msgPointer) asInteger = 0 ifFalse:
[return inspect. self error: 'Open Output Port Failed']. Gave system exceptions on the first string
function in the c routine. The fix was to use plan old unsigned int instead (which is actually what the C++ RtMidi function that gets called uses!) -----Original Message----- In addition to Steve’s notes, hopefully some of the following
rambling will be of use. In no particular order… I. msg := 'Take me to the C'. msgPointer := msg. interface testChar: msg size with: msgPointer. I think this works because DLLCC automatically appends the null
terminator when passing a Smalltalk ByteString. (If you pass a ByteArray instead, DLLCC has no inclination to append a
null, and the C function will interpret all the ensuing chars up to the first
zero byte valued character, wherever that occurs, as the intended string. This
can cause all sorts of trouble.) > msg := #[144 94 127] copy. > msgPointer := msg. > > interface testChar: msg size with: msgPointer. I don't think the above will include the null terminator, so it's good
that you use the loop in this case. I'm a little surprised that the
cout<< call works in the C function--perhaps the next char on the heap is
a zero byte. II. > [if > openOutputPort: 1; “<<<fails here…” > testOutput] ensure: [interface close] I'm probably missing something, but here it looks like you're not
passing the other required parameters to the call. I assume there's another
Smalltalk method which fills in the missing parameters and makes the actuall
DLLCC call using, say: openOutPort: dev with: portNumber with:
portName Eg., you'd want something like: if openOutPort: 1 with: 115 with: 'abc'. or if openOutPort: 1 with: 115 with: 'abc' copyToHeap. (You can test this by inspecting:
('abc' copyToHeap) copyCStringFromHeap Note that I wouldn't use gcCopy variants at first because they can
involve garbage collection surprise issues. For example, if the DLL expects to
use the pointer later, you don't want it to be GC'd. This can be tricky with
thapi. Also, structs that contain gcMalloc'd objects do not (iirc) know enough
to tell the GC to stay away from their member objects. So, a held reference to
a struct will not prevent its internal gcMalloc'd members from disappearing.
Later, replace malloc with gcMalloc and see what needs tweaking. (This
development approach is okay as long as your development image can tolerate
some buildup of un-freed pointers.) III. > msg := #[144 94 127] copy. > msgPointer := msg gcCopyToHeap. > > interface sendMessage: outputDevice with: msg size with:
msgPointer. I’m not sure why this fails. In your C function, you appear to be
successfully appending the characters to an empty Vector. Assuming that the
receiver of the Vector object knows how to deal with it, things should work. IV. On a minor note, you might also want to check that the type, int64_t is
declared to be a long long (assuming it's 64-bits). Eg., here’s an example from MySQLInterface,
my_ulonglong
<C: typedef unsigned long long my_ulonglong> Hth, -Dave From:
[hidden email] [mailto:[hidden email]] On Behalf Of Stewart MacLean OK,
I’ve done some further testing and it looks like my first problem is with
converting the pointer passed in from DLLCC to a string within the C function.
Please see below for comparative test runs – the first fails, the second
works fine. This indicates that the pointer string can be dereferenced ok
within C. When I
create a string pointer locally within the C function, it works fine. With the
string pointer from DLLCC, it terminates with a “0x95ff4b12
std::__throw_logic_error(char const*) + 121” Any
help in explaining this behaviour appreciated…. 1) Failing Scenario….Smalltalk code… testOutput " | if | RtMidiExternalInterface unloadLibraries. (if := self new) open. [if openOutputPort:
1; “<<<fails here…” testOutput] ensure: [interface close] “ | msg msgPointer | RtMidiExternalInterface unloadLibraries. msg := #[144 94 127] copy. msgPointer := msg gcCopyToHeap. interface sendMessage: outputDevice with:
msg size with: msgPointer. External
interface…. openOutPort:
dev with: portNumber with: portName <C:
rtErr openOutPort(outDevice * dev, int64_t portNumber, char * portName)> ^self
externalAccessFailedWith: _errorCode C Code… rtErr openOutPort( outDevice* dev,
int64_t portNumber, char* portName ){
try {
std::cout << "openOutPort\n";
//const char *s =
"Hello, World!"; // works ok with these
//std::string
name(s);
std::string
name(portName); //<<<<<< fails here
std::cout << "Pre openPort\n";
dev->ptr->openPort(portNumber, name);
std::cout << "Pre RTMIDI_NOERROR\n";
return RTMIDI_NOERROR;
}
catch ( RtError &error ) {
error.printMessage();
return RTMIDI_ERROR;
} }; Console output…. newMidiInDevice getInPortCount getInPortName getInPortName getInPortName newMidiOutDevice getOutPortCount getOutPortName getOutPortName openOutPort terminate called throwing an
exceptionAbort trap: 6 Error
log… 8 libstdc++.6.dylib
0x95ff4b12 std::__throw_logic_error(char const*) +
121 9 libstdc++.6.dylib
0x9601edb5 char* std::string::_S_construct<char
const*>(char const*, char const*, std::allocator<char> const&,
std::forward_iterator_tag) + 163 10 libstdc++.6.dylib
0x9601ee76 std::basic_string<char,
std::char_traits<char>, std::allocator<char>
>::basic_string(char const*, std::allocator<char> const&) + 60 11 librtmidi.dylib
0x0a76e859 openOutPort + 121 12 com.cincom.vw7.9.1
0x00077da9
pdCallC + 2545 (unx86CallC.c:368) 13 com.cincom.vw7.9.1
0x00006a26
primCallVarArgC + 332 (exCallC.c:512) 14 com.cincom.vw7.9.1
0x0005ee2b
rtPrimGlueVarArgMany + 43 2) This
works fine…Smalltalk code… testChar | msg
msgPointer | " 100
timesRepeat: [self new testChar]. " RtMidiExternalInterface
unloadLibraries. interface
:= RtMidiExternalInterface new. msg :=
'Take me to the C'. msgPointer
:= msg. interface
testChar: msg size with: msgPointer. msg :=
#[144 94 127] copy. msgPointer
:= msg. interface
testChar: msg size with: msgPointer. External interface…. testChar:
messageLength with: message <C:
rtErr testChar(int messageLength, char* message)> ^self
externalAccessFailedWith: _errorCode C Code….. rtErr
testChar(int messageLength, char* message ){
std::cout << "testChar\n";
std::cout << message;
std::cout << "\nPre for loop\n";
for (int i = 0; i < (int)messageLength; ++i)
{ std::cout << "Each:\n";
printf("dec: %d char: %c\n", message[i], message[i]);
}
return RTMIDI_NOERROR; }; Console output, all good… testChar Take me to the C Pre for loop Each: dec: 84 char: T Each: dec: 97 char: a Each: dec: 107 char: k Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 109 char: m Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 116 char: t Each: dec: 111 char: o Each: dec: 32 char: Each: dec: 116 char: t Each: dec: 104 char: h Each: dec: 101 char: e Each: dec: 32 char: Each: dec: 67 char: C testChar ?^ Pre for loop Each: dec: -112 char: ? Each: dec: 94 char: ^ Each: dec: 127 char: -----Original Message----- It’s been a while, but
I’m back with VW working on a I’m aiming to interface
to a C++ midi library written by via a C wrapper API written by Ben Swift https://github.com/benswift/rtmidi-c-api
I’ve had a little experience in compiling C and the DLLCC, but
I’m running into a lot of problems. After spending days on this I’d
very much appreciate any help on this! The rig is: VW 7.9.1 on Mac OS X 10.7.3. I’ve compiled a test midi out program in C++ and that (more or
less) works fine. I’ve compiled the shared C library, and I can open it
and retrieve lists of I’ve tried all sorts of combinations drawn from the DLLC manual,
the THAPI example, the net, Siren, and Jun. The main problems I’m having is passing the portName to
openOutPort, and passing the message contents to sendMessage: rtErr openOutPort( outDevice* dev, int64_t portNumber, char* portName ){ try { std::string name(portName); dev->ptr->openPort(portNumber, name); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } }; My understanding is that the DLLCC machinery should take a String and
convert it to a null terminated string pointer. I’ve tried copying to
heap, asFixed… etc. What is the correct way to pass this String in from
Smalltalk? The send message uses a relatively new type that is apparently guaranteed
to be of fixed width. I just want to pass a ByteArray of the form #[144 94
127]. This gets loaded to a vector and shunted off to the C++ library.
I’ve tried using char * and int * copyToHeap, creating CTypes etc. When
the call works, I end up with random numbers that sometime stay the same
between calls. Again this fails the first time, and then “work”
subsequently. rtErr sendMessage( outDevice* dev, int64_t messageLength, uint8_t* message ){ try { std::vector<uint8_t> msgVector; for (int i = 0; i < (int)messageLength; ++i) { msgVector.push_back(message[i]); } dev->ptr->sendMessage(&msgVector); return RTMIDI_NOERROR; } catch ( RtError &error ) { error.printMessage(); return RTMIDI_ERROR; } };
What is the correct way of passing in a ByteArray into this function?
Any help appreciated!
Thanks,
Stewart
_______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |