C 创建一个wav。来自MIDI文件的文件,并将其提供给NWEB
我正在尝试向nweb添加一个功能,允许它将MIDI.mid文件渲染为.wav声音文件,以便浏览器(如带有内置.wav播放器的Chrome)可以播放这些文件。我有nweb,但除此之外,我完全被难住了。谢谢你的帮助C 创建一个wav。来自MIDI文件的文件,并将其提供给NWEB,c,server,wav,midi,C,Server,Wav,Midi,我正在尝试向nweb添加一个功能,允许它将MIDI.mid文件渲染为.wav声音文件,以便浏览器(如带有内置.wav播放器的Chrome)可以播放这些文件。我有nweb,但除此之外,我完全被难住了。谢谢你的帮助 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include &l
#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);
}
}
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义BUFSIZE 8096
#定义错误42
#定义抱歉43
#定义日志44
结构{
字符*ext;
char*文件类型;
}扩展[]={
{“gif”,“image/gif”},
{“jpg”,“image/jpeg”},
{“jpeg”,“图像/jpeg”},
{“png”,“image/png”},
{“zip”,“image/zip”},
{“gz”,“image/gz},
{“tar”,“image/tar”},
{“htm”,“text/html”},
{“html”,“text/html”},
{“mp3”,“音乐/mp3”},
{0,0} };
无效日志(int类型,char*s1,char*s2,int num)
{
int-fd;
char logbuffer[BUFSIZE*2];
开关(类型){
案例错误:(void)sprintf(logbuffer,“错误:%s:%s Errno=%d退出pid=%d”,s1,s2,Errno,getpid());中断;
对不起:
(无效)sprintf(日志缓冲区,“nweb Web服务器抱歉:%s%s\r\n”,s1,s2);
(void)写入(num,logbuffer,strlen(logbuffer));
(void)sprintf(日志缓冲区,“对不起:%s:%s”,s1,s2);
打破
案例日志:(无效)sprintf(日志缓冲区,“信息:%s:%s:%d”,s1,s2,num);中断;
}
/*此处不进行检查,如果出现故障,则无法执行任何操作*/
如果((fd=open(“nweb.log”,O|u CREAT | O|u WRONLY | O|u APPEND,0644))>=0{
(void)写入(fd、logbuffer、strlen(logbuffer));
(无效)写入(fd,“\n”,1);
(无效)关闭(fd);
}
如果(type==ERROR | | type==SORRY)退出(3);
}
/*这是一个子web服务器进程,因此我们可以在出现错误时退出*/
无效web(整数fd,整数hit)
{
int j,文件,布弗伦,莱恩;
长i,ret;
char*fstr;
静态字符缓冲区[BUFSIZE+1];/*静态so零填充*/
ret=读取(fd、缓冲区、BUFSIZE);/*一次性读取Web请求*/
如果(ret==0 | | ret==1){/*读取失败立即停止*/
日志(抱歉,“无法读取浏览器请求”,“fd”);
}
如果(ret>0&&ret
可以使用以下内容渲染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);
#包括
// ...
流体设置*设置=新流体设置()
//渲染频率为44.1KHz。
流体设置(设置,“合成采样率”,44100);
流体合成*合成=新流体合成(设置)
//将音量设置为70%。音量过高可能会导致剪辑。
流体合成装置增益(合成,0.7f);
//插值的质量。这是高质量的。需要更多的CPU。
流体合成法(synth,-1,流体合成法);
//要使用的声音字体文件。
流体合成(合成,“soundfont.sf2”,真);
流体播放器=新的流体播放器(synth);
//加载MIDI文件。
流体播放器添加(播放器,“midi\u file.mid”);
//开始“播放”MIDI文件。这只是为MIDI文件做准备
//渲染时,它不会真正“播放”任何内容。
流体_播放器_播放(播放器);
注意:您可以使用fluid\u player\u add()
,而不是fluid\u player\u add\u mem()
,将MIDI字节馈送到FluidSync。这取决于您从源代码获取MIDI数据的方式
以上初始化并设置合成器和播放器。请注意,您需要一个soundfont文件(SF2格式),否则无法渲染任何内容。SF2文件包含各种MIDI乐器的音频数据。假设您的MIDI文件针对的是GM标准(通用MIDI),则需要找到GM soundfont(或者是一个GS字体;GS是GM的一个扩展,有更多的乐器,一些MIDI文件需要它。)有很多免费的SF2声音字体,大小不一(从2MB到几GB不等)
要实际进行渲染并获取音频数据,请调用fluid\u synth\u write\u float()
(对于浮点样本)或fluid\u synth\u write\u s16()
(对于整数样本)。然后,检查MIDI文件是否已结束使用fluid\u player\u get\u status()播放
获得音频样本后,您可以使用WAV格式提供,或者使用编码器(如libvorbis文件库)将样本压缩为Ogg/Vorbis音频。或者使用libmpg123提供MP3音频。Chrome和Firefox浏览器都有MIDI播放器插件可用。