| 1 |
/* sound.c */ |
| 2 |
|
| 3 |
/* TODO: make this thread-safe by wrapping locks around the header/data base references */ |
| 4 |
|
| 5 |
#if defined(HAVE_CONFIG_H) |
| 6 |
#include "config.h" |
| 7 |
#endif |
| 8 |
|
| 9 |
#include <math.h> |
| 10 |
#include <stdio.h> |
| 11 |
#if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_FCNTL_H)) |
| 12 |
#include <fcntl.h> |
| 13 |
#endif |
| 14 |
#include <signal.h> |
| 15 |
#if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_LIMITS_H)) |
| 16 |
#include <limits.h> |
| 17 |
#endif |
| 18 |
#include <errno.h> |
| 19 |
#include <stdlib.h> |
| 20 |
|
| 21 |
#if (defined(NEXT) || (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H)))) |
| 22 |
#include <libc.h> |
| 23 |
#else |
| 24 |
#if (!(defined(_MSC_VER))) && (!(defined(MPW_C))) |
| 25 |
#include <unistd.h> |
| 26 |
#endif |
| 27 |
#if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_STRING_H)) |
| 28 |
#include <string.h> |
| 29 |
#endif |
| 30 |
#endif |
| 31 |
|
| 32 |
#include <ctype.h> |
| 33 |
#include <stddef.h> |
| 34 |
|
| 35 |
#include "sndlib.h" |
| 36 |
|
| 37 |
#if MACOS |
| 38 |
#if (!defined(MPW_C)) |
| 39 |
#include <time.h> |
| 40 |
#include <stat.h> |
| 41 |
#endif |
| 42 |
#else |
| 43 |
#include <sys/types.h> |
| 44 |
#include <sys/stat.h> |
| 45 |
#endif |
| 46 |
|
| 47 |
#include <stdarg.h> |
| 48 |
|
| 49 |
static int mus_error_tag = MUS_INITIAL_ERROR_TAG; |
| 50 |
int mus_make_error_tag(void) {return(mus_error_tag++);} |
| 51 |
static void (*mus_error_handler)(int err_type, char *err_msg); |
| 52 |
void mus_set_error_handler(void (*new_error_handler)(int err_type, char *err_msg)) {mus_error_handler = new_error_handler;} |
| 53 |
static char *mus_error_buffer = NULL; |
| 54 |
|
| 55 |
void mus_error(int error, char *format, ...) |
| 56 |
{ |
| 57 |
va_list ap; |
| 58 |
va_start(ap,format); |
| 59 |
vsprintf(mus_error_buffer,format,ap); |
| 60 |
va_end(ap); |
| 61 |
if (mus_error_handler) |
| 62 |
(*mus_error_handler)(error,mus_error_buffer); |
| 63 |
else fprintf(stderr,mus_error_buffer); |
| 64 |
} |
| 65 |
|
| 66 |
void mus_fwrite(int fd, char *format, ...) |
| 67 |
{ |
| 68 |
va_list ap; |
| 69 |
va_start(ap,format); |
| 70 |
vsprintf(mus_error_buffer,format,ap); |
| 71 |
va_end(ap); |
| 72 |
write(fd,mus_error_buffer,strlen(mus_error_buffer)); |
| 73 |
} |
| 74 |
|
| 75 |
static char *s_copy_string (char *str) |
| 76 |
{ |
| 77 |
char *newstr = NULL; |
| 78 |
if ((str) && (*str)) |
| 79 |
{ |
| 80 |
newstr = (char *)CALLOC(strlen(str)+1,sizeof(char)); |
| 81 |
strcpy(newstr,str); |
| 82 |
} |
| 83 |
return(newstr); |
| 84 |
} |
| 85 |
|
| 86 |
|
| 87 |
#ifndef MPW_C |
| 88 |
static time_t file_write_date(char *filename) |
| 89 |
{ |
| 90 |
struct stat statbuf; |
| 91 |
int err; |
| 92 |
err = stat(filename,&statbuf); |
| 93 |
if (err < 0) return(err); |
| 94 |
return((time_t)(statbuf.st_mtime)); |
| 95 |
} |
| 96 |
#else |
| 97 |
#include <Files.h> |
| 98 |
static int file_write_date(char *filename) |
| 99 |
{ |
| 100 |
#if 0 |
| 101 |
/* this isn't right... */ |
| 102 |
HParamBlockRec pb; |
| 103 |
FSSpec fs; |
| 104 |
FSMakeFSSpec(0,0,(unsigned char *)filename,&fs); |
| 105 |
pb.fileParam.ioVRefNum = fs.vRefNum; |
| 106 |
pb.fileParam.ioDirID = fs.parID; |
| 107 |
pb.fileParam.ioNamePtr = fs.name; |
| 108 |
PBHGetFInfo(&pb,FALSE); |
| 109 |
mus_error(0,"%s date: %d ",filename,pb.fileParam.ioFlMdDat); |
| 110 |
return(pb.fileParam.ioFlMdDat); |
| 111 |
#else |
| 112 |
return(1); |
| 113 |
#endif |
| 114 |
} |
| 115 |
#endif |
| 116 |
|
| 117 |
static int sndlib_initialized = 0; |
| 118 |
|
| 119 |
int initialize_sndlib(void) |
| 120 |
{ |
| 121 |
int err = 0; |
| 122 |
if (!sndlib_initialized) |
| 123 |
{ |
| 124 |
sndlib_initialized = 1; |
| 125 |
mus_error_buffer = (char *)CALLOC(256,sizeof(char)); |
| 126 |
if (mus_error_buffer == NULL) return(-1); |
| 127 |
err = mus_create_header_buffer(); |
| 128 |
if (err == 0) |
| 129 |
{ |
| 130 |
err = mus_create_descriptors(); |
| 131 |
if (err == 0) err = initialize_audio(); |
| 132 |
} |
| 133 |
if (err == -1) {FREE(mus_error_buffer); return(-1);} |
| 134 |
} |
| 135 |
return(0); |
| 136 |
} |
| 137 |
|
| 138 |
typedef struct { |
| 139 |
char *file_name; /* full path -- everything is keyed to this name */ |
| 140 |
int table_pos; |
| 141 |
int *aux_comment_start,*aux_comment_end; |
| 142 |
int *loop_modes,*loop_starts,*loop_ends; |
| 143 |
int markers; |
| 144 |
int *marker_ids,*marker_positions; |
| 145 |
int samples, datum_size, data_location, srate, chans, header_type, data_format, original_sound_format, true_file_length; |
| 146 |
int comment_start, comment_end, header_distributed, type_specifier, bits_per_sample, fact_samples, block_align; |
| 147 |
int write_date; |
| 148 |
int *max_amps; |
| 149 |
} sound_file; |
| 150 |
|
| 151 |
static int sound_table_size = 0; |
| 152 |
static sound_file **sound_table = NULL; |
| 153 |
|
| 154 |
static void free_sound_file(sound_file *sf) |
| 155 |
{ |
| 156 |
if (sf) |
| 157 |
{ |
| 158 |
sound_table[sf->table_pos] = NULL; |
| 159 |
if (sf->aux_comment_start) FREE(sf->aux_comment_start); |
| 160 |
if (sf->aux_comment_end) FREE(sf->aux_comment_end); |
| 161 |
if (sf->file_name) FREE(sf->file_name); |
| 162 |
if (sf->loop_modes) FREE(sf->loop_modes); |
| 163 |
if (sf->loop_starts) FREE(sf->loop_starts); |
| 164 |
if (sf->loop_ends) FREE(sf->loop_ends); |
| 165 |
if (sf->marker_ids) FREE(sf->marker_ids); |
| 166 |
if (sf->marker_positions) FREE(sf->marker_positions); |
| 167 |
if (sf->max_amps) FREE(sf->max_amps); |
| 168 |
FREE(sf); |
| 169 |
} |
| 170 |
} |
| 171 |
|
| 172 |
static sound_file *add_to_sound_table(void) |
| 173 |
{ |
| 174 |
int i,pos; |
| 175 |
#ifdef MACOS |
| 176 |
sound_file **ptr; |
| 177 |
#endif |
| 178 |
pos = -1; |
| 179 |
for (i=0;i<sound_table_size;i++) |
| 180 |
if (sound_table[i] == NULL) |
| 181 |
{ |
| 182 |
pos = i; |
| 183 |
break; |
| 184 |
} |
| 185 |
if (pos == -1) |
| 186 |
{ |
| 187 |
pos = sound_table_size; |
| 188 |
sound_table_size += 16; |
| 189 |
if (sound_table == NULL) |
| 190 |
sound_table = (sound_file **)CALLOC(sound_table_size,sizeof(sound_file *)); |
| 191 |
else |
| 192 |
{ |
| 193 |
#ifdef MACOS |
| 194 |
ptr = (sound_file **)CALLOC(sound_table_size,sizeof(sound_file *)); |
| 195 |
for (i=0;i<pos;i++) ptr[i] = sound_table[i]; |
| 196 |
FREE(sound_table); |
| 197 |
sound_table = ptr; |
| 198 |
#else |
| 199 |
sound_table = (sound_file **)REALLOC(sound_table,sound_table_size * sizeof(sound_file *)); |
| 200 |
#endif |
| 201 |
for (i=pos;i<sound_table_size;i++) sound_table[i] = NULL; |
| 202 |
} |
| 203 |
} |
| 204 |
sound_table[pos] = (sound_file *)CALLOC(1,sizeof(sound_file)); |
| 205 |
sound_table[pos]->table_pos = pos; |
| 206 |
return(sound_table[pos]); |
| 207 |
} |
| 208 |
|
| 209 |
static void re_read_raw_header(sound_file *sf) |
| 210 |
{ |
| 211 |
int chan,data_size; |
| 212 |
chan = mus_open_read(sf->file_name); |
| 213 |
data_size = lseek(chan,0L,SEEK_END); |
| 214 |
sf->true_file_length = data_size; |
| 215 |
sf->samples = mus_bytes2samples(sf->data_format,data_size); |
| 216 |
close(chan); |
| 217 |
} |
| 218 |
|
| 219 |
int forget_sound(char *name) |
| 220 |
{ |
| 221 |
int i; |
| 222 |
for (i=0;i<sound_table_size;i++) |
| 223 |
{ |
| 224 |
if (sound_table[i]) |
| 225 |
{ |
| 226 |
if (strcmp(name,sound_table[i]->file_name) == 0) |
| 227 |
{ |
| 228 |
free_sound_file(sound_table[i]); |
| 229 |
return(0); |
| 230 |
} |
| 231 |
} |
| 232 |
} |
| 233 |
return(-1); |
| 234 |
} |
| 235 |
|
| 236 |
static sound_file *find_sound_file(char *name) |
| 237 |
{ |
| 238 |
int i,date; |
| 239 |
sound_file *sf; |
| 240 |
for (i=0;i<sound_table_size;i++) |
| 241 |
{ |
| 242 |
if (sound_table[i]) |
| 243 |
{ |
| 244 |
if (strcmp(name,sound_table[i]->file_name) == 0) |
| 245 |
{ |
| 246 |
sf = sound_table[i]; |
| 247 |
date = file_write_date(name); |
| 248 |
if (date == sf->write_date) |
| 249 |
return(sf); |
| 250 |
else |
| 251 |
{ |
| 252 |
if (sf->header_type == raw_sound_file) |
| 253 |
{ |
| 254 |
/* sound has changed since we last read it, but it has no header, so |
| 255 |
* the only sensible thing to check is the new length (i.e. caller |
| 256 |
* has set other fields by hand) |
| 257 |
*/ |
| 258 |
sf->write_date = date; |
| 259 |
re_read_raw_header(sf); |
| 260 |
return(sf); |
| 261 |
} |
| 262 |
free_sound_file(sf); |
| 263 |
return(NULL); |
| 264 |
} |
| 265 |
} |
| 266 |
} |
| 267 |
} |
| 268 |
return(NULL); |
| 269 |
} |
| 270 |
|
| 271 |
static void fill_sf_record(sound_file *sf) |
| 272 |
{ |
| 273 |
sf->data_location = mus_header_data_location(); |
| 274 |
sf->samples = mus_header_samples(); |
| 275 |
sf->data_format = mus_header_format(); |
| 276 |
sf->srate = mus_header_srate(); |
| 277 |
sf->chans = mus_header_chans(); |
| 278 |
sf->datum_size = mus_header_format2bytes(); |
| 279 |
sf->header_type = mus_header_type(); |
| 280 |
sf->original_sound_format = mus_header_original_format(); |
| 281 |
sf->true_file_length = mus_true_file_length(); |
| 282 |
sf->comment_start = mus_header_comment_start(); |
| 283 |
sf->comment_end = mus_header_comment_end(); |
| 284 |
sf->header_distributed = mus_header_distributed(); |
| 285 |
sf->type_specifier = mus_header_type_specifier(); |
| 286 |
sf->bits_per_sample = mus_header_bits_per_sample(); |
| 287 |
sf->fact_samples = mus_header_fact_samples(); |
| 288 |
sf->block_align = mus_header_block_align(); |
| 289 |
sf->write_date = file_write_date(sf->file_name); |
| 290 |
/* loop points and aux comments */ |
| 291 |
} |
| 292 |
|
| 293 |
static sound_file *read_sound_file_header_with_fd(int fd, char *arg) |
| 294 |
{ |
| 295 |
int err=0; |
| 296 |
sound_file *sf = NULL; |
| 297 |
initialize_sndlib(); |
| 298 |
err = mus_read_header_with_fd(fd); |
| 299 |
if (err == -1) return(NULL); |
| 300 |
sf = add_to_sound_table(); |
| 301 |
sf->file_name = s_copy_string(arg); |
| 302 |
fill_sf_record(sf); |
| 303 |
return(sf); |
| 304 |
} |
| 305 |
|
| 306 |
static sound_file *read_sound_file_header_with_name(char *name) |
| 307 |
{ |
| 308 |
sound_file *sf = NULL; |
| 309 |
initialize_sndlib(); |
| 310 |
if (mus_read_header(name) != -1) |
| 311 |
{ |
| 312 |
sf = add_to_sound_table(); |
| 313 |
sf->file_name = s_copy_string(name); |
| 314 |
fill_sf_record(sf); |
| 315 |
} |
| 316 |
return(sf); |
| 317 |
} |
| 318 |
|
| 319 |
static sound_file *getsf(char *arg) |
| 320 |
{ |
| 321 |
sound_file *sf = NULL; |
| 322 |
if ((sf = find_sound_file(arg)) == NULL) |
| 323 |
{ |
| 324 |
sf = read_sound_file_header_with_name(arg); |
| 325 |
if (sf == NULL) set_audio_error(SNDLIB_CANT_OPEN); |
| 326 |
} |
| 327 |
return(sf); |
| 328 |
} |
| 329 |
|
| 330 |
int sound_samples (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->samples); else return(-1);} |
| 331 |
int sound_frames (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->samples / sf->chans); else return(-1);} |
| 332 |
int sound_datum_size (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->datum_size); else return(-1);} |
| 333 |
int sound_data_location (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->data_location); else return(-1);} |
| 334 |
int sound_chans (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->chans); else return(-1);} |
| 335 |
int sound_srate (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->srate); else return(-1);} |
| 336 |
int sound_header_type (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->header_type); else return(-1);} |
| 337 |
int sound_data_format (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->data_format); else return(-1);} |
| 338 |
int sound_original_format (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->original_sound_format); else return(-1);} |
| 339 |
int sound_comment_start (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->comment_start); else return(-1);} |
| 340 |
int sound_comment_end (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->comment_end); else return(-1);} |
| 341 |
int sound_length (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->true_file_length); else return(-1);} |
| 342 |
int sound_fact_samples (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->fact_samples); else return(-1);} |
| 343 |
int sound_distributed (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->header_distributed); else return(-1);} |
| 344 |
int sound_write_date (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->write_date); else return(-1);} |
| 345 |
int sound_type_specifier (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->type_specifier); else return(-1);} |
| 346 |
int sound_align (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->block_align); else return(-1);} |
| 347 |
int sound_bits_per_sample (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->bits_per_sample); else return(-1);} |
| 348 |
float sound_duration(char *arg) {return((float)sound_frames(arg) / (float)sound_srate(arg));} |
| 349 |
|
| 350 |
int sound_aiff_p(char *arg) |
| 351 |
{ |
| 352 |
return(sound_header_type(arg) == AIFF_sound_file); |
| 353 |
} |
| 354 |
|
| 355 |
char *sound_comment(char *name) |
| 356 |
{ |
| 357 |
int start,end,fd,len; |
| 358 |
char *sc = NULL; |
| 359 |
start = sound_comment_start(name); |
| 360 |
end = sound_comment_end(name); |
| 361 |
if (end == 0) return(NULL); |
| 362 |
len = end-start+1; |
| 363 |
if (len>0) |
| 364 |
{ |
| 365 |
/* open and get the comment */ |
| 366 |
sc = (char *)CALLOC(len+1,sizeof(char)); /* len+1 calloc'd => we'll always have a trailing null */ |
| 367 |
#if MACOS |
| 368 |
fd = open(name,O_RDONLY); |
| 369 |
#else |
| 370 |
#ifdef WINDOZE |
| 371 |
fd = open(name,O_RDONLY | O_BINARY); |
| 372 |
#else |
| 373 |
fd = open(name,O_RDONLY,0); |
| 374 |
#endif |
| 375 |
#endif |
| 376 |
lseek(fd,start,SEEK_SET); |
| 377 |
read(fd,sc,len); |
| 378 |
close(fd); |
| 379 |
return(sc); |
| 380 |
} |
| 381 |
else return(NULL); |
| 382 |
} |
| 383 |
|
| 384 |
char *sound_type_name(int type) |
| 385 |
{ |
| 386 |
return(mus_header_type2string(type)); |
| 387 |
} |
| 388 |
|
| 389 |
char *sound_format_name(int format) |
| 390 |
{ |
| 391 |
return(mus_header_data_format2string(format)); |
| 392 |
} |
| 393 |
|
| 394 |
int sound_bytes_per_sample(int format) {return(mus_format2bytes(format));} |
| 395 |
|
| 396 |
typedef struct { |
| 397 |
int fd; |
| 398 |
char *name; |
| 399 |
} output_info; |
| 400 |
|
| 401 |
static output_info **header_names = NULL; |
| 402 |
static int header_names_size = 0; |
| 403 |
|
| 404 |
static void save_header_name(int fd, char *arg) |
| 405 |
{ |
| 406 |
int i,loc; |
| 407 |
#ifdef MACOS |
| 408 |
output_info **ptr; |
| 409 |
#endif |
| 410 |
loc = -1; |
| 411 |
for (i=0;i<header_names_size;i++) |
| 412 |
{ |
| 413 |
if (header_names[i] == NULL) |
| 414 |
{ |
| 415 |
loc = i; |
| 416 |
break; |
| 417 |
} |
| 418 |
} |
| 419 |
if (loc == -1) |
| 420 |
{ |
| 421 |
loc = header_names_size; |
| 422 |
header_names_size += 4; |
| 423 |
if (header_names == NULL) |
| 424 |
header_names = (output_info **)CALLOC(header_names_size,sizeof(output_info *)); |
| 425 |
else |
| 426 |
{ |
| 427 |
#ifdef MACOS |
| 428 |
ptr = (output_info **)CALLOC(header_names_size,sizeof(output_info *)); |
| 429 |
for (i=0;i<loc;i++) ptr[i] = header_names[i]; |
| 430 |
FREE(header_names); |
| 431 |
header_names = ptr; |
| 432 |
#else |
| 433 |
header_names = (output_info **)REALLOC(header_names,header_names_size * sizeof(output_info *)); |
| 434 |
#endif |
| 435 |
for (i=loc;i<header_names_size;i++) header_names[i] = NULL; |
| 436 |
} |
| 437 |
} |
| 438 |
header_names[loc] = (output_info *)CALLOC(1,sizeof(output_info)); |
| 439 |
header_names[loc]->fd = fd; |
| 440 |
header_names[loc]->name = s_copy_string(arg); |
| 441 |
} |
| 442 |
|
| 443 |
static void flush_header(int fd) |
| 444 |
{ |
| 445 |
int i,loc,val; |
| 446 |
sound_file *sf; |
| 447 |
loc = -1; |
| 448 |
val = -1; |
| 449 |
for (i=0;i<header_names_size;i++) |
| 450 |
{ |
| 451 |
if (header_names[i]) |
| 452 |
{ |
| 453 |
if (header_names[i]->fd == fd) |
| 454 |
{ |
| 455 |
loc = i; |
| 456 |
break; |
| 457 |
} |
| 458 |
} |
| 459 |
} |
| 460 |
if (loc != -1) |
| 461 |
{ |
| 462 |
if (header_names[loc]->name) |
| 463 |
{ |
| 464 |
sf = getsf(header_names[loc]->name); |
| 465 |
if (sf) sf->write_date = 0; /* force subsequent re-read */ |
| 466 |
FREE(header_names[loc]->name); |
| 467 |
header_names[loc]->name = NULL; |
| 468 |
} |
| 469 |
FREE(header_names[loc]); |
| 470 |
header_names[loc] = NULL; |
| 471 |
} |
| 472 |
} |
| 473 |
|
| 474 |
int open_sound_input (char *arg) |
| 475 |
{ |
| 476 |
int fd; |
| 477 |
sound_file *sf = NULL; |
| 478 |
set_audio_error(SNDLIB_NO_ERROR); |
| 479 |
initialize_sndlib(); |
| 480 |
fd = mus_open_read(arg); |
| 481 |
if (fd != -1) |
| 482 |
{ |
| 483 |
if ((sf = find_sound_file(arg)) == NULL) |
| 484 |
{ |
| 485 |
sf = read_sound_file_header_with_fd(fd,arg); |
| 486 |
} |
| 487 |
} |
| 488 |
if (sf) |
| 489 |
{ |
| 490 |
mus_set_file_descriptors(fd,sf->data_format,sf->datum_size,sf->data_location,sf->chans,sf->header_type); |
| 491 |
mus_seek(fd,sf->data_location,SEEK_SET); |
| 492 |
} |
| 493 |
else set_audio_error(SNDLIB_CANT_OPEN); |
| 494 |
return(fd); |
| 495 |
} |
| 496 |
|
| 497 |
int open_sound_output (char *arg, int srate, int chans, int data_format, int header_type, char *comment) |
| 498 |
{ |
| 499 |
int fd = 0,err,comlen = 0; |
| 500 |
if (comment) comlen = strlen(comment); |
| 501 |
set_audio_error(SNDLIB_NO_ERROR); |
| 502 |
initialize_sndlib(); |
| 503 |
err = mus_write_header(arg,header_type,srate,chans,0,0,data_format,comment,comlen); |
| 504 |
if (err != -1) |
| 505 |
{ |
| 506 |
fd = mus_open_write(arg); |
| 507 |
mus_set_file_descriptors(fd,data_format,mus_format2bytes(data_format),mus_header_data_location(),chans,header_type); |
| 508 |
save_header_name(fd,arg); |
| 509 |
} |
| 510 |
else set_audio_error(SNDLIB_CANT_OPEN); |
| 511 |
return(fd); |
| 512 |
} |
| 513 |
|
| 514 |
int reopen_sound_output(char *arg, int chans, int format, int type, int data_loc) |
| 515 |
{ |
| 516 |
int fd; |
| 517 |
set_audio_error(SNDLIB_NO_ERROR); |
| 518 |
initialize_sndlib(); |
| 519 |
fd = mus_reopen_write(arg); |
| 520 |
mus_set_file_descriptors(fd,format,mus_format2bytes(format),data_loc,chans,type); |
| 521 |
save_header_name(fd,arg); |
| 522 |
return(fd); |
| 523 |
} |
| 524 |
|
| 525 |
int close_sound_input (int fd) |
| 526 |
{ |
| 527 |
return(mus_close(fd)); /* this closes the clm file descriptors */ |
| 528 |
} |
| 529 |
|
| 530 |
int close_sound_output (int fd, int bytes_of_data) |
| 531 |
{ |
| 532 |
flush_header(fd); |
| 533 |
mus_update_header_with_fd(fd,mus_get_header_type(fd),bytes_of_data); |
| 534 |
return(mus_close(fd)); |
| 535 |
} |
| 536 |
|
| 537 |
int read_sound (int fd, int beg, int end, int chans, int **bufs) |
| 538 |
{ |
| 539 |
return(mus_read(fd,beg,end,chans,bufs)); |
| 540 |
} |
| 541 |
|
| 542 |
int write_sound (int tfd, int beg, int end, int chans, int **bufs) |
| 543 |
{ |
| 544 |
return(mus_write(tfd,beg,end,chans,bufs)); |
| 545 |
} |
| 546 |
|
| 547 |
int seek_sound (int tfd, long offset, int origin) |
| 548 |
{ |
| 549 |
return(mus_seek(tfd,offset,origin)); |
| 550 |
} |
| 551 |
|
| 552 |
int seek_sound_frame(int tfd, int frame) |
| 553 |
{ |
| 554 |
return(mus_seek_frame(tfd,frame)); |
| 555 |
} |
| 556 |
|
| 557 |
int override_sound_header(char *arg, int srate, int chans, int format, int type, int location, int size) |
| 558 |
{ |
| 559 |
sound_file *sf; |
| 560 |
/* perhaps once a header has been over-ridden, we should not reset the relevant fields upon re-read? */ |
| 561 |
sf = getsf(arg); |
| 562 |
if (sf) |
| 563 |
{ |
| 564 |
if (location != -1) sf->data_location = location; |
| 565 |
if (size != -1) sf->samples = size; |
| 566 |
if (format != -1) |
| 567 |
{ |
| 568 |
sf->data_format = format; |
| 569 |
sf->datum_size = mus_format2bytes(format); |
| 570 |
} |
| 571 |
if (srate != -1) sf->srate = srate; |
| 572 |
if (chans != -1) sf->chans = chans; |
| 573 |
if (type != -1) sf->header_type = type; |
| 574 |
return(0); |
| 575 |
} |
| 576 |
else return(-1); |
| 577 |
} |
| 578 |
|
| 579 |
int sound_max_amp(char *ifile, int *vals) |
| 580 |
{ |
| 581 |
int ifd,ichans,bufnum,n,curframes,i,frames,chn,fc; |
| 582 |
int *buffer,*time,*samp; |
| 583 |
int **ibufs; |
| 584 |
sound_file *sf; |
| 585 |
sf = getsf(ifile); |
| 586 |
if ((sf) && (sf->max_amps)) |
| 587 |
{ |
| 588 |
for (chn=0;chn<sf->chans;chn++) |
| 589 |
{ |
| 590 |
vals[chn*2] = sf->max_amps[chn*2]; |
| 591 |
vals[chn*2+1] = sf->max_amps[chn*2+1]; |
| 592 |
} |
| 593 |
return(sf->samples / sf->chans); |
| 594 |
} |
| 595 |
ifd = open_sound_input(ifile); |
| 596 |
sf = getsf(ifile); |
| 597 |
if (ifd == -1) return(-1); |
| 598 |
ichans = sound_chans(ifile); |
| 599 |
frames = sound_frames(ifile); |
| 600 |
if (frames <= 0) {close_sound_input(ifd); return(0);} |
| 601 |
seek_sound_frame(ifd,0); |
| 602 |
ibufs = (int **)CALLOC(ichans,sizeof(int *)); |
| 603 |
bufnum = 8192; |
| 604 |
for (i=0;i<ichans;i++) ibufs[i] = (int *)CALLOC(bufnum,sizeof(int)); |
| 605 |
time = (int *)CALLOC(ichans,sizeof(int)); |
| 606 |
samp = (int *)CALLOC(ichans,sizeof(int)); |
| 607 |
for (n=0;n<frames;n+=bufnum) |
| 608 |
{ |
| 609 |
if ((n+bufnum)<frames) curframes = bufnum; else curframes = (frames-n); |
| 610 |
read_sound(ifd,0,curframes-1,ichans,ibufs); |
| 611 |
for (chn=0;chn<ichans;chn++) |
| 612 |
{ |
| 613 |
buffer = (int *)(ibufs[chn]); |
| 614 |
fc=samp[chn]; |
| 615 |
for (i=0;i<curframes;i++) |
| 616 |
{ |
| 617 |
if ((buffer[i]>fc) || (fc < -buffer[i])) |
| 618 |
{ |
| 619 |
time[chn]=i+n; |
| 620 |
samp[chn]=buffer[i]; |
| 621 |
if (samp[chn]<0) samp[chn] = -samp[chn]; |
| 622 |
fc = samp[chn]; |
| 623 |
} |
| 624 |
} |
| 625 |
} |
| 626 |
} |
| 627 |
close_sound_input(ifd); |
| 628 |
if (sf->max_amps == NULL) sf->max_amps = (int *)CALLOC(ichans*2,sizeof(int)); |
| 629 |
for (chn=0,i=0;chn<ichans;chn++,i+=2) |
| 630 |
{ |
| 631 |
vals[i]=samp[chn]; |
| 632 |
vals[i+1]=time[chn]; |
| 633 |
sf->max_amps[i] = vals[i]; |
| 634 |
sf->max_amps[i+1] = vals[i+1]; |
| 635 |
} |
| 636 |
FREE(time); |
| 637 |
FREE(samp); |
| 638 |
for (i=0;i<ichans;i++) FREE(ibufs[i]); |
| 639 |
FREE(ibufs); |
| 640 |
return(frames); |
| 641 |
} |
| 642 |
|
| 643 |
|
| 644 |
int mus_file2array(char *filename, int chan, int start, int samples, int *array) |
| 645 |
{ |
| 646 |
int ifd,chans,total_read; |
| 647 |
int **bufs; |
| 648 |
ifd = open_sound_input(filename); |
| 649 |
if (ifd == -1) return(-1); |
| 650 |
chans = sound_chans(filename); |
| 651 |
bufs = (int **)CALLOC(chans,sizeof(int *)); |
| 652 |
bufs[chan] = array; |
| 653 |
seek_sound_frame(ifd,start); |
| 654 |
total_read = mus_read_any(ifd,0,chans,samples,bufs,(int *)bufs); |
| 655 |
close_sound_input(ifd); |
| 656 |
FREE(bufs); |
| 657 |
return(total_read); |
| 658 |
} |
| 659 |
|
| 660 |
int mus_array2file(char *filename, int *ddata, int len, int srate, int channels) |
| 661 |
{ |
| 662 |
/* put ddata into a sound file, taking byte order into account */ |
| 663 |
/* assume ddata is interleaved already if more than one channel */ |
| 664 |
int fd; |
| 665 |
#ifdef SNDLIB_LITTLE_ENDIAN |
| 666 |
int i; |
| 667 |
unsigned char *o; |
| 668 |
unsigned char tmp; |
| 669 |
#endif |
| 670 |
fd = mus_create(filename); |
| 671 |
if (fd == -1) return(-1); |
| 672 |
mus_write_next_header(fd,srate,channels,28,len*4,SNDLIB_32_LINEAR,NULL,0); |
| 673 |
#ifdef SNDLIB_LITTLE_ENDIAN |
| 674 |
o = (unsigned char *)ddata; |
| 675 |
for (i=0;i<len;i++,o+=4) |
| 676 |
{ |
| 677 |
tmp = o[0]; o[0]=o[3]; o[3]=tmp; tmp=o[1]; o[1]=o[2]; o[2]=tmp; |
| 678 |
} |
| 679 |
#endif |
| 680 |
#ifndef MACOS |
| 681 |
write(fd,(unsigned char *)ddata,len*4); |
| 682 |
#else |
| 683 |
write(fd,(char *)ddata,len*4); |
| 684 |
#endif |
| 685 |
close(fd); |
| 686 |
return(0); |
| 687 |
} |
| 688 |
|