A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2474 lines 74 kB view raw
1/* Copyright (c) 1997-1999 Miller Puckette. 2* For information on usage and redistribution, and for a DISCLAIMER OF ALL 3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ 4 5/* this file contains, first, a collection of soundfile access routines, a 6sort of soundfile library. Second, the "soundfiler" object is defined which 7uses the routines to read or write soundfiles, synchronously, from garrays. 8These operations are not to be done in "real time" as they may have to wait 9for disk accesses (even the write routine.) Finally, the realtime objects 10readsf~ and writesf~ are defined which confine disk operations to a separate 11thread so that they can be used in real time. The readsf~ and writesf~ 12objects use Posix-like threads. */ 13 14#ifdef ROCKBOX 15#include "plugin.h" 16#include "../../pdbox.h" 17#else /* ROCKBOX */ 18#ifdef UNIX 19#include <unistd.h> 20#include <fcntl.h> 21#endif 22#include <pthread.h> 23#ifdef MSW 24#include <io.h> 25#endif 26#include <stdio.h> 27#include <string.h> 28#include <errno.h> 29#endif /* ROCKBOX */ 30 31#include "m_pd.h" 32 33#define MAXSFCHANS 64 34 35/***************** soundfile header structures ************************/ 36 37typedef unsigned short uint16; 38typedef unsigned long uint32; 39 40#define FORMAT_WAVE 0 41#define FORMAT_AIFF 1 42#define FORMAT_NEXT 2 43 44/* the NeXTStep sound header structure; can be big or little endian */ 45 46typedef struct _nextstep 47{ 48 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */ 49 uint32 ns_onset; /* byte offset of first sample */ 50 uint32 ns_length; /* length of sound in bytes */ 51 uint32 ns_format; /* format; see below */ 52 uint32 ns_sr; /* sample rate */ 53 uint32 ns_nchans; /* number of channels */ 54 char ns_info[4]; /* comment */ 55} t_nextstep; 56 57#define NS_FORMAT_LINEAR_16 3 58#define NS_FORMAT_LINEAR_24 4 59#define NS_FORMAT_FLOAT 6 60#define SCALE (1./(1024. * 1024. * 1024. * 2.)) 61 62/* the WAVE header. All Wave files are little endian. We assume 63 the "fmt" chunk comes first which is usually the case but perhaps not 64 always; same for AIFF and the "COMM" chunk. */ 65 66typedef unsigned word; 67typedef unsigned long dword; 68 69typedef struct _wave 70{ 71 char w_fileid[4]; /* chunk id 'RIFF' */ 72 uint32 w_chunksize; /* chunk size */ 73 char w_waveid[4]; /* wave chunk id 'WAVE' */ 74 char w_fmtid[4]; /* format chunk id 'fmt ' */ 75 uint32 w_fmtchunksize; /* format chunk size */ 76 uint16 w_fmttag; /* format tag (WAV_INT etc) */ 77 uint16 w_nchannels; /* number of channels */ 78 uint32 w_samplespersec; /* sample rate in hz */ 79 uint32 w_navgbytespersec; /* average bytes per second */ 80 uint16 w_nblockalign; /* number of bytes per frame */ 81 uint16 w_nbitspersample; /* number of bits in a sample */ 82 char w_datachunkid[4]; /* data chunk id 'data' */ 83 uint32 w_datachunksize; /* length of data chunk */ 84} t_wave; 85 86typedef struct _fmt /* format chunk */ 87{ 88 uint16 f_fmttag; /* format tag, 1 for PCM */ 89 uint16 f_nchannels; /* number of channels */ 90 uint32 f_samplespersec; /* sample rate in hz */ 91 uint32 f_navgbytespersec; /* average bytes per second */ 92 uint16 f_nblockalign; /* number of bytes per frame */ 93 uint16 f_nbitspersample; /* number of bits in a sample */ 94} t_fmt; 95 96typedef struct _wavechunk /* ... and the last two items */ 97{ 98 char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */ 99 uint32 wc_size; /* length of data chunk */ 100} t_wavechunk; 101 102#define WAV_INT 1 103#define WAV_FLOAT 3 104 105/* the AIFF header. I'm assuming AIFC is compatible but don't really know 106 that. */ 107 108typedef struct _datachunk 109{ 110 char dc_id[4]; /* data chunk id 'SSND' */ 111 uint32 dc_size; /* length of data chunk */ 112} t_datachunk; 113 114typedef struct _comm 115{ 116 uint16 c_nchannels; /* number of channels */ 117 uint16 c_nframeshi; /* # of sample frames (hi) */ 118 uint16 c_nframeslo; /* # of sample frames (lo) */ 119 uint16 c_bitspersamp; /* bits per sample */ 120 unsigned char c_samprate[10]; /* sample rate, 80-bit float! */ 121} t_comm; 122 123 /* this version is more convenient for writing them out: */ 124typedef struct _aiff 125{ 126 char a_fileid[4]; /* chunk id 'FORM' */ 127 uint32 a_chunksize; /* chunk size */ 128 char a_aiffid[4]; /* aiff chunk id 'AIFF' */ 129 char a_fmtid[4]; /* format chunk id 'COMM' */ 130 uint32 a_fmtchunksize; /* format chunk size, 18 */ 131 uint16 a_nchannels; /* number of channels */ 132 uint16 a_nframeshi; /* # of sample frames (hi) */ 133 uint16 a_nframeslo; /* # of sample frames (lo) */ 134 uint16 a_bitspersamp; /* bits per sample */ 135 unsigned char a_samprate[10]; /* sample rate, 80-bit float! */ 136} t_aiff; 137 138#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */ 139 140 141#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */ 142 143#define WHDR1 sizeof(t_nextstep) 144#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1) 145#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2) 146 147#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2) 148 149#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */ 150 151#ifdef MSW 152#include <fcntl.h> 153#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY 154#else 155#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC 156#endif 157 158/* this routine returns 1 if the high order byte comes at the lower 159address on our architecture (big-endianness.). It's 1 for Motorola, 1600 for Intel: */ 161 162extern int garray_ambigendian(void); 163 164/* byte swappers */ 165 166static uint32 swap4(uint32 n, int doit) 167{ 168 if (doit) 169 return (((n & 0xff) << 24) | ((n & 0xff00) << 8) | 170 ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24)); 171 else return (n); 172} 173 174static uint16 swap2(uint32 n, int doit) 175{ 176 if (doit) 177 return (((n & 0xff) << 8) | ((n & 0xff00) >> 8)); 178 else return (n); 179} 180 181static void swapstring(char *foo, int doit) 182{ 183 if (doit) 184 { 185 char a = foo[0], b = foo[1], c = foo[2], d = foo[3]; 186 foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a; 187 } 188} 189 190/******************** soundfile access routines **********************/ 191 192/* This routine opens a file, looks for either a nextstep or "wave" header, 193* seeks to end of it, and fills in bytes per sample and number of channels. 194* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples 195* are supported. If "headersize" is nonzero, the 196* caller should supply the number of channels, endinanness, and bytes per 197* sample; the header is ignored. Otherwise, the routine tries to read the 198* header and fill in the properties. 199*/ 200 201int open_soundfile(const char *dirname, const char *filename, int headersize, 202 int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit, 203 long skipframes) 204{ 205 char buf[OBUFSIZE], *bufptr; 206#ifdef ROCKBOX 207 int fd, nchannels, bigendian, bytespersamp, swap, sysrtn; 208#else 209 int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn; 210#endif 211 long bytelimit = 0x7fffffff; 212#ifndef ROCKBOX 213 errno = 0; 214#endif 215 fd = open_via_path(dirname, filename, 216 "", buf, &bufptr, MAXPDSTRING, 1); 217 if (fd < 0) 218 return (-1); 219 if (headersize >= 0) /* header detection overridden */ 220 { 221 bigendian = *p_bigendian; 222 nchannels = *p_nchannels; 223 bytespersamp = *p_bytespersamp; 224 bytelimit = *p_bytelimit; 225 } 226 else 227 { 228 int bytesread = read(fd, buf, READHDRSIZE); 229 int format; 230 if (bytesread < 4) 231 goto badheader; 232 if (!strncmp(buf, ".snd", 4)) 233 format = FORMAT_NEXT, bigendian = 1; 234 else if (!strncmp(buf, "dns.", 4)) 235 format = FORMAT_NEXT, bigendian = 0; 236 else if (!strncmp(buf, "RIFF", 4)) 237 { 238 if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4)) 239 goto badheader; 240 format = FORMAT_WAVE, bigendian = 0; 241 } 242 else if (!strncmp(buf, "FORM", 4)) 243 { 244 if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4)) 245 goto badheader; 246 format = FORMAT_AIFF, bigendian = 1; 247 } 248 else 249 goto badheader; 250 swap = (bigendian != garray_ambigendian()); 251 if (format == FORMAT_NEXT) /* nextstep header */ 252 { 253#ifndef ROCKBOX 254 uint32 param; 255#endif 256 if (bytesread < (int)sizeof(t_nextstep)) 257 goto badheader; 258 nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap); 259 format = swap4(((t_nextstep *)buf)->ns_format, swap); 260 headersize = swap4(((t_nextstep *)buf)->ns_onset, swap); 261 if (format == NS_FORMAT_LINEAR_16) 262 bytespersamp = 2; 263 else if (format == NS_FORMAT_LINEAR_24) 264 bytespersamp = 3; 265 else if (format == NS_FORMAT_FLOAT) 266 bytespersamp = 4; 267 else goto badheader; 268 bytelimit = 0x7fffffff; 269 } 270 else if (format == FORMAT_WAVE) /* wave header */ 271 { 272 /* This is awful. You have to skip over chunks, 273 except that if one happens to be a "fmt" chunk, you want to 274 find out the format from that one. The case where the 275 "fmt" chunk comes after the audio isn't handled. */ 276 headersize = 12; 277 if (bytesread < 20) 278 goto badheader; 279 /* First we guess a number of channels, etc., in case there's 280 no "fmt" chunk to follow. */ 281 nchannels = 1; 282 bytespersamp = 2; 283 /* copy the first chunk header to beginnning of buffer. */ 284 memmove(buf, buf + headersize, sizeof(t_wavechunk)); 285 /* post("chunk %c %c %c %c", 286 ((t_wavechunk *)buf)->wc_id[0], 287 ((t_wavechunk *)buf)->wc_id[1], 288 ((t_wavechunk *)buf)->wc_id[2], 289 ((t_wavechunk *)buf)->wc_id[3]); */ 290 /* read chunks in loop until we get to the data chunk */ 291 while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4)) 292 { 293 long chunksize = swap4(((t_wavechunk *)buf)->wc_size, 294 swap), seekto = headersize + chunksize + 8, seekout; 295 296 if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4)) 297 { 298 long commblockonset = headersize + 8; 299 seekout = lseek(fd, commblockonset, SEEK_SET); 300 if (seekout != commblockonset) 301 goto badheader; 302 if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt)) 303 goto badheader; 304 nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap); 305 format = swap2(((t_fmt *)buf)->f_nbitspersample, swap); 306 if (format == 16) 307 bytespersamp = 2; 308 else if (format == 24) 309 bytespersamp = 3; 310 else if (format == 32) 311 bytespersamp = 4; 312 else goto badheader; 313 } 314 seekout = lseek(fd, seekto, SEEK_SET); 315 if (seekout != seekto) 316 goto badheader; 317 if (read(fd, buf, sizeof(t_wavechunk)) < 318 (int) sizeof(t_wavechunk)) 319 goto badheader; 320 /* post("new chunk %c %c %c %c at %d", 321 ((t_wavechunk *)buf)->wc_id[0], 322 ((t_wavechunk *)buf)->wc_id[1], 323 ((t_wavechunk *)buf)->wc_id[2], 324 ((t_wavechunk *)buf)->wc_id[3], seekto); */ 325 headersize = seekto; 326 } 327 bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap); 328 headersize += 8; 329 } 330 else 331 { 332 /* AIFF. same as WAVE; actually predates it. Disgusting. */ 333 headersize = 12; 334 if (bytesread < 20) 335 goto badheader; 336 /* First we guess a number of channels, etc., in case there's 337 no COMM block to follow. */ 338 nchannels = 1; 339 bytespersamp = 2; 340 /* copy the first chunk header to beginnning of buffer. */ 341 memmove(buf, buf + headersize, sizeof(t_datachunk)); 342 /* read chunks in loop until we get to the data chunk */ 343 while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4)) 344 { 345 long chunksize = swap4(((t_datachunk *)buf)->dc_size, 346 swap), seekto = headersize + chunksize + 8, seekout; 347 /* post("chunk %c %c %c %c seek %d", 348 ((t_datachunk *)buf)->dc_id[0], 349 ((t_datachunk *)buf)->dc_id[1], 350 ((t_datachunk *)buf)->dc_id[2], 351 ((t_datachunk *)buf)->dc_id[3], seekto); */ 352 if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4)) 353 { 354 long commblockonset = headersize + 8; 355 seekout = lseek(fd, commblockonset, SEEK_SET); 356 if (seekout != commblockonset) 357 goto badheader; 358 if (read(fd, buf, sizeof(t_comm)) < 359 (int) sizeof(t_comm)) 360 goto badheader; 361 nchannels = swap2(((t_comm *)buf)->c_nchannels, swap); 362 format = swap2(((t_comm *)buf)->c_bitspersamp, swap); 363 if (format == 16) 364 bytespersamp = 2; 365 else if (format == 24) 366 bytespersamp = 3; 367 else goto badheader; 368 } 369 seekout = lseek(fd, seekto, SEEK_SET); 370 if (seekout != seekto) 371 goto badheader; 372 if (read(fd, buf, sizeof(t_datachunk)) < 373 (int) sizeof(t_datachunk)) 374 goto badheader; 375 headersize = seekto; 376 } 377 bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap); 378 headersize += 8; 379 } 380 } 381 /* seek past header and any sample frames to skip */ 382 sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0); 383 if (sysrtn != nchannels * bytespersamp * skipframes + headersize) 384 return (-1); 385 bytelimit -= nchannels * bytespersamp * skipframes; 386 if (bytelimit < 0) 387 bytelimit = 0; 388 /* copy sample format back to caller */ 389 *p_bigendian = bigendian; 390 *p_nchannels = nchannels; 391 *p_bytespersamp = bytespersamp; 392 *p_bytelimit = bytelimit; 393 return (fd); 394badheader: 395 /* the header wasn't recognized. We're threadable here so let's not 396 print out the error... */ 397#ifndef ROCKBOX 398 errno = EIO; 399#endif 400 return (-1); 401} 402 403static void soundfile_xferin(int sfchannels, int nvecs, t_sample **vecs, 404 long itemsread, unsigned char *buf, int nitems, int bytespersamp, 405 int bigendian) 406{ 407 int i, j; 408 unsigned char *sp, *sp2; 409 t_sample *fp; 410 int nchannels = (sfchannels < nvecs ? sfchannels : nvecs); 411 int bytesperframe = bytespersamp * sfchannels; 412 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp) 413 { 414 if (bytespersamp == 2) 415 { 416 if (bigendian) 417 { 418 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread; 419 j < nitems; j++, sp2 += bytesperframe, fp++) 420 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)); 421 } 422 else 423 { 424 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread; 425 j < nitems; j++, sp2 += bytesperframe, fp++) 426#ifdef ROCKBOX_BIG_ENDIAN 427 { 428 short xx = (sp2[1] << 8) | sp2[0]; 429 *fp = xx << (fix1-16); 430 } 431#else 432 *fp = ((short*)sp2)[0]<<(fix1-16); 433#endif 434 } 435 } 436 else if (bytespersamp == 3) 437 { 438 if (bigendian) 439 { 440 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread; 441 j < nitems; j++, sp2 += bytesperframe, fp++) 442 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16) 443 | (sp2[2] << 8)); 444 } 445 else 446 { 447 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread; 448 j < nitems; j++, sp2 += bytesperframe, fp++) 449 *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16) 450 | (sp2[0] << 8)); 451 } 452 } 453 else if (bytespersamp == 4) 454 { 455 if (bigendian) 456 { 457 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread; 458 j < nitems; j++, sp2 += bytesperframe, fp++) 459 *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16) 460 | (sp2[2] << 8) | sp2[3]); 461 } 462 else 463 { 464 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread; 465 j < nitems; j++, sp2 += bytesperframe, fp++) 466 *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16) 467 | (sp2[1] << 8) | sp2[0]); 468 } 469 } 470 } 471 /* zero out other outputs */ 472 for (i = sfchannels; i < nvecs; i++) 473 for (j = nitems, fp = vecs[i]; j--; ) 474 *fp++ = 0; 475 476} 477 478 /* soundfiler_write ... 479 480 usage: write [flags] filename table ... 481 flags: 482 -nframes <frames> 483 -skip <frames> 484 -bytes <bytes per sample> 485 -normalize 486 -nextstep 487 -wave 488 -big 489 -little 490 */ 491 492 /* the routine which actually does the work should LATER also be called 493 from garray_write16. */ 494 495 496 /* Parse arguments for writing. The "obj" argument is only for flagging 497 errors. For streaming to a file the "normalize", "onset" and "nframes" 498 arguments shouldn't be set but the calling routine flags this. */ 499 500static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, 501 t_symbol **p_filesym, 502 int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian, 503 int *p_normalize, long *p_onset, long *p_nframes, float *p_rate) 504{ 505 int argc = *p_argc; 506 t_atom *argv = *p_argv; 507 int bytespersamp = 2, bigendian = 0, 508 endianness = -1, swap, filetype = -1, normalize = 0; 509 long onset = 0, nframes = 0x7fffffff; 510 t_symbol *filesym; 511 float rate = -1; 512 513 while (argc > 0 && argv->a_type == A_SYMBOL && 514 *argv->a_w.w_symbol->s_name == '-') 515 { 516 char *flag = argv->a_w.w_symbol->s_name + 1; 517 if (!strcmp(flag, "skip")) 518 { 519 if (argc < 2 || argv[1].a_type != A_FLOAT || 520 ((onset = argv[1].a_w.w_float) < 0)) 521 goto usage; 522 argc -= 2; argv += 2; 523 } 524 else if (!strcmp(flag, "nframes")) 525 { 526 if (argc < 2 || argv[1].a_type != A_FLOAT || 527 ((nframes = argv[1].a_w.w_float) < 0)) 528 goto usage; 529 argc -= 2; argv += 2; 530 } 531 else if (!strcmp(flag, "bytes")) 532 { 533 if (argc < 2 || argv[1].a_type != A_FLOAT || 534 ((bytespersamp = argv[1].a_w.w_float) < 2) || 535 bytespersamp > 4) 536 goto usage; 537 argc -= 2; argv += 2; 538 } 539 else if (!strcmp(flag, "normalize")) 540 { 541 normalize = 1; 542 argc -= 1; argv += 1; 543 } 544 else if (!strcmp(flag, "wave")) 545 { 546 filetype = FORMAT_WAVE; 547 argc -= 1; argv += 1; 548 } 549 else if (!strcmp(flag, "nextstep")) 550 { 551 filetype = FORMAT_NEXT; 552 argc -= 1; argv += 1; 553 } 554 else if (!strcmp(flag, "aiff")) 555 { 556 filetype = FORMAT_AIFF; 557 argc -= 1; argv += 1; 558 } 559 else if (!strcmp(flag, "big")) 560 { 561 endianness = 1; 562 argc -= 1; argv += 1; 563 } 564 else if (!strcmp(flag, "little")) 565 { 566 endianness = 0; 567 argc -= 1; argv += 1; 568 } 569 else if (!strcmp(flag, "r") || !strcmp(flag, "rate")) 570 { 571 if (argc < 2 || argv[1].a_type != A_FLOAT || 572 ((rate = argv[1].a_w.w_float) <= 0)) 573 goto usage; 574 argc -= 2; argv += 2; 575 } 576 else goto usage; 577 } 578 if (!argc || argv->a_type != A_SYMBOL) 579 goto usage; 580 filesym = argv->a_w.w_symbol; 581 582 /* check if format not specified and fill in */ 583 if (filetype < 0) 584 { 585 if (strlen(filesym->s_name) >= 5 && 586 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") || 587 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF"))) 588 filetype = FORMAT_AIFF; 589 if (strlen(filesym->s_name) >= 6 && 590 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") || 591 !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF"))) 592 filetype = FORMAT_AIFF; 593 if (strlen(filesym->s_name) >= 5 && 594 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") || 595 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND"))) 596 filetype = FORMAT_NEXT; 597 if (strlen(filesym->s_name) >= 4 && 598 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") || 599 !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU"))) 600 filetype = FORMAT_NEXT; 601 if (filetype < 0) 602 filetype = FORMAT_WAVE; 603 } 604 /* don't handle AIFF floating point samples */ 605 if (bytespersamp == 4) 606 { 607 if (filetype == FORMAT_AIFF) 608 { 609 pd_error(obj, "AIFF floating-point file format unavailable"); 610 goto usage; 611 } 612 } 613 /* for WAVE force little endian; for nextstep use machine native */ 614 if (filetype == FORMAT_WAVE) 615 { 616 bigendian = 0; 617 if (endianness == 1) 618 pd_error(obj, "WAVE file forced to little endian"); 619 } 620 else if (filetype == FORMAT_AIFF) 621 { 622 bigendian = 1; 623 if (endianness == 0) 624 pd_error(obj, "AIFF file forced to big endian"); 625 } 626 else if (endianness == -1) 627 { 628 bigendian = garray_ambigendian(); 629 } 630 else bigendian = endianness; 631 swap = (bigendian != garray_ambigendian()); 632 633 argc--; argv++; 634 635 *p_argc = argc; 636 *p_argv = argv; 637 *p_filesym = filesym; 638 *p_filetype = filetype; 639 *p_bytespersamp = bytespersamp; 640 *p_swap = swap; 641 *p_normalize = normalize; 642 *p_onset = onset; 643 *p_nframes = nframes; 644 *p_bigendian = bigendian; 645 *p_rate = rate; 646 return (0); 647usage: 648 return (-1); 649} 650 651static int create_soundfile(t_canvas *canvas, const char *filename, 652 int filetype, int nframes, int bytespersamp, 653 int bigendian, int nchannels, int swap, float samplerate) 654{ 655 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING]; 656 char headerbuf[WRITEHDRSIZE]; 657 t_wave *wavehdr = (t_wave *)headerbuf; 658 t_nextstep *nexthdr = (t_nextstep *)headerbuf; 659 t_aiff *aiffhdr = (t_aiff *)headerbuf; 660 int fd, headersize = 0; 661 662 strncpy(filenamebuf, filename, MAXPDSTRING-10); 663 filenamebuf[MAXPDSTRING-10] = 0; 664 665 if (filetype == FORMAT_NEXT) 666 { 667 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd")) 668 strcat(filenamebuf, ".snd"); 669 if (bigendian) 670 strncpy(nexthdr->ns_fileid, ".snd", 4); 671 else strncpy(nexthdr->ns_fileid, "dns.", 4); 672 nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap); 673 nexthdr->ns_length = 0; 674 nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 : 675 (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap); 676 nexthdr->ns_sr = swap4(samplerate, swap); 677 nexthdr->ns_nchans = swap4(nchannels, swap); 678 strcpy(nexthdr->ns_info, "Pd "); 679 swapstring(nexthdr->ns_info, swap); 680 headersize = sizeof(t_nextstep); 681 } 682 else if (filetype == FORMAT_AIFF) 683 { 684 long datasize = nframes * nchannels * bytespersamp; 685 long longtmp; 686 t_datachunk *aiffdc = (t_datachunk *)(headerbuf + sizeof(t_aiff)); 687 static unsigned char AIFF_splrate[] = {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0}; 688 static unsigned char datachunk_ID[] = {'S', 'S', 'N', 'D'}; 689 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") && 690 strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff")) 691 strcat(filenamebuf, ".aif"); 692 strncpy(aiffhdr->a_fileid, "FORM", 4); 693 aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap); 694 strncpy(aiffhdr->a_aiffid, "AIFF", 4); 695 strncpy(aiffhdr->a_fmtid, "COMM", 4); 696 aiffhdr->a_fmtchunksize = swap4(18, swap); 697 aiffhdr->a_nchannels = swap2(nchannels, swap); 698 longtmp = swap4(nframes, swap); 699 memcpy(&aiffhdr->a_nframeshi, &longtmp, 4); 700 aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap); 701 memcpy(aiffhdr->a_samprate, AIFF_splrate, sizeof(AIFF_splrate)); 702 memcpy(aiffdc->dc_id, datachunk_ID, sizeof(datachunk_ID)); 703 longtmp = swap4(datasize, swap); 704#if __GNUC__ == 9 || __GNUC__ == 10 // False positive with GCC9 && GCC10 705#pragma GCC diagnostic push 706#pragma GCC diagnostic ignored "-Wstringop-overflow" 707#pragma GCC diagnostic ignored "-Warray-bounds" 708#endif 709 memcpy(&aiffdc->dc_size, &longtmp, 4); 710#if __GNUC__ == 9 711#pragma GCC diagnostic pop 712#endif 713 headersize = AIFFPLUS; 714 } 715 else /* WAVE format */ 716 { 717 long datasize = nframes * nchannels * bytespersamp; 718 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav")) 719 strcat(filenamebuf, ".wav"); 720 strncpy(wavehdr->w_fileid, "RIFF", 4); 721 wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap); 722 strncpy(wavehdr->w_waveid, "WAVE", 4); 723 strncpy(wavehdr->w_fmtid, "fmt ", 4); 724 wavehdr->w_fmtchunksize = swap4(16, swap); 725 wavehdr->w_fmttag = 726 swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap); 727 wavehdr->w_nchannels = swap2(nchannels, swap); 728 wavehdr->w_samplespersec = swap4(samplerate, swap); 729 wavehdr->w_navgbytespersec = 730 swap4((int)(samplerate * nchannels * bytespersamp), swap); 731 wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap); 732 wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap); 733 strncpy(wavehdr->w_datachunkid, "data", 4); 734 wavehdr->w_datachunksize = swap4(datasize, swap); 735 headersize = sizeof(t_wave); 736 } 737 738 canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING); 739 sys_bashfilename(buf2, buf2); 740 if ((fd = open(buf2, BINCREATE, 0666)) < 0) 741 return (-1); 742 743 if (write(fd, headerbuf, headersize) < headersize) 744 { 745 close (fd); 746 return (-1); 747 } 748 return (fd); 749} 750 751static void soundfile_finishwrite(void *obj, char *filename, int fd, 752 int filetype, long nframes, long itemswritten, int bytesperframe, int swap) 753{ 754 if (itemswritten < nframes) 755 { 756 if (nframes < 0x7fffffff) 757 pd_error(obj, "soundfiler_write: %d out of %d bytes written", 758 itemswritten, nframes); 759 /* try to fix size fields in header */ 760 if (filetype == FORMAT_WAVE) 761 { 762 long datasize = itemswritten * bytesperframe, mofo; 763 764 if (lseek(fd, 765 ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0, 766 SEEK_SET) == 0) 767 goto baddonewrite; 768 mofo = swap4(datasize + sizeof(t_wave) - 8, swap); 769 if (write(fd, (char *)(&mofo), 4) < 4) 770 goto baddonewrite; 771 if (lseek(fd, 772 ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0, 773 SEEK_SET) == 0) 774 goto baddonewrite; 775 mofo = swap4(datasize, swap); 776 if (write(fd, (char *)(&mofo), 4) < 4) 777 goto baddonewrite; 778 } 779 if (filetype == FORMAT_AIFF) 780 { 781 long mofo; 782 if (lseek(fd, 783 ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0, 784 SEEK_SET) == 0) 785 goto baddonewrite; 786 mofo = swap4(nframes, swap); 787 if (write(fd, (char *)(&mofo), 4) < 4) 788 goto baddonewrite; 789 } 790 if (filetype == FORMAT_NEXT) 791 { 792 /* do it the lazy way: just set the size field to 'unknown size'*/ 793 uint32 nextsize = 0xffffffff; 794 if (lseek(fd, 8, SEEK_SET) == 0) 795 { 796 goto baddonewrite; 797 } 798 if (write(fd, &nextsize, 4) < 4) 799 { 800 goto baddonewrite; 801 } 802 } 803 } 804 return; 805baddonewrite: 806#ifdef ROCKBOX 807 post("%s: error", filename); 808#else 809 post("%s: %s", filename, strerror(errno)); 810#endif 811} 812 813static void soundfile_xferout(int nchannels, t_sample **vecs, 814 unsigned char *buf, int nitems, long onset, int bytespersamp, 815 int bigendian, float normalfactor) 816{ 817 int i, j; 818 unsigned char *sp, *sp2; 819 t_sample *fp; 820 int bytesperframe = bytespersamp * nchannels; 821 long xx; 822 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp) 823 { 824 if (bytespersamp == 2) 825 { 826 float ff = normalfactor * 32768.; 827 if (bigendian) 828 { 829 for (j = 0, sp2 = sp, fp = vecs[i] + onset; 830 j < nitems; j++, sp2 += bytesperframe, fp++) 831 { 832 int xx = 32768. + (*fp * ff); 833 xx -= 32768; 834 if (xx < -32767) 835 xx = -32767; 836 if (xx > 32767) 837 xx = 32767; 838 sp2[0] = (xx >> 8); 839 sp2[1] = xx; 840 } 841 } 842 else 843 { 844 for (j = 0, sp2 = sp, fp=vecs[i] + onset; 845 j < nitems; j++, sp2 += bytesperframe, fp++) 846 { 847 int xx = 32768. + (*fp * ff); 848 xx -= 32768; 849 if (xx < -32767) 850 xx = -32767; 851 if (xx > 32767) 852 xx = 32767; 853 sp2[1] = (xx >> 8); 854 sp2[0] = xx; 855 } 856 } 857 } 858 else if (bytespersamp == 3) 859 { 860 float ff = normalfactor * 8388608.; 861 if (bigendian) 862 { 863 for (j = 0, sp2 = sp, fp=vecs[i] + onset; 864 j < nitems; j++, sp2 += bytesperframe, fp++) 865 { 866 int xx = 8388608. + (*fp * ff); 867 xx -= 8388608; 868 if (xx < -8388607) 869 xx = -8388607; 870 if (xx > 8388607) 871 xx = 8388607; 872 sp2[0] = (xx >> 16); 873 sp2[1] = (xx >> 8); 874 sp2[2] = xx; 875 } 876 } 877 else 878 { 879 for (j = 0, sp2 = sp, fp=vecs[i] + onset; 880 j < nitems; j++, sp2 += bytesperframe, fp++) 881 { 882 int xx = 8388608. + (*fp * ff); 883 xx -= 8388608; 884 if (xx < -8388607) 885 xx = -8388607; 886 if (xx > 8388607) 887 xx = 8388607; 888 sp2[2] = (xx >> 16); 889 sp2[1] = (xx >> 8); 890 sp2[0] = xx; 891 } 892 } 893 } 894 else if (bytespersamp == 4) 895 { 896 if (bigendian) 897 { 898 for (j = 0, sp2 = sp, fp=vecs[i] + onset; 899 j < nitems; j++, sp2 += bytesperframe, fp++) 900 { 901#ifdef ROCKBOX 902 union f2i f2i; 903 f2i.f = *fp * normalfactor; 904 xx = f2i.i; 905#else /* ROCKBOX */ 906 float f2 = *fp * normalfactor; 907 xx = *(long *)&f2; 908#endif /* ROCKBOX */ 909 sp2[0] = (xx >> 24); sp2[1] = (xx >> 16); 910 sp2[2] = (xx >> 8); sp2[3] = xx; 911 } 912 } 913 else 914 { 915 for (j = 0, sp2 = sp, fp=vecs[i] + onset; 916 j < nitems; j++, sp2 += bytesperframe, fp++) 917 { 918#ifdef ROCKBOX 919 union f2i f2i; 920 f2i.f = *fp * normalfactor; 921 xx = f2i.i; 922#else /* ROCKBOX */ 923 float f2 = *fp * normalfactor; 924 xx = *(long *)&f2; 925#endif /* ROCKBOX */ 926 sp2[3] = (xx >> 24); sp2[2] = (xx >> 16); 927 sp2[1] = (xx >> 8); sp2[0] = xx; 928 } 929 } 930 } 931 } 932} 933 934 935/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */ 936#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */ 937#define SAMPBUFSIZE 1024 938 939 940static t_class *soundfiler_class; 941 942typedef struct _soundfiler 943{ 944 t_object x_obj; 945 t_canvas *x_canvas; 946} t_soundfiler; 947 948static t_soundfiler *soundfiler_new(void) 949{ 950 t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class); 951 x->x_canvas = canvas_getcurrent(); 952 outlet_new(&x->x_obj, &s_float); 953 return (x); 954} 955 956 /* soundfiler_read ... 957 958 usage: read [flags] filename table ... 959 flags: 960 -skip <frames> ... frames to skip in file 961 -nframes <frames> 962 -onset <frames> ... onset in table to read into (NOT DONE YET) 963 -raw <headersize channels bytes endian> 964 -resize 965 -maxsize <max-size> 966 */ 967 968static void soundfiler_read(t_soundfiler *x, t_symbol *s, 969 int argc, t_atom *argv) 970{ 971#ifdef ROCKBOX 972 (void) s; 973#endif 974 int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0, 975 resize = 0, i, j; 976#ifdef ROCKBOX 977 long skipframes = 0, nframes = 0, finalsize = 0, 978#else 979 long skipframes = 0, nframes = 0, finalsize = 0, itemsleft, 980#endif 981 maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff; 982 int fd = -1; 983 char endianness, *filename; 984 t_garray *garrays[MAXSFCHANS]; 985 t_sample *vecs[MAXSFCHANS]; 986 char sampbuf[SAMPBUFSIZE]; 987 int bufframes, nitems; 988#ifdef ROCKBOX 989 int fp; 990#else 991 FILE *fp; 992#endif 993 while (argc > 0 && argv->a_type == A_SYMBOL && 994 *argv->a_w.w_symbol->s_name == '-') 995 { 996 char *flag = argv->a_w.w_symbol->s_name + 1; 997 if (!strcmp(flag, "skip")) 998 { 999 if (argc < 2 || argv[1].a_type != A_FLOAT || 1000 ((skipframes = argv[1].a_w.w_float) < 0)) 1001 goto usage; 1002 argc -= 2; argv += 2; 1003 } 1004 else if (!strcmp(flag, "nframes")) 1005 { 1006 if (argc < 2 || argv[1].a_type != A_FLOAT || 1007 ((nframes = argv[1].a_w.w_float) < 0)) 1008 goto usage; 1009 argc -= 2; argv += 2; 1010 } 1011 else if (!strcmp(flag, "raw")) 1012 { 1013 if (argc < 5 || 1014 argv[1].a_type != A_FLOAT || 1015 ((headersize = argv[1].a_w.w_float) < 0) || 1016 argv[2].a_type != A_FLOAT || 1017 ((channels = argv[2].a_w.w_float) < 1) || 1018 (channels > MAXSFCHANS) || 1019 argv[3].a_type != A_FLOAT || 1020 ((bytespersamp = argv[3].a_w.w_float) < 2) || 1021 (bytespersamp > 4) || 1022 argv[4].a_type != A_SYMBOL || 1023 ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b' 1024 && endianness != 'l' && endianness != 'n')) 1025 goto usage; 1026 if (endianness == 'b') 1027 bigendian = 1; 1028 else if (endianness == 'l') 1029 bigendian = 0; 1030 else 1031 bigendian = garray_ambigendian(); 1032 argc -= 5; argv += 5; 1033 } 1034 else if (!strcmp(flag, "resize")) 1035 { 1036 resize = 1; 1037 argc -= 1; argv += 1; 1038 } 1039 else if (!strcmp(flag, "maxsize")) 1040 { 1041 if (argc < 2 || argv[1].a_type != A_FLOAT || 1042 ((maxsize = argv[1].a_w.w_float) < 0)) 1043 goto usage; 1044 resize = 1; /* maxsize implies resize. */ 1045 argc -= 2; argv += 2; 1046 } 1047 else goto usage; 1048 } 1049 if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL) 1050 goto usage; 1051 filename = argv[0].a_w.w_symbol->s_name; 1052 argc--; argv++; 1053 1054 for (i = 0; i < argc; i++) 1055 { 1056 int vecsize; 1057 if (argv[i].a_type != A_SYMBOL) 1058 goto usage; 1059 if (!(garrays[i] = 1060 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class))) 1061 { 1062 pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name); 1063 goto done; 1064 } 1065 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i])) 1066 error("%s: bad template for tabwrite", 1067 argv[i].a_w.w_symbol->s_name); 1068 if (finalsize && finalsize != vecsize && !resize) 1069 { 1070 post("soundfiler_read: arrays have different lengths; resizing..."); 1071 resize = 1; 1072 } 1073 finalsize = vecsize; 1074 } 1075 fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename, 1076 headersize, &bytespersamp, &bigendian, &channels, &bytelimit, 1077 skipframes); 1078 1079 if (fd < 0) 1080 { 1081#ifdef ROCKBOX 1082 pd_error(x, "soundfiler_read: %s: %s", 1083 filename, 1084 "unknown or bad header format"); 1085#else 1086 pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ? 1087 "unknown or bad header format" : strerror(errno))); 1088#endif 1089 goto done; 1090 } 1091 1092 if (resize) 1093 { 1094 /* figure out what to resize to */ 1095 long poswas, eofis, framesinfile; 1096 1097 poswas = lseek(fd, 0, SEEK_CUR); 1098 eofis = lseek(fd, 0, SEEK_END); 1099 if (poswas < 0 || eofis < 0) 1100 { 1101 pd_error(x, "lseek failed"); 1102 goto done; 1103 } 1104 lseek(fd, poswas, SEEK_SET); 1105 framesinfile = (eofis - poswas) / (channels * bytespersamp); 1106 if (framesinfile > maxsize) 1107 { 1108 pd_error(x, "soundfiler_read: truncated to %d elements", maxsize); 1109 framesinfile = maxsize; 1110 } 1111 if (framesinfile > bytelimit / (channels * bytespersamp)) 1112 framesinfile = bytelimit / (channels * bytespersamp); 1113 finalsize = framesinfile; 1114 for (i = 0; i < argc; i++) 1115 { 1116 int vecsize; 1117 1118 garray_resize(garrays[i], finalsize); 1119 /* for sanity's sake let's clear the save-in-patch flag here */ 1120 garray_setsaveit(garrays[i], 0); 1121 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]); 1122 /* if the resize failed, garray_resize reported the error */ 1123 if (vecsize != framesinfile) 1124 { 1125 pd_error(x, "resize failed"); 1126 goto done; 1127 } 1128 } 1129 } 1130 if (!finalsize) finalsize = 0x7fffffff; 1131 if (finalsize > bytelimit / (channels * bytespersamp)) 1132 finalsize = bytelimit / (channels * bytespersamp); 1133#ifdef ROCKBOX 1134 fp = fd; 1135#else 1136 fp = fdopen(fd, "rb"); 1137#endif 1138 bufframes = SAMPBUFSIZE / (channels * bytespersamp); 1139 1140 for (itemsread = 0; itemsread < finalsize; ) 1141 { 1142 int thisread = finalsize - itemsread; 1143 thisread = (thisread > bufframes ? bufframes : thisread); 1144#ifdef ROCKBOX 1145 nitems = read(fp, sampbuf, thisread * bytespersamp * channels) / (bytespersamp * channels); 1146#else 1147 nitems = fread(sampbuf, channels * bytespersamp, thisread, fp); 1148#endif 1149 if (nitems <= 0) break; 1150 soundfile_xferin(channels, argc, vecs, itemsread, 1151 (unsigned char *)sampbuf, nitems, bytespersamp, bigendian); 1152 itemsread += nitems; 1153 } 1154 /* zero out remaining elements of vectors */ 1155 1156 for (i = 0; i < argc; i++) 1157 { 1158#ifdef ROCKBOX 1159 int vecsize; 1160#else 1161 int nzero, vecsize; 1162#endif 1163 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]); 1164 for (j = itemsread; j < vecsize; j++) 1165 vecs[i][j] = 0; 1166 } 1167 /* zero out vectors in excess of number of channels */ 1168 for (i = channels; i < argc; i++) 1169 { 1170 int vecsize; 1171 t_sample *foo; 1172 garray_getfloatarray(garrays[i], &vecsize, &foo); 1173 for (j = 0; j < vecsize; j++) 1174 foo[j] = 0; 1175 } 1176 /* do all graphics updates */ 1177 for (i = 0; i < argc; i++) 1178 garray_redraw(garrays[i]); 1179#ifdef ROCKBOX 1180 close(fp); 1181#else 1182 fclose(fp); 1183#endif 1184 fd = -1; 1185 goto done; 1186usage: 1187 pd_error(x, "usage: read [flags] filename tablename..."); 1188 post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ..."); 1189 post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>."); 1190done: 1191 if (fd >= 0) 1192 close (fd); 1193 outlet_float(x->x_obj.ob_outlet, (float)itemsread); 1194} 1195 1196 /* this is broken out from soundfiler_write below so garray_write can 1197 call it too... not done yet though. */ 1198 1199long soundfiler_dowrite(void *obj, t_canvas *canvas, 1200 int argc, t_atom *argv) 1201{ 1202#ifdef ROCKBOX 1203 int bytespersamp, bigendian, 1204 swap, filetype, normalize, i, j, nchannels; 1205 long onset, nframes, 1206 itemswritten = 0; 1207#else 1208 int headersize, bytespersamp, bigendian, 1209 endianness, swap, filetype, normalize, i, j, nchannels; 1210 long onset, nframes, itemsleft, 1211 maxsize = DEFMAXSIZE, itemswritten = 0; 1212#endif 1213 t_garray *garrays[MAXSFCHANS]; 1214 t_sample *vecs[MAXSFCHANS]; 1215 char sampbuf[SAMPBUFSIZE]; 1216#ifdef ROCKBOX 1217 int bufframes; 1218#else 1219 int bufframes, nitems; 1220#endif 1221 int fd = -1; 1222 float normfactor, biggest = 0, samplerate; 1223 t_symbol *filesym; 1224 1225 if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype, 1226 &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes, 1227 &samplerate)) 1228 goto usage; 1229 nchannels = argc; 1230 if (nchannels < 1 || nchannels > MAXSFCHANS) 1231 goto usage; 1232 if (samplerate < 0) 1233 samplerate = sys_getsr(); 1234 for (i = 0; i < nchannels; i++) 1235 { 1236 int vecsize; 1237 if (argv[i].a_type != A_SYMBOL) 1238 goto usage; 1239 if (!(garrays[i] = 1240 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class))) 1241 { 1242 pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name); 1243 goto fail; 1244 } 1245 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i])) 1246 error("%s: bad template for tabwrite", 1247 argv[i].a_w.w_symbol->s_name); 1248 if (nframes > vecsize - onset) 1249 nframes = vecsize - onset; 1250 1251 for (j = 0; j < vecsize; j++) 1252 { 1253 if (vecs[i][j] > biggest) 1254 biggest = vecs[i][j]; 1255 else if (-vecs[i][j] > biggest) 1256 biggest = -vecs[i][j]; 1257 } 1258 } 1259 if (nframes <= 0) 1260 { 1261 pd_error(obj, "soundfiler_write: no samples at onset %ld", onset); 1262 goto fail; 1263 } 1264 1265 if ((fd = create_soundfile(canvas, filesym->s_name, filetype, 1266 nframes, bytespersamp, bigendian, nchannels, 1267 swap, samplerate)) < 0) 1268 { 1269#ifdef ROCKBOX 1270 post("%s: %s\n", filesym->s_name, "error"); 1271#else 1272 post("%s: %s\n", filesym->s_name, strerror(errno)); 1273#endif 1274 goto fail; 1275 } 1276 if (!normalize) 1277 { 1278 if ((bytespersamp != 4) && (biggest > 1)) 1279 { 1280 post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest); 1281 normalize = 1; 1282 } 1283 else post("%s: biggest amplitude = %f", filesym->s_name, biggest); 1284 } 1285 if (normalize) 1286 normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1); 1287 else normfactor = 1; 1288 1289 bufframes = SAMPBUFSIZE / (nchannels * bytespersamp); 1290 1291 for (itemswritten = 0; itemswritten < nframes; ) 1292 { 1293#ifdef ROCKBOX 1294 int thiswrite = nframes - itemswritten, nbytes; 1295#else 1296 int thiswrite = nframes - itemswritten, nitems, nbytes; 1297#endif 1298 thiswrite = (thiswrite > bufframes ? bufframes : thiswrite); 1299 soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite, 1300 onset, bytespersamp, bigendian, normfactor); 1301 nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite); 1302 if (nbytes < nchannels * bytespersamp * thiswrite) 1303 { 1304#ifdef ROCKBOX 1305 post("%s: %s", filesym->s_name, "error"); 1306#else 1307 post("%s: %s", filesym->s_name, strerror(errno)); 1308#endif 1309 if (nbytes > 0) 1310 itemswritten += nbytes / (nchannels * bytespersamp); 1311 break; 1312 } 1313 itemswritten += thiswrite; 1314 onset += thiswrite; 1315 } 1316 if (fd >= 0) 1317 { 1318 soundfile_finishwrite(obj, filesym->s_name, fd, 1319 filetype, nframes, itemswritten, nchannels * bytespersamp, swap); 1320 close (fd); 1321 } 1322 return ((float)itemswritten); 1323usage: 1324 pd_error(obj, "usage: write [flags] filename tablename..."); 1325 post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ..."); 1326 post("-big -little -normalize"); 1327 post("(defaults to a 16-bit wave file)."); 1328fail: 1329 if (fd >= 0) 1330 close (fd); 1331 return (0); 1332} 1333 1334static void soundfiler_write(t_soundfiler *x, t_symbol *s, 1335 int argc, t_atom *argv) 1336{ 1337#ifdef ROCKBOX 1338 (void) s; 1339#endif 1340 long bozo = soundfiler_dowrite(x, x->x_canvas, 1341 argc, argv); 1342 outlet_float(x->x_obj.ob_outlet, (float)bozo); 1343} 1344 1345static void soundfiler_setup(void) 1346{ 1347 soundfiler_class = class_new(gensym("soundfiler"), (t_newmethod)soundfiler_new, 1348 0, sizeof(t_soundfiler), 0, 0); 1349 class_addmethod(soundfiler_class, (t_method)soundfiler_read, gensym("read"), 1350 A_GIMME, 0); 1351 class_addmethod(soundfiler_class, (t_method)soundfiler_write, 1352 gensym("write"), A_GIMME, 0); 1353} 1354 1355 1356#ifndef FIXEDPOINT 1357/************************* readsf object ******************************/ 1358 1359/* READSF uses the Posix threads package; for the moment we're Linux 1360only although this should be portable to the other platforms. 1361 1362Each instance of readsf~ owns a "child" thread for doing the UNIX (MSW?) file 1363reading. The parent thread signals the child each time: 1364 (1) a file wants opening or closing; 1365 (2) we've eaten another 1/16 of the shared buffer (so that the 1366 child thread should check if it's time to read some more.) 1367The child signals the parent whenever a read has completed. Signalling 1368is done by setting "conditions" and putting data in mutex-controlled common 1369areas. 1370*/ 1371 1372#define MAXBYTESPERSAMPLE 4 1373#define MAXVECSIZE 128 1374 1375#define READSIZE 65536 1376#define WRITESIZE 65536 1377#define DEFBUFPERCHAN 262144 1378#define MINBUFSIZE (4 * READSIZE) 1379#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */ 1380 1381#define REQUEST_NOTHING 0 1382#define REQUEST_OPEN 1 1383#define REQUEST_CLOSE 2 1384#define REQUEST_QUIT 3 1385#define REQUEST_BUSY 4 1386 1387#define STATE_IDLE 0 1388#define STATE_STARTUP 1 1389#define STATE_STREAM 2 1390 1391static t_class *readsf_class; 1392 1393typedef struct _readsf 1394{ 1395 t_object x_obj; 1396 t_canvas *x_canvas; 1397 t_clock *x_clock; 1398 char *x_buf; /* soundfile buffer */ 1399 int x_bufsize; /* buffer size in bytes */ 1400 int x_noutlets; /* number of audio outlets */ 1401 t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */ 1402 int x_vecsize; /* vector size for transfers */ 1403 t_outlet *x_bangout; /* bang-on-done outlet */ 1404 int x_state; /* opened, running, or idle */ 1405 float x_insamplerate; /* sample rate of input signal if known */ 1406 /* parameters to communicate with subthread */ 1407 int x_requestcode; /* pending request from parent to I/O thread */ 1408 char *x_filename; /* file to open (string is permanently allocated) */ 1409 int x_fileerror; /* slot for "errno" return */ 1410 int x_skipheaderbytes; /* size of header we'll skip */ 1411 int x_bytespersample; /* bytes per sample (2 or 3) */ 1412 int x_bigendian; /* true if file is big-endian */ 1413 int x_sfchannels; /* number of channels in soundfile */ 1414 float x_samplerate; /* sample rate of soundfile */ 1415 long x_onsetframes; /* number of sample frames to skip */ 1416 long x_bytelimit; /* max number of data bytes to read */ 1417 int x_fd; /* filedesc */ 1418 int x_fifosize; /* buffer size appropriately rounded down */ 1419 int x_fifohead; /* index of next byte to get from file */ 1420 int x_fifotail; /* index of next byte the ugen will read */ 1421 int x_eof; /* true if fifohead has stopped changing */ 1422 int x_sigcountdown; /* counter for signalling child for more data */ 1423 int x_sigperiod; /* number of ticks per signal */ 1424 int x_filetype; /* writesf~ only; type of file to create */ 1425 int x_itemswritten; /* writesf~ only; items writen */ 1426 int x_swap; /* writesf~ only; true if byte swapping */ 1427 float x_f; /* writesf~ only; scalar for signal inlet */ 1428 pthread_mutex_t x_mutex; 1429 pthread_cond_t x_requestcondition; 1430 pthread_cond_t x_answercondition; 1431 pthread_t x_childthread; 1432} t_readsf; 1433 1434 1435/************** the child thread which performs file I/O ***********/ 1436 1437#if 0 1438static void pute(char *s) /* debug routine */ 1439{ 1440 write(2, s, strlen(s)); 1441} 1442#define DEBUG_SOUNDFILE 1443#endif 1444 1445#if 1 1446#define sfread_cond_wait pthread_cond_wait 1447#define sfread_cond_signal pthread_cond_signal 1448#else 1449#include <sys/time.h> /* debugging version... */ 1450#include <sys/types.h> 1451static void readsf_fakewait(pthread_mutex_t *b) 1452{ 1453 struct timeval timout; 1454 timout.tv_sec = 0; 1455 timout.tv_usec = 1000000; 1456 pthread_mutex_unlock(b); 1457 select(0, 0, 0, 0, &timout); 1458 pthread_mutex_lock(b); 1459} 1460 1461#define sfread_cond_wait(a,b) readsf_fakewait(b) 1462#define sfread_cond_signal(a) 1463#endif 1464 1465static void *readsf_child_main(void *zz) 1466{ 1467 t_readsf *x = zz; 1468#ifdef DEBUG_SOUNDFILE 1469 pute("1\n"); 1470#endif 1471 pthread_mutex_lock(&x->x_mutex); 1472 while (1) 1473 { 1474 int fd, fifohead; 1475 char *buf; 1476#ifdef DEBUG_SOUNDFILE 1477 pute("0\n"); 1478#endif 1479 if (x->x_requestcode == REQUEST_NOTHING) 1480 { 1481#ifdef DEBUG_SOUNDFILE 1482 pute("wait 2\n"); 1483#endif 1484 sfread_cond_signal(&x->x_answercondition); 1485 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex); 1486#ifdef DEBUG_SOUNDFILE 1487 pute("3\n"); 1488#endif 1489 } 1490 else if (x->x_requestcode == REQUEST_OPEN) 1491 { 1492 char boo[80]; 1493 int sysrtn, wantbytes; 1494 1495 /* copy file stuff out of the data structure so we can 1496 relinquish the mutex while we're in open_soundfile(). */ 1497 long onsetframes = x->x_onsetframes; 1498 long bytelimit = 0x7fffffff; 1499 int skipheaderbytes = x->x_skipheaderbytes; 1500 int bytespersample = x->x_bytespersample; 1501 int sfchannels = x->x_sfchannels; 1502 int bigendian = x->x_bigendian; 1503 char *filename = x->x_filename; 1504 char *dirname = canvas_getdir(x->x_canvas)->s_name; 1505 /* alter the request code so that an ensuing "open" will get 1506 noticed. */ 1507#ifdef DEBUG_SOUNDFILE 1508 pute("4\n"); 1509#endif 1510 x->x_requestcode = REQUEST_BUSY; 1511 x->x_fileerror = 0; 1512 1513 /* if there's already a file open, close it */ 1514 if (x->x_fd >= 0) 1515 { 1516 fd = x->x_fd; 1517 pthread_mutex_unlock(&x->x_mutex); 1518 close (fd); 1519 pthread_mutex_lock(&x->x_mutex); 1520 x->x_fd = -1; 1521 if (x->x_requestcode != REQUEST_BUSY) 1522 goto lost; 1523 } 1524 /* open the soundfile with the mutex unlocked */ 1525 pthread_mutex_unlock(&x->x_mutex); 1526 fd = open_soundfile(dirname, filename, 1527 skipheaderbytes, &bytespersample, &bigendian, 1528 &sfchannels, &bytelimit, onsetframes); 1529 pthread_mutex_lock(&x->x_mutex); 1530 1531#ifdef DEBUG_SOUNDFILE 1532 pute("5\n"); 1533#endif 1534 /* copy back into the instance structure. */ 1535 x->x_bytespersample = bytespersample; 1536 x->x_sfchannels = sfchannels; 1537 x->x_bigendian = bigendian; 1538 x->x_fd = fd; 1539 x->x_bytelimit = bytelimit; 1540 if (fd < 0) 1541 { 1542 x->x_fileerror = errno; 1543 x->x_eof = 1; 1544#ifdef DEBUG_SOUNDFILE 1545 pute("open failed\n"); 1546 pute(filename); 1547 pute(dirname); 1548#endif 1549 goto lost; 1550 } 1551 /* check if another request has been made; if so, field it */ 1552 if (x->x_requestcode != REQUEST_BUSY) 1553 goto lost; 1554#ifdef DEBUG_SOUNDFILE 1555 pute("6\n"); 1556#endif 1557 x->x_fifohead = 0; 1558 /* set fifosize from bufsize. fifosize must be a 1559 multiple of the number of bytes eaten for each DSP 1560 tick. We pessimistically assume MAXVECSIZE samples 1561 per tick since that could change. There could be a 1562 problem here if the vector size increases while a 1563 soundfile is being played... */ 1564 x->x_fifosize = x->x_bufsize - (x->x_bufsize % 1565 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE)); 1566 /* arrange for the "request" condition to be signalled 16 1567 times per buffer */ 1568#ifdef DEBUG_SOUNDFILE 1569 sprintf(boo, "fifosize %d\n", 1570 x->x_fifosize); 1571 pute(boo); 1572#endif 1573 x->x_sigcountdown = x->x_sigperiod = 1574 (x->x_fifosize / 1575 (16 * x->x_bytespersample * x->x_sfchannels * 1576 x->x_vecsize)); 1577 /* in a loop, wait for the fifo to get hungry and feed it */ 1578 1579 while (x->x_requestcode == REQUEST_BUSY) 1580 { 1581 int fifosize = x->x_fifosize; 1582#ifdef DEBUG_SOUNDFILE 1583 pute("77\n"); 1584#endif 1585 if (x->x_eof) 1586 break; 1587 if (x->x_fifohead >= x->x_fifotail) 1588 { 1589 /* if the head is >= the tail, we can immediately read 1590 to the end of the fifo. Unless, that is, we would 1591 read all the way to the end of the buffer and the 1592 "tail" is zero; this would fill the buffer completely 1593 which isn't allowed because you can't tell a completely 1594 full buffer from an empty one. */ 1595 if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE)) 1596 { 1597 wantbytes = fifosize - x->x_fifohead; 1598 if (wantbytes > READSIZE) 1599 wantbytes = READSIZE; 1600 if (wantbytes > x->x_bytelimit) 1601 wantbytes = x->x_bytelimit; 1602#ifdef DEBUG_SOUNDFILE 1603 sprintf(boo, "head %d, tail %d, size %d\n", 1604 x->x_fifohead, x->x_fifotail, wantbytes); 1605 pute(boo); 1606#endif 1607 } 1608 else 1609 { 1610#ifdef DEBUG_SOUNDFILE 1611 pute("wait 7a ...\n"); 1612#endif 1613 sfread_cond_signal(&x->x_answercondition); 1614#ifdef DEBUG_SOUNDFILE 1615 pute("signalled\n"); 1616#endif 1617 sfread_cond_wait(&x->x_requestcondition, 1618 &x->x_mutex); 1619#ifdef DEBUG_SOUNDFILE 1620 pute("7a done\n"); 1621#endif 1622 continue; 1623 } 1624 } 1625 else 1626 { 1627 /* otherwise check if there are at least READSIZE 1628 bytes to read. If not, wait and loop back. */ 1629 wantbytes = x->x_fifotail - x->x_fifohead - 1; 1630 if (wantbytes < READSIZE) 1631 { 1632#ifdef DEBUG_SOUNDFILE 1633 pute("wait 7...\n"); 1634#endif 1635 sfread_cond_signal(&x->x_answercondition); 1636 sfread_cond_wait(&x->x_requestcondition, 1637 &x->x_mutex); 1638#ifdef DEBUG_SOUNDFILE 1639 pute("7 done\n"); 1640#endif 1641 continue; 1642 } 1643 else wantbytes = READSIZE; 1644 if (wantbytes > x->x_bytelimit) 1645 wantbytes = x->x_bytelimit; 1646 } 1647#ifdef DEBUG_SOUNDFILE 1648 pute("8\n"); 1649#endif 1650 fd = x->x_fd; 1651 buf = x->x_buf; 1652 fifohead = x->x_fifohead; 1653 pthread_mutex_unlock(&x->x_mutex); 1654 sysrtn = read(fd, buf + fifohead, wantbytes); 1655 pthread_mutex_lock(&x->x_mutex); 1656 if (x->x_requestcode != REQUEST_BUSY) 1657 break; 1658 if (sysrtn < 0) 1659 { 1660#ifdef DEBUG_SOUNDFILE 1661 pute("fileerror\n"); 1662#endif 1663 x->x_fileerror = errno; 1664 break; 1665 } 1666 else if (sysrtn == 0) 1667 { 1668 x->x_eof = 1; 1669 break; 1670 } 1671 else 1672 { 1673 x->x_fifohead += sysrtn; 1674 x->x_bytelimit -= sysrtn; 1675 if (x->x_bytelimit <= 0) 1676 { 1677 x->x_eof = 1; 1678 break; 1679 } 1680 if (x->x_fifohead == fifosize) 1681 x->x_fifohead = 0; 1682 } 1683#ifdef DEBUG_SOUNDFILE 1684 sprintf(boo, "after: head %d, tail %d\n", 1685 x->x_fifohead, x->x_fifotail); 1686 pute(boo); 1687#endif 1688 /* signal parent in case it's waiting for data */ 1689 sfread_cond_signal(&x->x_answercondition); 1690 } 1691 lost: 1692 1693 if (x->x_requestcode == REQUEST_BUSY) 1694 x->x_requestcode = REQUEST_NOTHING; 1695 /* fell out of read loop: close file if necessary, 1696 set EOF and signal once more */ 1697 if (x->x_fd >= 0) 1698 { 1699 fd = x->x_fd; 1700 pthread_mutex_unlock(&x->x_mutex); 1701 close (fd); 1702 pthread_mutex_lock(&x->x_mutex); 1703 x->x_fd = -1; 1704 } 1705 sfread_cond_signal(&x->x_answercondition); 1706 1707 } 1708 else if (x->x_requestcode == REQUEST_CLOSE) 1709 { 1710 if (x->x_fd >= 0) 1711 { 1712 fd = x->x_fd; 1713 pthread_mutex_unlock(&x->x_mutex); 1714 close (fd); 1715 pthread_mutex_lock(&x->x_mutex); 1716 x->x_fd = -1; 1717 } 1718 if (x->x_requestcode == REQUEST_CLOSE) 1719 x->x_requestcode = REQUEST_NOTHING; 1720 sfread_cond_signal(&x->x_answercondition); 1721 } 1722 else if (x->x_requestcode == REQUEST_QUIT) 1723 { 1724 if (x->x_fd >= 0) 1725 { 1726 fd = x->x_fd; 1727 pthread_mutex_unlock(&x->x_mutex); 1728 close (fd); 1729 pthread_mutex_lock(&x->x_mutex); 1730 x->x_fd = -1; 1731 } 1732 x->x_requestcode = REQUEST_NOTHING; 1733 sfread_cond_signal(&x->x_answercondition); 1734 break; 1735 } 1736 else 1737 { 1738#ifdef DEBUG_SOUNDFILE 1739 pute("13\n"); 1740#endif 1741 } 1742 } 1743#ifdef DEBUG_SOUNDFILE 1744 pute("thread exit\n"); 1745#endif 1746 pthread_mutex_unlock(&x->x_mutex); 1747 return (0); 1748} 1749 1750/******** the object proper runs in the calling (parent) thread ****/ 1751 1752static void readsf_tick(t_readsf *x); 1753 1754static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize) 1755{ 1756 t_readsf *x; 1757 int nchannels = fnchannels, bufsize = fbufsize, i; 1758 char *buf; 1759 1760 if (nchannels < 1) 1761 nchannels = 1; 1762 else if (nchannels > MAXSFCHANS) 1763 nchannels = MAXSFCHANS; 1764 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels; 1765 else if (bufsize < MINBUFSIZE) 1766 bufsize = MINBUFSIZE; 1767 else if (bufsize > MAXBUFSIZE) 1768 bufsize = MAXBUFSIZE; 1769 buf = getbytes(bufsize); 1770 if (!buf) return (0); 1771 1772 x = (t_readsf *)pd_new(readsf_class); 1773 1774 for (i = 0; i < nchannels; i++) 1775 outlet_new(&x->x_obj, gensym("signal")); 1776 x->x_noutlets = nchannels; 1777 x->x_bangout = outlet_new(&x->x_obj, &s_bang); 1778 pthread_mutex_init(&x->x_mutex, 0); 1779 pthread_cond_init(&x->x_requestcondition, 0); 1780 pthread_cond_init(&x->x_answercondition, 0); 1781 x->x_vecsize = MAXVECSIZE; 1782 x->x_state = STATE_IDLE; 1783 x->x_clock = clock_new(x, (t_method)readsf_tick); 1784 x->x_canvas = canvas_getcurrent(); 1785 x->x_bytespersample = 2; 1786 x->x_sfchannels = 1; 1787 x->x_fd = -1; 1788 x->x_buf = buf; 1789 x->x_bufsize = bufsize; 1790 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0; 1791 pthread_create(&x->x_childthread, 0, readsf_child_main, x); 1792 return (x); 1793} 1794 1795static void readsf_tick(t_readsf *x) 1796{ 1797 outlet_bang(x->x_bangout); 1798} 1799 1800static t_int *readsf_perform(t_int *w) 1801{ 1802 t_readsf *x = (t_readsf *)(w[1]); 1803 int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j, 1804 bytespersample = x->x_bytespersample, 1805 bigendian = x->x_bigendian; 1806 float *fp; 1807 if (x->x_state == STATE_STREAM) 1808 { 1809 int wantbytes, nchannels, sfchannels = x->x_sfchannels; 1810 pthread_mutex_lock(&x->x_mutex); 1811 wantbytes = sfchannels * vecsize * bytespersample; 1812 while ( 1813 !x->x_eof && x->x_fifohead >= x->x_fifotail && 1814 x->x_fifohead < x->x_fifotail + wantbytes-1) 1815 { 1816#ifdef DEBUG_SOUNDFILE 1817 pute("wait...\n"); 1818#endif 1819 sfread_cond_signal(&x->x_requestcondition); 1820 sfread_cond_wait(&x->x_answercondition, &x->x_mutex); 1821#ifdef DEBUG_SOUNDFILE 1822 pute("done\n"); 1823#endif 1824 } 1825 if (x->x_eof && x->x_fifohead >= x->x_fifotail && 1826 x->x_fifohead < x->x_fifotail + wantbytes-1) 1827 { 1828 int xfersize; 1829 if (x->x_fileerror) 1830 { 1831 pd_error(x, "dsp: %s: %s", x->x_filename, 1832 (x->x_fileerror == EIO ? 1833 "unknown or bad header format" : 1834 strerror(x->x_fileerror))); 1835 } 1836 clock_delay(x->x_clock, 0); 1837 x->x_state = STATE_IDLE; 1838 1839 /* if there's a partial buffer left, copy it out. */ 1840 xfersize = (x->x_fifohead - x->x_fifotail + 1) / 1841 (sfchannels * bytespersample); 1842 if (xfersize) 1843 { 1844 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0, 1845 (unsigned char *)(x->x_buf + x->x_fifotail), xfersize, 1846 bytespersample, bigendian); 1847 vecsize -= xfersize; 1848 } 1849 /* then zero out the (rest of the) output */ 1850 for (i = 0; i < noutlets; i++) 1851 for (j = vecsize, fp = x->x_outvec[i] + xfersize; j--; ) 1852 *fp++ = 0; 1853 1854 sfread_cond_signal(&x->x_requestcondition); 1855 pthread_mutex_unlock(&x->x_mutex); 1856 return (w+2); 1857 } 1858 1859 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0, 1860 (unsigned char *)(x->x_buf + x->x_fifotail), vecsize, 1861 bytespersample, bigendian); 1862 1863 x->x_fifotail += wantbytes; 1864 if (x->x_fifotail >= x->x_fifosize) 1865 x->x_fifotail = 0; 1866 if ((--x->x_sigcountdown) <= 0) 1867 { 1868 sfread_cond_signal(&x->x_requestcondition); 1869 x->x_sigcountdown = x->x_sigperiod; 1870 } 1871 pthread_mutex_unlock(&x->x_mutex); 1872 } 1873 else 1874 { 1875 idle: 1876 for (i = 0; i < noutlets; i++) 1877 for (j = vecsize, fp = x->x_outvec[i]; j--; ) 1878 *fp++ = 0; 1879 } 1880 return (w+2); 1881} 1882 1883static void readsf_start(t_readsf *x) 1884{ 1885 /* start making output. If we're in the "startup" state change 1886 to the "running" state. */ 1887 if (x->x_state == STATE_STARTUP) 1888 x->x_state = STATE_STREAM; 1889 else pd_error(x, "readsf: start requested with no prior 'open'"); 1890} 1891 1892static void readsf_stop(t_readsf *x) 1893{ 1894 /* LATER rethink whether you need the mutex just to set a variable? */ 1895 pthread_mutex_lock(&x->x_mutex); 1896 x->x_state = STATE_IDLE; 1897 x->x_requestcode = REQUEST_CLOSE; 1898 sfread_cond_signal(&x->x_requestcondition); 1899 pthread_mutex_unlock(&x->x_mutex); 1900} 1901 1902static void readsf_float(t_readsf *x, t_floatarg f) 1903{ 1904 if (f != 0) 1905 readsf_start(x); 1906 else readsf_stop(x); 1907} 1908 1909 /* open method. Called as: 1910 open filename [skipframes headersize channels bytespersamp endianness] 1911 (if headersize is zero, header is taken to be automatically 1912 detected; thus, use the special "-1" to mean a truly headerless file.) 1913 */ 1914 1915static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv) 1916{ 1917 t_symbol *filesym = atom_getsymbolarg(0, argc, argv); 1918 t_float onsetframes = atom_getfloatarg(1, argc, argv); 1919 t_float headerbytes = atom_getfloatarg(2, argc, argv); 1920 t_float channels = atom_getfloatarg(3, argc, argv); 1921 t_float bytespersamp = atom_getfloatarg(4, argc, argv); 1922 t_symbol *endian = atom_getsymbolarg(5, argc, argv); 1923 if (!*filesym->s_name) 1924 return; 1925 pthread_mutex_lock(&x->x_mutex); 1926 x->x_requestcode = REQUEST_OPEN; 1927 x->x_filename = filesym->s_name; 1928 x->x_fifotail = 0; 1929 x->x_fifohead = 0; 1930 if (*endian->s_name == 'b') 1931 x->x_bigendian = 1; 1932 else if (*endian->s_name == 'l') 1933 x->x_bigendian = 0; 1934 else if (*endian->s_name) 1935 pd_error(x, "endianness neither 'b' nor 'l'"); 1936 else x->x_bigendian = garray_ambigendian(); 1937 x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0); 1938 x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes : 1939 (headerbytes == 0 ? -1 : 0)); 1940 x->x_sfchannels = (channels >= 1 ? channels : 1); 1941 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2); 1942 x->x_eof = 0; 1943 x->x_fileerror = 0; 1944 x->x_state = STATE_STARTUP; 1945 sfread_cond_signal(&x->x_requestcondition); 1946 pthread_mutex_unlock(&x->x_mutex); 1947} 1948 1949static void readsf_dsp(t_readsf *x, t_signal **sp) 1950{ 1951 int i, noutlets = x->x_noutlets; 1952 pthread_mutex_lock(&x->x_mutex); 1953 x->x_vecsize = sp[0]->s_n; 1954 1955 x->x_sigperiod = (x->x_fifosize / 1956 (x->x_bytespersample * x->x_sfchannels * x->x_vecsize)); 1957 for (i = 0; i < noutlets; i++) 1958 x->x_outvec[i] = sp[i]->s_vec; 1959 pthread_mutex_unlock(&x->x_mutex); 1960 dsp_add(readsf_perform, 1, x); 1961} 1962 1963static void readsf_print(t_readsf *x) 1964{ 1965 post("state %d", x->x_state); 1966 post("fifo head %d", x->x_fifohead); 1967 post("fifo tail %d", x->x_fifotail); 1968 post("fifo size %d", x->x_fifosize); 1969 post("fd %d", x->x_fd); 1970 post("eof %d", x->x_eof); 1971} 1972 1973static void readsf_free(t_readsf *x) 1974{ 1975 /* request QUIT and wait for acknowledge */ 1976 void *threadrtn; 1977 pthread_mutex_lock(&x->x_mutex); 1978 x->x_requestcode = REQUEST_QUIT; 1979 sfread_cond_signal(&x->x_requestcondition); 1980 while (x->x_requestcode != REQUEST_NOTHING) 1981 { 1982 sfread_cond_signal(&x->x_requestcondition); 1983 sfread_cond_wait(&x->x_answercondition, &x->x_mutex); 1984 } 1985 pthread_mutex_unlock(&x->x_mutex); 1986 if (pthread_join(x->x_childthread, &threadrtn)) 1987 error("readsf_free: join failed"); 1988 1989 pthread_cond_destroy(&x->x_requestcondition); 1990 pthread_cond_destroy(&x->x_answercondition); 1991 pthread_mutex_destroy(&x->x_mutex); 1992 freebytes(x->x_buf, x->x_bufsize); 1993 clock_free(x->x_clock); 1994} 1995 1996static void readsf_setup(void) 1997{ 1998 readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new, 1999 (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0); 2000 class_addfloat(readsf_class, (t_method)readsf_float); 2001 class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0); 2002 class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0); 2003 class_addmethod(readsf_class, (t_method)readsf_dsp, gensym("dsp"), 0); 2004 class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"), 2005 A_GIMME, 0); 2006 class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0); 2007} 2008 2009/******************************* writesf *******************/ 2010 2011static t_class *writesf_class; 2012 2013#define t_writesf t_readsf /* just re-use the structure */ 2014 2015/************** the child thread which performs file I/O ***********/ 2016 2017static void *writesf_child_main(void *zz) 2018{ 2019 t_writesf *x = zz; 2020#ifdef DEBUG_SOUNDFILE 2021 pute("1\n"); 2022#endif 2023 pthread_mutex_lock(&x->x_mutex); 2024 while (1) 2025 { 2026#ifdef DEBUG_SOUNDFILE 2027 pute("0\n"); 2028#endif 2029 if (x->x_requestcode == REQUEST_NOTHING) 2030 { 2031#ifdef DEBUG_SOUNDFILE 2032 pute("wait 2\n"); 2033#endif 2034 sfread_cond_signal(&x->x_answercondition); 2035 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex); 2036#ifdef DEBUG_SOUNDFILE 2037 pute("3\n"); 2038#endif 2039 } 2040 else if (x->x_requestcode == REQUEST_OPEN) 2041 { 2042 char boo[80]; 2043 int fd, sysrtn, writebytes; 2044 2045 /* copy file stuff out of the data structure so we can 2046 relinquish the mutex while we're in open_soundfile(). */ 2047 long onsetframes = x->x_onsetframes; 2048 long bytelimit = 0x7fffffff; 2049 int skipheaderbytes = x->x_skipheaderbytes; 2050 int bytespersample = x->x_bytespersample; 2051 int sfchannels = x->x_sfchannels; 2052 int bigendian = x->x_bigendian; 2053 int filetype = x->x_filetype; 2054 char *filename = x->x_filename; 2055 t_canvas *canvas = x->x_canvas; 2056 float samplerate = x->x_samplerate; 2057 2058 /* alter the request code so that an ensuing "open" will get 2059 noticed. */ 2060#ifdef DEBUG_SOUNDFILE 2061 pute("4\n"); 2062#endif 2063 x->x_requestcode = REQUEST_BUSY; 2064 x->x_fileerror = 0; 2065 2066 /* if there's already a file open, close it */ 2067 if (x->x_fd >= 0) 2068 { 2069 pthread_mutex_unlock(&x->x_mutex); 2070 close (x->x_fd); 2071 pthread_mutex_lock(&x->x_mutex); 2072 x->x_fd = -1; 2073 if (x->x_requestcode != REQUEST_BUSY) 2074 continue; 2075 } 2076 /* open the soundfile with the mutex unlocked */ 2077 pthread_mutex_unlock(&x->x_mutex); 2078 fd = create_soundfile(canvas, filename, filetype, 0, 2079 bytespersample, bigendian, sfchannels, 2080 garray_ambigendian() != bigendian, samplerate); 2081 pthread_mutex_lock(&x->x_mutex); 2082#ifdef DEBUG_SOUNDFILE 2083 pute("5\n"); 2084#endif 2085 2086 if (fd < 0) 2087 { 2088 x->x_fd = -1; 2089 x->x_eof = 1; 2090 x->x_fileerror = errno; 2091#ifdef DEBUG_SOUNDFILE 2092 pute("open failed\n"); 2093 pute(filename); 2094#endif 2095 x->x_requestcode = REQUEST_NOTHING; 2096 continue; 2097 } 2098 /* check if another request has been made; if so, field it */ 2099 if (x->x_requestcode != REQUEST_BUSY) 2100 continue; 2101#ifdef DEBUG_SOUNDFILE 2102 pute("6\n"); 2103#endif 2104 x->x_fd = fd; 2105 x->x_fifotail = 0; 2106 x->x_itemswritten = 0; 2107 x->x_swap = garray_ambigendian() != bigendian; 2108 /* in a loop, wait for the fifo to have data and write it 2109 to disk */ 2110 while (x->x_requestcode == REQUEST_BUSY || 2111 (x->x_requestcode == REQUEST_CLOSE && 2112 x->x_fifohead != x->x_fifotail)) 2113 { 2114 int fifosize = x->x_fifosize, fifotail; 2115 char *buf = x->x_buf; 2116#ifdef DEBUG_SOUNDFILE 2117 pute("77\n"); 2118#endif 2119 2120 /* if the head is < the tail, we can immediately write 2121 from tail to end of fifo to disk; otherwise we hold off 2122 writing until there are at least WRITESIZE bytes in the 2123 buffer */ 2124 if (x->x_fifohead < x->x_fifotail || 2125 x->x_fifohead >= x->x_fifotail + WRITESIZE 2126 || (x->x_requestcode == REQUEST_CLOSE && 2127 x->x_fifohead != x->x_fifotail)) 2128 { 2129 writebytes = (x->x_fifohead < x->x_fifotail ? 2130 fifosize : x->x_fifohead) - x->x_fifotail; 2131 if (writebytes > READSIZE) 2132 writebytes = READSIZE; 2133 } 2134 else 2135 { 2136#ifdef DEBUG_SOUNDFILE 2137 pute("wait 7a ...\n"); 2138#endif 2139 sfread_cond_signal(&x->x_answercondition); 2140#ifdef DEBUG_SOUNDFILE 2141 pute("signalled\n"); 2142#endif 2143 sfread_cond_wait(&x->x_requestcondition, 2144 &x->x_mutex); 2145#ifdef DEBUG_SOUNDFILE 2146 pute("7a done\n"); 2147#endif 2148 continue; 2149 } 2150#ifdef DEBUG_SOUNDFILE 2151 pute("8\n"); 2152#endif 2153 fifotail = x->x_fifotail; 2154 fd = x->x_fd; 2155 pthread_mutex_unlock(&x->x_mutex); 2156 sysrtn = write(fd, buf + fifotail, writebytes); 2157 pthread_mutex_lock(&x->x_mutex); 2158 if (x->x_requestcode != REQUEST_BUSY && 2159 x->x_requestcode != REQUEST_CLOSE) 2160 break; 2161 if (sysrtn < writebytes) 2162 { 2163#ifdef DEBUG_SOUNDFILE 2164 pute("fileerror\n"); 2165#endif 2166 x->x_fileerror = errno; 2167 break; 2168 } 2169 else 2170 { 2171 x->x_fifotail += sysrtn; 2172 if (x->x_fifotail == fifosize) 2173 x->x_fifotail = 0; 2174 } 2175 x->x_itemswritten += 2176 sysrtn / (x->x_bytespersample * x->x_sfchannels); 2177 sprintf(boo, "after: head %d, tail %d\n", 2178 x->x_fifohead, x->x_fifotail); 2179#ifdef DEBUG_SOUNDFILE 2180 pute(boo); 2181#endif 2182 /* signal parent in case it's waiting for data */ 2183 sfread_cond_signal(&x->x_answercondition); 2184 } 2185 } 2186 else if (x->x_requestcode == REQUEST_CLOSE || 2187 x->x_requestcode == REQUEST_QUIT) 2188 { 2189 int quit = (x->x_requestcode == REQUEST_QUIT); 2190 if (x->x_fd >= 0) 2191 { 2192 int bytesperframe = x->x_bytespersample * x->x_sfchannels; 2193 int bigendian = x->x_bigendian; 2194 char *filename = x->x_filename; 2195 int fd = x->x_fd; 2196 int filetype = x->x_filetype; 2197 int itemswritten = x->x_itemswritten; 2198 int swap = x->x_swap; 2199 pthread_mutex_unlock(&x->x_mutex); 2200 2201 soundfile_finishwrite(x, filename, fd, 2202 filetype, 0x7fffffff, itemswritten, 2203 bytesperframe, swap); 2204 close (fd); 2205 2206 pthread_mutex_lock(&x->x_mutex); 2207 x->x_fd = -1; 2208 } 2209 x->x_requestcode = REQUEST_NOTHING; 2210 sfread_cond_signal(&x->x_answercondition); 2211 if (quit) 2212 break; 2213 } 2214 else 2215 { 2216#ifdef DEBUG_SOUNDFILE 2217 pute("13\n"); 2218#endif 2219 } 2220 } 2221#ifdef DEBUG_SOUNDFILE 2222 pute("thread exit\n"); 2223#endif 2224 pthread_mutex_unlock(&x->x_mutex); 2225 return (0); 2226} 2227 2228/******** the object proper runs in the calling (parent) thread ****/ 2229 2230static void writesf_tick(t_writesf *x); 2231 2232static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize) 2233{ 2234 t_writesf *x; 2235 int nchannels = fnchannels, bufsize = fbufsize, i; 2236 char *buf; 2237 2238 if (nchannels < 1) 2239 nchannels = 1; 2240 else if (nchannels > MAXSFCHANS) 2241 nchannels = MAXSFCHANS; 2242 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels; 2243 else if (bufsize < MINBUFSIZE) 2244 bufsize = MINBUFSIZE; 2245 else if (bufsize > MAXBUFSIZE) 2246 bufsize = MAXBUFSIZE; 2247 buf = getbytes(bufsize); 2248 if (!buf) return (0); 2249 2250 x = (t_writesf *)pd_new(writesf_class); 2251 2252 for (i = 1; i < nchannels; i++) 2253 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); 2254 2255 x->x_f = 0; 2256 x->x_sfchannels = nchannels; 2257 pthread_mutex_init(&x->x_mutex, 0); 2258 pthread_cond_init(&x->x_requestcondition, 0); 2259 pthread_cond_init(&x->x_answercondition, 0); 2260 x->x_vecsize = MAXVECSIZE; 2261 x->x_insamplerate = x->x_samplerate = 0; 2262 x->x_state = STATE_IDLE; 2263 x->x_clock = 0; /* no callback needed here */ 2264 x->x_canvas = canvas_getcurrent(); 2265 x->x_bytespersample = 2; 2266 x->x_fd = -1; 2267 x->x_buf = buf; 2268 x->x_bufsize = bufsize; 2269 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0; 2270 pthread_create(&x->x_childthread, 0, writesf_child_main, x); 2271 return (x); 2272} 2273 2274static t_int *writesf_perform(t_int *w) 2275{ 2276 t_writesf *x = (t_writesf *)(w[1]); 2277 int vecsize = x->x_vecsize, sfchannels = x->x_sfchannels, i, j, 2278 bytespersample = x->x_bytespersample, 2279 bigendian = x->x_bigendian; 2280 float *fp; 2281 if (x->x_state == STATE_STREAM) 2282 { 2283 int wantbytes; 2284 pthread_mutex_lock(&x->x_mutex); 2285 wantbytes = sfchannels * vecsize * bytespersample; 2286 while (x->x_fifotail > x->x_fifohead && 2287 x->x_fifotail < x->x_fifohead + wantbytes + 1) 2288 { 2289#ifdef DEBUG_SOUNDFILE 2290 pute("wait...\n"); 2291#endif 2292 sfread_cond_signal(&x->x_requestcondition); 2293 sfread_cond_wait(&x->x_answercondition, &x->x_mutex); 2294#ifdef DEBUG_SOUNDFILE 2295 pute("done\n"); 2296#endif 2297 } 2298 2299 soundfile_xferout(sfchannels, x->x_outvec, 2300 (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0, 2301 bytespersample, bigendian, 1.); 2302 2303 x->x_fifohead += wantbytes; 2304 if (x->x_fifohead >= x->x_fifosize) 2305 x->x_fifohead = 0; 2306 if ((--x->x_sigcountdown) <= 0) 2307 { 2308#ifdef DEBUG_SOUNDFILE 2309 pute("signal 1\n"); 2310#endif 2311 sfread_cond_signal(&x->x_requestcondition); 2312 x->x_sigcountdown = x->x_sigperiod; 2313 } 2314 pthread_mutex_unlock(&x->x_mutex); 2315 } 2316 return (w+2); 2317} 2318 2319static void writesf_start(t_writesf *x) 2320{ 2321 /* start making output. If we're in the "startup" state change 2322 to the "running" state. */ 2323 if (x->x_state == STATE_STARTUP) 2324 x->x_state = STATE_STREAM; 2325 else 2326 pd_error(x, "writesf: start requested with no prior 'open'"); 2327} 2328 2329static void writesf_stop(t_writesf *x) 2330{ 2331 /* LATER rethink whether you need the mutex just to set a Svariable? */ 2332 pthread_mutex_lock(&x->x_mutex); 2333 x->x_state = STATE_IDLE; 2334 x->x_requestcode = REQUEST_CLOSE; 2335#ifdef DEBUG_SOUNDFILE 2336 pute("signal 2\n"); 2337#endif 2338 sfread_cond_signal(&x->x_requestcondition); 2339 pthread_mutex_unlock(&x->x_mutex); 2340} 2341 2342 2343 /* open method. Called as: open [args] filename with args as in 2344 soundfiler_writeargparse(). 2345 */ 2346 2347static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) 2348{ 2349 t_symbol *filesym; 2350 int filetype, bytespersamp, swap, bigendian, normalize; 2351 long onset, nframes; 2352 float samplerate; 2353 if (soundfiler_writeargparse(x, &argc, 2354 &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian, 2355 &normalize, &onset, &nframes, &samplerate)) 2356 { 2357 pd_error(x, 2358 "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ..."); 2359 post("... [-big,-little] [-rate ####] filename"); 2360 } 2361 if (normalize || onset || (nframes != 0x7fffffff)) 2362 pd_error(x, "normalize/onset/nframes argument to writesf~: ignored"); 2363 if (argc) 2364 pd_error(x, "extra argument(s) to writesf~: ignored"); 2365 pthread_mutex_lock(&x->x_mutex); 2366 x->x_bytespersample = bytespersamp; 2367 x->x_swap = swap; 2368 x->x_bigendian = bigendian; 2369 x->x_filename = filesym->s_name; 2370 x->x_filetype = filetype; 2371 x->x_itemswritten = 0; 2372 x->x_requestcode = REQUEST_OPEN; 2373 x->x_fifotail = 0; 2374 x->x_fifohead = 0; 2375 x->x_eof = 0; 2376 x->x_fileerror = 0; 2377 x->x_state = STATE_STARTUP; 2378 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2); 2379 if (samplerate > 0) 2380 x->x_samplerate = samplerate; 2381 else if (x->x_insamplerate > 0) 2382 x->x_samplerate = x->x_insamplerate; 2383 else x->x_samplerate = sys_getsr(); 2384 /* set fifosize from bufsize. fifosize must be a 2385 multiple of the number of bytes eaten for each DSP 2386 tick. */ 2387 x->x_fifosize = x->x_bufsize - (x->x_bufsize % 2388 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE)); 2389 /* arrange for the "request" condition to be signalled 16 2390 times per buffer */ 2391 x->x_sigcountdown = x->x_sigperiod = 2392 (x->x_fifosize / 2393 (16 * x->x_bytespersample * x->x_sfchannels * 2394 x->x_vecsize)); 2395 sfread_cond_signal(&x->x_requestcondition); 2396 pthread_mutex_unlock(&x->x_mutex); 2397} 2398 2399static void writesf_dsp(t_writesf *x, t_signal **sp) 2400{ 2401 int i, ninlets = x->x_sfchannels; 2402 pthread_mutex_lock(&x->x_mutex); 2403 x->x_vecsize = sp[0]->s_n; 2404 2405 x->x_sigperiod = (x->x_fifosize / 2406 (x->x_bytespersample * ninlets * x->x_vecsize)); 2407 for (i = 0; i < ninlets; i++) 2408 x->x_outvec[i] = sp[i]->s_vec; 2409 x->x_insamplerate = sp[0]->s_sr; 2410 pthread_mutex_unlock(&x->x_mutex); 2411 dsp_add(writesf_perform, 1, x); 2412} 2413 2414static void writesf_print(t_writesf *x) 2415{ 2416 post("state %d", x->x_state); 2417 post("fifo head %d", x->x_fifohead); 2418 post("fifo tail %d", x->x_fifotail); 2419 post("fifo size %d", x->x_fifosize); 2420 post("fd %d", x->x_fd); 2421 post("eof %d", x->x_eof); 2422} 2423 2424static void writesf_free(t_writesf *x) 2425{ 2426 /* request QUIT and wait for acknowledge */ 2427 void *threadrtn; 2428 pthread_mutex_lock(&x->x_mutex); 2429 x->x_requestcode = REQUEST_QUIT; 2430 /* post("stopping writesf thread..."); */ 2431 sfread_cond_signal(&x->x_requestcondition); 2432 while (x->x_requestcode != REQUEST_NOTHING) 2433 { 2434 /* post("signalling..."); */ 2435 sfread_cond_signal(&x->x_requestcondition); 2436 sfread_cond_wait(&x->x_answercondition, &x->x_mutex); 2437 } 2438 pthread_mutex_unlock(&x->x_mutex); 2439 if (pthread_join(x->x_childthread, &threadrtn)) 2440 error("writesf_free: join failed"); 2441 /* post("... done."); */ 2442 2443 pthread_cond_destroy(&x->x_requestcondition); 2444 pthread_cond_destroy(&x->x_answercondition); 2445 pthread_mutex_destroy(&x->x_mutex); 2446 freebytes(x->x_buf, x->x_bufsize); 2447} 2448 2449static void writesf_setup(void) 2450{ 2451 writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new, 2452 (t_method)writesf_free, sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0); 2453 class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0); 2454 class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0); 2455 class_addmethod(writesf_class, (t_method)writesf_dsp, gensym("dsp"), 0); 2456 class_addmethod(writesf_class, (t_method)writesf_open, gensym("open"), 2457 A_GIMME, 0); 2458 class_addmethod(writesf_class, (t_method)writesf_print, gensym("print"), 0); 2459 CLASS_MAINSIGNALIN(writesf_class, t_writesf, x_f); 2460} 2461 2462#endif 2463 2464/* ------------------------ global setup routine ------------------------- */ 2465 2466void d_soundfile_setup(void) 2467{ 2468 soundfiler_setup(); 2469#ifndef FIXEDPOINT 2470 readsf_setup(); 2471 writesf_setup(); 2472#endif 2473} 2474