📄 sndwrite.c
字号:
/* sndwrite.c -- write sounds to files *//* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */#include "stdlib.h"#include "switches.h"#include "string.h"#ifdef UNIX#include "sys/types.h"#endif#ifdef WINDOWS#include <io.h>#endif#include <stdio.h>/* include sound.h first because it includes math.h * which declares abs(). cext.h #defines abs()! * sound.h depends on xlisp.h */#include "xlisp.h"#include "sound.h"#include "cext.h"#include "userio.h"#include "falloc.h"#include "sndwrite.h"#include "extern.h"#include "snd.h"#ifdef UNIX#include "sys/file.h"/* #include <sys/stat.h>*/#include <netinet/in.h>#else#ifdef MACINTOSH#include <unistd.h>#include <stat.h>#define L_SET SEEK_SET#define L_INCR SEEK_CUR#endif#endif#define D if (0) int sndwrite_trace = 0; /* debugging */sample_type sound_save_sound(LVAL s_as_lval, long n, snd_type snd, char *buf, long *ntotal, snd_type player);sample_type sound_save_array(LVAL sa, long n, snd_type snd, char *buf, long *ntotal, snd_type player);unsigned char st_linear_to_ulaw(int sample);typedef struct { sound_type sound; long cnt; sample_block_values_type ptr; double scale; int terminated;} sound_state_node, *sound_state_type;LVAL prepare_audio(LVAL play, snd_type snd, snd_type player){ long flags; if (play == NIL) return NIL; player->format = snd->format; player->u.audio.devicename[0] = 0; player->u.audio.interfacename[0] = 0; if (snd_open(player, &flags) != SND_SUCCESS) { xlabort("snd_save -- could not open audio output"); } /* make sure player and snd are compatible -- if not, set player to NULL * and print a warning message */ if (player->format.channels == snd->format.channels && player->format.mode == snd->format.mode && player->format.bits == snd->format.bits) { /* ok so far, check out the sample rate */ if (player->format.srate != snd->format.srate) { char msg[100]; sprintf(msg, "%s(%g)%s(%g).\n", "Warning: file sample rate ", snd->format.srate, " differs from audio playback sample rate ", player->format.srate); stdputstr(msg); } } else { stdputstr("File format not supported by audio output.\n"); return NIL; } return play;}/* finish_audio -- flush the remaining samples, then close *//**/void finish_audio(snd_type player){ /* note that this is a busy loop! */ while (snd_flush(player) != SND_SUCCESS) ; snd_close(player);}/* write_to_audio -- handle audio output from buffer *//* * We want to write as soon as space is available so that * a full sound buffer can be queued up for output. This * may require transferring only part of buf, so we keep * track of progress and output whenever space is available. */void write_to_audio(snd_type player, void *buf, long buflen){ long rslt; while (buflen) { /* this loop is a busy-wait loop! */ rslt = snd_poll(player); /* wait for buffer space */ rslt = min(rslt, buflen); if (rslt) { snd_write(player, buf, rslt); buf = (void *) ((char *) buf + (rslt * snd_bytes_per_frame(player))); buflen -= rslt; } } }double sound_save( LVAL snd_expr, long n, unsigned char *filename, long format, long mode, long bits, long swap, double *sr, long *nchans, double *duration, LVAL play){ LVAL result; char *buf; long ntotal; double max_sample; snd_node snd; snd_node player; long flags; snd.device = SND_DEVICE_FILE; snd.write_flag = SND_WRITE; strcpy(snd.u.file.filename, (char *) filename); snd.u.file.file = -1; /* this is a marker that snd is unopened */ snd.u.file.header = format; snd.format.mode = mode; snd.format.bits = bits; snd.u.file.swap = swap; player.device = SND_DEVICE_AUDIO; player.write_flag = SND_WRITE; player.u.audio.devicename[0] = '\0'; player.u.audio.descriptor = NULL; player.u.audio.protocol = SND_COMPUTEAHEAD; player.u.audio.latency = 1.0; player.u.audio.granularity = 0.0; if ((buf = (char *) malloc(max_sample_block_len * MAX_SND_CHANNELS * sizeof(float))) == NULL) { xlabort("snd_save -- couldn't allocate memory"); } result = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE RESULT IS UNPROTECTED */ if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); *nchans = snd.format.channels = i; while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { xlerror("sound_save: array has non-sound element", result); } } /* assume all are the same: */ *sr = snd.format.srate = getsound(getelement(result, 0))->sr; /* note: if filename is "", then don't write file; therefore, * write the file if (filename[0]) */ if (filename[0] && snd_open(&snd, &flags) != SND_SUCCESS) { xlabort("snd_save -- could not open sound file"); } play = prepare_audio(play, &snd, &player); max_sample = sound_save_array(result, n, &snd, buf, &ntotal, (play == NIL ? NULL : &player)); *duration = ntotal / *sr; if (filename[0]) snd_close(&snd); if (play != NIL) finish_audio(&player); } else if (exttypep(result, a_sound)) { *nchans = snd.format.channels = 1; *sr = snd.format.srate = (getsound(result))->sr; if (filename[0] && snd_open(&snd, &flags) != SND_SUCCESS) { xlabort("snd_save -- could not open sound file"); } play = prepare_audio(play, &snd, &player); max_sample = sound_save_sound(result, n, &snd, buf, &ntotal, (play == NIL ? NULL : &player)); *duration = ntotal / *sr; if (filename[0]) snd_close(&snd); if (play != NIL) finish_audio(&player); } else { xlerror("sound_save: expression did not return a sound", result); max_sample = 0.0; } free(buf); return max_sample;}double sound_overwrite( LVAL snd_expr, long n, unsigned char *filename, long byte_offset, long header, long mode, long bits, long swap, double sr, long nchans, double *duration){ LVAL result; char *buf; char error[140]; long ntotal; double max_sample; snd_node snd; long flags; snd.device = SND_DEVICE_FILE; snd.write_flag = SND_OVERWRITE; strcpy(snd.u.file.filename, (char *) filename); snd.u.file.header = header; snd.u.file.byte_offset = byte_offset; snd.format.channels = nchans; snd.format.mode = mode; snd.format.bits = bits; snd.u.file.swap = swap; snd.format.srate = sr; if ((buf = (char *) malloc(max_sample_block_len * MAX_SND_CHANNELS * sizeof(float))) == NULL) { xlabort("snd_overwrite: couldn't allocate memory"); } if (snd_open(&snd, &flags) != SND_SUCCESS) { sprintf(error, "snd_overwrite: cannot open file %s and seek to %d", filename, (int)byte_offset); free(buf); xlabort(error); } result = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE RESULT IS UNPROTECTED */ if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); if (nchans != i) { sprintf(error, "%s%d%s%d%s", "snd_overwrite: number of channels in sound (", (int)i, ") does not match\n number of channels in file (", (int)nchans, ")"); free(buf); snd_close(&snd); xlabort(error); } while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { free(buf); snd_close(&snd); xlerror("sound_save: array has non-sound element", result); } } /* assume all are the same: */ if (sr != getsound(getelement(result, 0))->sr) { sprintf(error, "%s%g%s%g%s", "snd_overwrite: sample rate in sound (", getsound(getelement(result, 0))->sr, ") does not match\n sample rate in file (", sr, ")"); free(buf); snd_close(&snd); xlabort(error); } max_sample = sound_save_array(result, n, &snd, buf, &ntotal, NULL); *duration = ntotal / sr; } else if (exttypep(result, a_sound)) { if (nchans != 1) { sprintf(error, "%s%s%d%s", "snd_overwrite: number of channels in sound (1", ") does not match\n number of channels in file (", (int)nchans, ")");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -