簡體   English   中英

創建一個wav。 MIDI文件中的文件並將其提供給NWEB

[英]Create a wav. file from a MIDI file and serving it to NWEB

我正在嘗試向nweb添加一項功能,使它可以將MIDI .mid文件呈現為.wav聲音文件,以便具有內置.wav播放器的Chrome之類的瀏覽器可以播放它們。 我有nweb,但除此之外,我完全陷入了困境。 幫助將不勝感激!

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <fcntl.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 

#define BUFSIZE 8096 
#define ERROR 42 
#define SORRY 43 
#define LOG   44 

struct { 
    char *ext; 
    char *filetype; 
} extensions [] = { 
    {"gif", "image/gif" },   
    {"jpg", "image/jpeg"},  
    {"jpeg","image/jpeg"}, 
    {"png", "image/png" },   
    {"zip", "image/zip" },   
    {"gz",  "image/gz"  },   
    {"tar", "image/tar" },   
    {"htm", "text/html" },   
    {"html","text/html" },   
    {"mp3","music/mp3"}, 
    {0,0} }; 

void log(int type, char *s1, char *s2, int num) 
{ 
int fd ; 
char logbuffer[BUFSIZE*2]; 

switch (type) { 
case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid()); break; 
case SORRY:  
    (void)sprintf(logbuffer, "<HTML><BODY><H1>nweb Web Server Sorry: %s %s</H1></BODY></HTML>\r\n", s1, s2); 
    (void)write(num,logbuffer,strlen(logbuffer)); 
    (void)sprintf(logbuffer,"SORRY: %s:%s",s1, s2);  
    break; 
case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,num); break; 
}     
/* no checks here, nothing can be done a failure anyway */ 
if((fd = open("nweb.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) { 
    (void)write(fd,logbuffer,strlen(logbuffer));  
    (void)write(fd,"\n",1);       
    (void)close(fd); 
} 
if(type == ERROR || type == SORRY) exit(3); 
} 

/* this is a child web server process, so we can exit on errors */ 
void web(int fd, int hit) 
{ 
int j, file_fd, buflen, len; 
long i, ret; 
char * fstr; 
static char buffer[BUFSIZE+1]; /* static so zero filled */ 

ret =read(fd,buffer,BUFSIZE);     /* read Web request in one go */ 
if(ret == 0 || ret == -1) {    /* read failure stop now */ 
    log(SORRY,"failed to read browser request","",fd); 
} 
if(ret > 0 && ret < BUFSIZE)    /* return code is valid chars */ 
    buffer[ret]=0;        /* terminate the buffer */ 
else buffer[0]=0; 

for(i=0;i<ret;i++)    /* remove CF and LF characters */ 
    if(buffer[i] == '\r' || buffer[i] == '\n') 
        buffer[i]='*'; 
log(LOG,"request",buffer,hit); 

if( strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4) ) 
    log(SORRY,"Only simple GET operation supported",buffer,fd); 

for(i=4;i<BUFSIZE;i++) { /* null terminate after the second space to ignore extra stuff */ 
    if(buffer[i] == ' ') { /* string is "GET URL " +lots of other stuff */ 
        buffer[i] = 0; 
        break; 
    } 
} 

for(j=0;j<i-1;j++)     /* check for illegal parent directory use .. */ 
    if(buffer[j] == '.' && buffer[j+1] == '.') 
        log(SORRY,"Parent directory (..) path names not supported",buffer,fd); 

if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) ) /* convert no filename to index file */ 
    (void)strcpy(buffer,"GET /index.html"); 

/* work out the file type and check we support it */ 
buflen=strlen(buffer); 
fstr = (char *)0; 
for(i=0;extensions[i].ext != 0;i++) { 
    len = strlen(extensions[i].ext); 
    if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) { 
        fstr =extensions[i].filetype; 
        break; 
    } 
} 
if(fstr == 0) log(SORRY,"file extension type not supported",buffer,fd); 

if(( file_fd = open(&buffer[5],O_RDONLY)) == -1) /* open the file for reading */ 
    log(SORRY, "failed to open file",&buffer[5],fd); 

log(LOG,"SEND",&buffer[5],hit); 

(void)sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr); 
(void)write(fd,buffer,strlen(buffer)); 

/* send file in 8KB block - last block may be smaller */ 
while (    (ret = read(file_fd, buffer, BUFSIZE)) > 0 ) { 
    (void)write(fd,buffer,ret); 
} 
#ifdef LINUX 
sleep(1);    /* to allow socket to drain */ 
#endif 
exit(1); 
} 


int main(int argc, char **argv) 
{ 
int i, port, pid, listenfd, socketfd, hit; 
size_t length; 
static struct sockaddr_in cli_addr; /* static = initialised to zeros */ 
static struct sockaddr_in serv_addr; /* static = initialised to zeros */ 

if( argc < 3  || argc > 3 || !strcmp(argv[1], "-?") ) { 
    (void)printf("hint: nweb Port-Number Top-Directory\n\n" 
"\tnweb is a small and very safe mini web server\n" 
"\tnweb only servers out file/web pages with extensions named below\n" 
"\t and only from the named directory or its sub-directories.\n" 
"\tThere is no fancy features = safe and secure.\n\n" 
"\tExample: nweb 8181 /home/nwebdir &\n\n" 
"\tOnly Supports:"); 
    for(i=0;extensions[i].ext != 0;i++) 
        (void)printf(" %s",extensions[i].ext); 

    (void)printf("\n\tNot Supported: URLs including \"..\", Java, Javascript, CGI\n" 
"\tNot Supported: directories / /etc /bin /lib /tmp /usr /dev /sbin \n" 
"\tNo warranty given or implied\n\tNigel Griffiths nag@uk.ibm.com\n" 
        ); 
    exit(0); 
} 
if( !strncmp(argv[2],"/"   ,2 ) || !strncmp(argv[2],"/etc", 5 ) || 
    !strncmp(argv[2],"/bin",5 ) || !strncmp(argv[2],"/lib", 5 ) || 
    !strncmp(argv[2],"/tmp",5 ) || !strncmp(argv[2],"/usr", 5 ) || 
    !strncmp(argv[2],"/dev",5 ) || !strncmp(argv[2],"/sbin",6) ){ 
    (void)printf("ERROR: Bad top directory %s, see nweb -?\n",argv[2]); 
    exit(3); 
} 
if(chdir(argv[2]) == -1){  
    (void)printf("ERROR: Can't Change to directory %s\n",argv[2]); 
    exit(4); 
} 

/* Become daemon + unstoppable and no zombies children (= no wait()) */ 
if(fork() != 0) 
    return 0; /* parent returns OK to shell */ 
(void)signal(SIGCLD, SIG_IGN); /* ignore child death */ 
(void)signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */ 
for(i=0;i<32;i++) 
    (void)close(i);        /* close open files */ 
(void)setpgrp();        /* break away from process group */ 

log(LOG,"nweb starting",argv[1],getpid()); 
/* setup the network socket */ 
if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) 
    log(ERROR, "system call","socket",0); 
port = atoi(argv[1]); 
if(port < 0 || port >60000) 
    log(ERROR,"Invalid port number (try 1->60000)",argv[1],0); 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
serv_addr.sin_port = htons(port); 
if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0) 
    log(ERROR,"system call","bind",0); 
if( listen(listenfd,64) <0) 
    log(ERROR,"system call","listen",0); 

for(hit=1; ;hit++) { 
    length = sizeof(cli_addr); 
    if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) 
        log(ERROR,"system call","accept",0); 

    if((pid = fork()) < 0) { 
        log(ERROR,"system call","fork",0); 
    } 
    else { 
        if(pid == 0) {     /* child */ 
            (void)close(listenfd); 
            web(socketfd,hit); /* never returns */ 
        } else {     /* parent */ 
            (void)close(socketfd); 
        } 
    } 
} 
} 

您可以使用FluidSynth( http://www.fluidsynth.org/ )。 它帶有一個C庫。 該API記錄在這里:

http://fluidsynth.sourceforge.net/api/

您可以使用以下方式渲染MIDI文件:

#include <fluidsynth.h>

// ...

fluid_settings_t* settings = new_fluid_settings()
// Render at 44.1KHz.
fluid_settings_setnum(settings, "synth.sample-rate", 44100);
fluid_synth_t* synth = new_fluid_synth(settings)
// Set volume to 70%. High volume levels may cause clipping.
fluid_synth_set_gain(synth, 0.7f);
// Quality of interpolation. This is high quality. Needs more CPU.
fluid_synth_set_interp_method(synth, -1, FLUID_INTERP_7THORDER);
// Which soundfont file to use.
fluid_synth_sfload(synth, "soundfont.sf2", true);
fluid_player_t* player = new_fluid_player(synth);
// Load a MIDI file.
fluid_player_add(player, "midi_file.mid");
// Start "playing" the MIDI file. This simply prepares the file for
// rendering, it doesn't really "play" anything.
fluid_player_play(player);

注:代替fluid_player_add()您可以使用fluid_player_add_mem()而不是喂MIDI字節來FluidSynth。 這取決於您如何從源中獲取MIDI數據。

上面的代碼初始化並設置了合成器和播放器。 請注意,您需要一個soundfont文件(SF2格式),否則您將無法呈現任何內容。 SF2文件包含各種MIDI樂器的音頻數據。 假設您的MIDI文件以GM標准(通用MIDI)為目標,您將需要找到GM音色(或GS音色; GS是GM的擴展,具有更多樂器,一些MIDI文件需要它。)有很多免費的SF2音色可用,大小不等(范圍從2MB到數GB不等。)

要實際進行渲染並獲取音頻數據,請調用fluid_synth_write_float() (對於浮點樣本)或fluid_synth_write_s16() (對於整數樣本)。 之后,使用fluid_player_get_status()檢查MIDI文件是否已結束播放。

獲得音頻樣本后,可以將它們以WAV格式提供,也可以使用編碼器(如libvorbisfile庫)將樣本壓縮為Ogg / Vorbis音頻。 或者,也許可以使用libmpg123來提供MP3音頻。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM