从 C 转换:C# 中的 fputc 和 fwrite?

发布于 2024-11-18 09:55:15 字数 4102 浏览 2 评论 0原文

问题:为了编写 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,如何将数据写入文件?

换句话说:有人可以帮我将 fwritefputcWrite4Bytes 转换为正确的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

緦唸λ蓇 2024-11-25 09:55:15
FileStream sink;
Int32 SynthCallback(IntPtr wav, Int32 numsamples, IntPtr events)
{
    var wavm = new Int16[numsamples];
    Marshal.Copy(wav, wavm, 0, numsamples);
    // and do something with wavm

    //or
    var wavbytes = new Byte[numsamples * 2];
    Marshal.Copy(wav, wavbytes, 0, numsamples*2);
    sink.Write(wavbytes, 0, numsamples*2);
}

要写入 32 整数,您可以使用 BitConverter.GetBytes 和 FileStream.Write 或 BinaryWriter。

FileStream sink;
Int32 SynthCallback(IntPtr wav, Int32 numsamples, IntPtr events)
{
    var wavm = new Int16[numsamples];
    Marshal.Copy(wav, wavm, 0, numsamples);
    // and do something with wavm

    //or
    var wavbytes = new Byte[numsamples * 2];
    Marshal.Copy(wav, wavbytes, 0, numsamples*2);
    sink.Write(wavbytes, 0, numsamples*2);
}

For writing 32-integers, you can either use BitConverter.GetBytes and FileStream.Write or maybe BinaryWriter.

冷心人i 2024-11-25 09:55:15

您可以 P/Invoke CreateFile/WriteFile 直接写入 IntPtr。

You could P/Invoke CreateFile/WriteFile to write the IntPtr directly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文