2011-07-03 15 views
3

問題:爲了將一個C#接口寫入libespeak,我需要將回調SynthCallback轉換爲C#從C:fputc轉換並在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 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; 
} 

回答

3
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.GetBytesFileStream.Write也許BinaryWriter

+0

我很驚訝,第一次嘗試成功時,用BinaryWriter + BitConverter.GetBytes。 –

0

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

+0

這需要導出的功能,它不是,再加上從託管到非託管,託管回調,從那裏回到非託管代碼沒有意義... –

+0

@Quandary:好吧那麼你需要將IntPtr中的數據複製到一個簡短的[]中。 – Goz