Преобразование из C: fputc и fwrite в C #? - PullRequest
2 голосов
/ 03 июля 2011

Вопрос: Чтобы написать C# интерфейс для libespeak, мне нужно преобразовать обратный вызов SynthCallback в C#.

См. Ниже C код.
Вам может понадобиться это для справки:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
http://www -mmsp.ece.mcgill.ca / документы / Аудиоформаты / волна / 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 to a 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;
}

Ответы [ 2 ]

2 голосов
/ 03 июля 2011
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.

0 голосов
/ 03 июля 2011

Вы можете P / Invoke CreateFile / WriteFile, чтобы написать IntPtr напрямую.

...