我通过在Visual Studio 2010中将我自己的C ++项目编译为DLL来集成CMU的PocketSphinx和Unity,我是从Unity Pro中的C#脚本调用的。我知道dll是有效的,因为我使用相同的代码创建了另一个项目作为exe,编译它,它作为一个独立的程序完美地工作。我正在使用pocketsphinx_continuous项目示例,该示例获取麦克风输入并将文本输出到控制台。我已经自定义了要从Unity内部调用的代码,它应该作为字符串而不是控制台输出回我的C#代码。我觉得我几乎有这个工作,但const char *只是没有把它作为一个字符串。如果我使用此声明,我将最终获得访问冲突错误:
private static extern string recogn_from_microphone();
所以,我试图使用这个:
private static extern IntPtr recogn_from_microphone();
然后,我使用这行代码尝试打印该函数的输出:
print(“你刚才说”+ Marshal.PtrToStringAnsi(recogn_from_microphone()));
但是,我只得到了“你刚刚说过”作为回报。如果我这样做,我可以设法得到一个内存地址:print(“你刚才说”+ recogn_from_microphone());所以,我知道有些东西会被退回。
这是我的C ++代码(其中大部分是最初用C语言编写的,来自pocketsphinx的示例代码):
char* MakeStringCopy (const char* str)
{
if (str == NULL) return NULL;
char* res = (char*)malloc(strlen(str) + 1);
strcpy(res, str);
return res;
}
extern __declspec(dllexport) const char * recognize_from_microphone()
{
//this is a near complete duplication of the code from main()
char const *cfg;
config = cmd_ln_init(NULL, ps_args(), TRUE,
"-hmm", MODELDIR "\\hmm\\en_US\\hub4wsj_sc_8k",
"-lm", MODELDIR "\\lm\\en\\turtle.DMP",
"-dict", MODELDIR "\\lm\\en\\turtle.dic",
NULL);
if (config == NULL)
{
return "config is null";
}
ps = ps_init(config);
if (ps == NULL)
{
return "ps is null";
}
ad_rec_t *ad;
int16 adbuf[4096];
int32 k, ts, rem;
char const *hyp;
char const *uttid;
cont_ad_t *cont;
char word[256];
char words[1024] = "";
//char temp[] = "hypothesis";
//hyp = temp;
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
(int)cmd_ln_float32_r(config, "-samprate"))) == NULL)
E_FATAL("Failed to open audio device\n");
/* Initialize continuous listening module */
if ((cont = cont_ad_init(ad, ad_read)) == NULL)
E_FATAL("Failed to initialize voice activity detection\n");
if (ad_start_rec(ad) < 0)
E_FATAL("Failed to start recording\n");
if (cont_ad_calib(cont) < 0)
E_FATAL("Failed to calibrate voice activity detection\n");
for (;;) {
/* Indicate listening for next utterance */
//printf("READY....\n");
fflush(stdout);
fflush(stderr);
/* Wait data for next utterance */
while ((k = cont_ad_read(cont, adbuf, 4096)) == 0)
sleep_msec(100);
if (k < 0)
E_FATAL("Failed to read audio\n");
/*
* Non-zero amount of data received; start recognition of new utterance.
* NULL argument to uttproc_begin_utt => automatic generation of utterance-id.
*/
if (ps_start_utt(ps, NULL) < 0)
E_FATAL("Failed to start utterance\n");
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
//printf("Listening...\n");
fflush(stdout);
/* Note timestamp for this first block of data */
ts = cont->read_ts;
/* Decode utterance until end (marked by a "long" silence, >1sec) */
for (;;) {
/* Read non-silence audio data, if any, from continuous listening module */
if ((k = cont_ad_read(cont, adbuf, 4096)) < 0)
E_FATAL("Failed to read audio\n");
if (k == 0) {
/*
* No speech data available; check current timestamp with most recent
* speech to see if more than 1 sec elapsed. If so, end of utterance.
*/
if ((cont->read_ts - ts) > DEFAULT_SAMPLES_PER_SEC)
break;
}
else {
/* New speech data received; note current timestamp */
ts = cont->read_ts;
}
/*
* Decode whatever data was read above.
*/
rem = ps_process_raw(ps, adbuf, k, FALSE, FALSE);
/* If no work to be done, sleep a bit */
if ((rem == 0) && (k == 0))
sleep_msec(20);
}
/*
* Utterance ended; flush any accumulated, unprocessed A/D data and stop
* listening until current utterance completely decoded
*/
ad_stop_rec(ad);
while (ad_read(ad, adbuf, 4096) >= 0);
cont_ad_reset(cont);
fflush(stdout);
/* Finish decoding, obtain and print result */
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL, &uttid);
fflush(stdout);
/* Exit if the first word spoken was GOODBYE */
//actually, for unity, exit if any word was spoken at all! this will avoid an infinite loop of doom!
if (hyp) {
/*sscanf(hyp, "%s", words);
if (strcmp(word, "goodbye") == 0)*/
break;
}
else
return "nothing returned";
/* Resume A/D recording for next utterance */
if (ad_start_rec(ad) < 0)
E_FATAL("Failed to start recording\n");
}
cont_ad_close(cont);
ad_close(ad);
ps_free(ps);
const char *temp = new char[1024];
temp = MakeStringCopy(hyp);
return temp;}
如果改变返回温度;在这里返回“一些字符串”;然后我看到文本出现在Unity内部。但是,这没有用,因为我不需要硬编码文本,我需要语音识别代码的输出,最终会存储在hyp变量中。
任何人都可以帮我弄清楚我做错了什么吗?谢谢!
答案 0 :(得分:3)
问题是你不应该在C ++中分配原始内存并以C#方式使用它,谁会去掉你在函数MakeStringCopy
中分配的内存?
尝试这样的事情:
[DllImport("MyLibrary.dll")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetStringValue();
通过这种方式,你告诉编组人员CLR拥有调用该函数后产生的内存,它将负责解除分配。
此外,.Net strings contain unicode chars,这就是为什么在尝试为其分配ANSI字符时出现访问冲突错误的原因。使用属性UnmanagedType.LPStr
还告诉封送程序它应该期望的字符类型,以便它可以为您进行转换。
最后,对于C ++方面的内存分配,根据this sample in MSDN,您应该在函数CoTaskMemAlloc
中使用函数malloc
而不是MakeStringCopy
。
答案 1 :(得分:2)
终于搞定了!我最终不得不将一个stringbuilder对象传递给C ++函数,并从C#中获取该对象的字符串,就像我在这篇文章中找到的那样: http://www.pcreview.co.uk/forums/passing-and-retrieving-string-calling-c-function-c-t1367069.html
代码比我想要的慢,但至少它现在有效。这是我的最终代码:
C#:
[DllImport ("pocketsphinx_unity",CallingConvention=CallingConvention.Cdecl,CharSet = CharSet.Ansi)]
private static extern void recognize_from_microphone(StringBuilder str);StringBuilder mytext= new StringBuilder(1000);
recognize_from_microphone(mytext);
print("you just said " + mytext.ToString());
C ++:
extern __declspec(dllexport) void recognize_from_microphone(char * fromUnity){
static ps_decoder_t *ps;
static cmd_ln_t *config;
config = cmd_ln_init(NULL, ps_args(), TRUE,
"-hmm", MODELDIR "\\hmm\\en_US\\hub4wsj_sc_8k",
"-lm", MODELDIR "\\lm\\en\\turtle.DMP",
"-dict", MODELDIR "\\lm\\en\\turtle.dic",
NULL);
if (config == NULL)
{
//return "config is null";
}
ps = ps_init(config);
if (ps == NULL)
{
//return "ps is null";
}
ad_rec_t *ad;
int16 adbuf[4096];
int32 k, ts, rem;
char const *hyp;
char const *uttid;
cont_ad_t *cont;
//char word[256];
char * temp;
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
(int)cmd_ln_float32_r(config, "-samprate"))) == NULL)
printf("Failed to open audio device\n");
/* Initialize continuous listening module */
if ((cont = cont_ad_init(ad, ad_read)) == NULL)
printf("Failed to initialize voice activity detection\n");
if (ad_start_rec(ad) < 0)
printf("Failed to start recording\n");
if (cont_ad_calib(cont) < 0)
printf("Failed to calibrate voice activity detection\n");
for (;;) {
/* Indicate listening for next utterance */
//printf("READY....\n");
fflush(stdout);
fflush(stderr);
/* Wait data for next utterance */
while ((k = cont_ad_read(cont, adbuf, 4096)) == 0)
sleep_msec(100);
if (k < 0)
printf("Failed to read audio\n");
/*
* Non-zero amount of data received; start recognition of new utterance.
* NULL argument to uttproc_begin_utt => automatic generation of utterance-id.
*/
if (ps_start_utt(ps, NULL) < 0)
printf("Failed to start utterance\n");
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
//printf("Listening...\n");
fflush(stdout);
/* Note timestamp for this first block of data */
ts = cont->read_ts;
/* Decode utterance until end (marked by a "long" silence, >1sec) */
for (;;) {
/* Read non-silence audio data, if any, from continuous listening module */
if ((k = cont_ad_read(cont, adbuf, 4096)) < 0)
printf("Failed to read audio 2nd\n");
if (k == 0) {
/*
* No speech data available; check current timestamp with most recent
* speech to see if more than 1 sec elapsed. If so, end of utterance.
*/
if ((cont->read_ts - ts) > DEFAULT_SAMPLES_PER_SEC)
break;
}
else {
/* New speech data received; note current timestamp */
ts = cont->read_ts;
}
/*
* Decode whatever data was read above.
*/
rem = ps_process_raw(ps, adbuf, k, FALSE, FALSE);
/* If no work to be done, sleep a bit */
if ((rem == 0) && (k == 0))
sleep_msec(20);
}
/*
* Utterance ended; flush any accumulated, unprocessed A/D data and stop
* listening until current utterance completely decoded
*/
ad_stop_rec(ad);
while (ad_read(ad, adbuf, 4096) >= 0);
cont_ad_reset(cont);
fflush(stdout);
/* Finish decoding, obtain and print result */
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL, &uttid);
fflush(stdout);
/* Exit if the first word spoken was GOODBYE */
//actually, for unity, exit if any word was spoken at all! this will avoid an infinite loop of doom!
if (hyp) {
strcpy(fromUnity,hyp);
break;
}
else
//return "nothing returned";
/* Resume A/D recording for next utterance */
if (ad_start_rec(ad) < 0)
printf("Failed to start recording\n");
}
cont_ad_close(cont);
ad_close(ad);
ps_free(ps);
}