从 C 转换:C# 中的 fputc 和 fwrite?
问题:为了编写 libespeak 的 C#
接口,我需要将回调 SynthCallback
转换为 C#
。
请参阅下面的 C
代码。
您可能需要这个作为参考:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
http://www-mmsp.ece.mcgill.ca/documents /audioformats/wave/wave.html
基本上
espeak_initialize
espeak_SetSynthCallback(SynthCallback);
espeak_SetParameter(espeakRATE, 510, 0);
espeak_Synth(".", 20, 0, POS_CHARACTER, 0, 0, NULL, NULL);
都是DllImport-ed函数。 我已经让它们异步工作,无需文件。
现在我想让同步版本处理文件,但我有一个小问题:
回调函数
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
首先,我需要创建一个委托,以便我可以将此函数传递给 C
dll/so 。 这不是问题,但如果我将 short *wav 设为 System.IntPtr
,如何将数据写入文件?
换句话说:有人可以帮我将 fwrite
、fputc
、Write4Bytes
转换为正确的 C#
吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <espeak/speak_lib.h>
// gcc -o mine speak.cpp -I/usr/include/espeak/ -lespeak
FILE *f_wavfile = NULL;
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events);
// Write 4 bytes to a file, least significant first
static void Write4Bytes(FILE *f, int value)
{
int ix;
for(ix=0; ix<4; ix++)
{
fputc(value & 0xff,f);
value = value >> 8;
}
}
int OpenWavFile(char *path, int rate)
{
static unsigned char wave_hdr[44] = {
'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f
};
if(path == NULL)
return(2);
if(path[0] == 0)
return(0);
if(strcmp(path,"stdout")==0)
f_wavfile = stdout;
else
f_wavfile = fopen(path,"wb");
if(f_wavfile == NULL)
{
fprintf(stderr,"Can't write to: '%s'\n",path);
return(1);
}
fwrite(wave_hdr, 1, 24, f_wavfile);
Write4Bytes(f_wavfile, rate);
Write4Bytes(f_wavfile, rate * 2);
fwrite(&wave_hdr[32], 1, 12, f_wavfile);
return(0);
} // end of OpenWavFile
static void CloseWavFile()
{
unsigned int pos;
if((f_wavfile==NULL) || (f_wavfile == stdout))
return;
fflush(f_wavfile);
pos = ftell(f_wavfile);
fseek(f_wavfile, 4, SEEK_SET);
Write4Bytes(f_wavfile, pos - 8);
fseek(f_wavfile, 40, SEEK_SET);
Write4Bytes(f_wavfile, pos - 44);
fclose(f_wavfile);
} // end of CloseWavFile
int main()
{
char buf[22050];
int i = 0;
memset(&buf, 0, sizeof(buf));
// OpenWavFile((char*) "test.wav", 22050);
int SampleRate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 300, NULL, 0);
OpenWavFile((char*) "test.wav", SampleRate);
espeak_SetSynthCallback(SynthCallback);
//espeak_SetParameter(espeakRATE, 510, 0);
//espeak_SetParameter(espeakRANGE, 75, 0);
for (i=0; i < 9;i++)
{
/*
espeak_ERROR espeak_Synth(
const void *text,
size_t size,
unsigned int position,
espeak_POSITION_TYPE position_type,
unsigned int end_position,
unsigned int flags,
unsigned int* unique_identifier,
void* user_data);
*/
//espeak_POSITION_TYPE.POS_CHARACTER
espeak_Synth("test", 10, 0, POS_CHARACTER, 0, 0, NULL, NULL);
fwrite(buf, 1, 5512, f_wavfile);
espeak_Synth(".", 20, 0, POS_CHARACTER, 0, 0, NULL, NULL);
fwrite(buf, 1, 22050, f_wavfile);
}
CloseWavFile();
}
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
{
if (wav == NULL)
return 0;
if (numsamples > 0)
{
fwrite(wav, numsamples * 2, 1, f_wavfile);
}
return 0;
}
Question: In order to write a C#
interface to libespeak, I need to convert the callback SynthCallback
to C#
.
See the below C
code.
You might need this for reference:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html
Basically,
espeak_initialize
espeak_SetSynthCallback(SynthCallback);
espeak_SetParameter(espeakRATE, 510, 0);
espeak_Synth(".", 20, 0, POS_CHARACTER, 0, 0, NULL, NULL);
are DllImport-ed function.
And I already have them working asynchronously, without file.
Now I want to get the synchronous version working with files, but I have a little problem:
The callback function
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
First, I need to create a delegate for that I can pass this function to the C
dll/so.
Which isn't a problem, but if I make short *wav to a System.IntPtr
, how do I write the data to a file ?
In other words: Can somebody help me with fwrite
, fputc
, Write4Bytes
converting this into proper C#
?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <espeak/speak_lib.h>
// gcc -o mine speak.cpp -I/usr/include/espeak/ -lespeak
FILE *f_wavfile = NULL;
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events);
// Write 4 bytes to a file, least significant first
static void Write4Bytes(FILE *f, int value)
{
int ix;
for(ix=0; ix<4; ix++)
{
fputc(value & 0xff,f);
value = value >> 8;
}
}
int OpenWavFile(char *path, int rate)
{
static unsigned char wave_hdr[44] = {
'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f
};
if(path == NULL)
return(2);
if(path[0] == 0)
return(0);
if(strcmp(path,"stdout")==0)
f_wavfile = stdout;
else
f_wavfile = fopen(path,"wb");
if(f_wavfile == NULL)
{
fprintf(stderr,"Can't write to: '%s'\n",path);
return(1);
}
fwrite(wave_hdr, 1, 24, f_wavfile);
Write4Bytes(f_wavfile, rate);
Write4Bytes(f_wavfile, rate * 2);
fwrite(&wave_hdr[32], 1, 12, f_wavfile);
return(0);
} // end of OpenWavFile
static void CloseWavFile()
{
unsigned int pos;
if((f_wavfile==NULL) || (f_wavfile == stdout))
return;
fflush(f_wavfile);
pos = ftell(f_wavfile);
fseek(f_wavfile, 4, SEEK_SET);
Write4Bytes(f_wavfile, pos - 8);
fseek(f_wavfile, 40, SEEK_SET);
Write4Bytes(f_wavfile, pos - 44);
fclose(f_wavfile);
} // end of CloseWavFile
int main()
{
char buf[22050];
int i = 0;
memset(&buf, 0, sizeof(buf));
// OpenWavFile((char*) "test.wav", 22050);
int SampleRate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 300, NULL, 0);
OpenWavFile((char*) "test.wav", SampleRate);
espeak_SetSynthCallback(SynthCallback);
//espeak_SetParameter(espeakRATE, 510, 0);
//espeak_SetParameter(espeakRANGE, 75, 0);
for (i=0; i < 9;i++)
{
/*
espeak_ERROR espeak_Synth(
const void *text,
size_t size,
unsigned int position,
espeak_POSITION_TYPE position_type,
unsigned int end_position,
unsigned int flags,
unsigned int* unique_identifier,
void* user_data);
*/
//espeak_POSITION_TYPE.POS_CHARACTER
espeak_Synth("test", 10, 0, POS_CHARACTER, 0, 0, NULL, NULL);
fwrite(buf, 1, 5512, f_wavfile);
espeak_Synth(".", 20, 0, POS_CHARACTER, 0, 0, NULL, NULL);
fwrite(buf, 1, 22050, f_wavfile);
}
CloseWavFile();
}
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
{
if (wav == NULL)
return 0;
if (numsamples > 0)
{
fwrite(wav, numsamples * 2, 1, f_wavfile);
}
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
要写入 32 整数,您可以使用 BitConverter.GetBytes 和 FileStream.Write 或 BinaryWriter。
For writing 32-integers, you can either use
BitConverter.GetBytes
andFileStream.Write
or maybeBinaryWriter
.您可以 P/Invoke CreateFile/WriteFile 直接写入 IntPtr。
You could P/Invoke CreateFile/WriteFile to write the IntPtr directly.