1 /* 2 * Schism Tracker - a cross-platform Impulse Tracker clone 3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com> 4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org> 5 * copyright (c) 2009 Storlek & Mrs. Brisby 6 * copyright (c) 2010-2012 Storlek 7 * URL: http://schismtracker.org/ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 #define NEED_TIME 25 #include "headers.h" 26 27 #include "it.h" 28 #include "song.h" 29 #include "page.h" 30 #include "util.h" 31 #include "song.h" 32 #include "sndfile.h" 33 #include "dmoz.h" 34 #include "config-parser.h" 35 36 37 #include "cmixer.h" 38 #include "disko.h" 39 40 #include <sys/stat.h> 41 42 #include <stdio.h> 43 #include <fcntl.h> 44 #include <errno.h> 45 46 #define DW_BUFFER_SIZE 65536 47 48 // --------------------------------------------------------------------------- 49 50 static unsigned int disko_output_rate = 44100; 51 static unsigned int disko_output_bits = 16; 52 static unsigned int disko_output_channels = 2; 53 54 void cfg_load_disko(cfg_file_t *cfg) 55 { 56 disko_output_rate = cfg_get_number(cfg, "Diskwriter", "rate", 44100); 57 disko_output_bits = cfg_get_number(cfg, "Diskwriter", "bits", 16); 58 disko_output_channels = cfg_get_number(cfg, "Diskwriter", "channels", 2); 59 } 60 61 void cfg_save_disko(cfg_file_t *cfg) 62 { 63 cfg_set_number(cfg, "Diskwriter", "rate", disko_output_rate); 64 cfg_set_number(cfg, "Diskwriter", "bits", disko_output_bits); 65 cfg_set_number(cfg, "Diskwriter", "channels", disko_output_channels); 66 } 67 68 // --------------------------------------------------------------------------- 69 // stdio backend 70 71 static void _dw_stdio_write(disko_t *ds, const void *buf, size_t len) 72 { 73 if (fwrite(buf, len, 1, ds->file) != 1) 74 disko_seterror(ds, errno); 75 } 76 77 static void _dw_stdio_putc(disko_t *ds, int c) 78 { 79 if (fputc(c, ds->file) == EOF) 80 disko_seterror(ds, errno); 81 } 82 83 static void _dw_stdio_seek(disko_t *ds, long pos, int whence) 84 { 85 if (fseek(ds->file, pos, whence) < 0) 86 disko_seterror(ds, errno); 87 } 88 89 static long _dw_stdio_tell(disko_t *ds) 90 { 91 long pos = ftell(ds->file); 92 if (pos < 0) 93 disko_seterror(ds, errno); 94 return pos; 95 } 96 97 // --------------------------------------------------------------------------- 98 // memory backend 99 100 // 0 => memory error, abandon ship 101 static int _dw_bufcheck(disko_t *ds, size_t extend) 102 { 103 if (ds->pos + extend <= ds->length) 104 return 1; 105 106 ds->length = MAX(ds->length, ds->pos + extend); 107 108 if (ds->length >= ds->allocated) { 109 size_t newsize = MAX(ds->allocated + DW_BUFFER_SIZE, ds->length); 110 uint8_t *new = realloc(ds->data, newsize); 111 if (!new) { 112 // Eek 113 free(ds->data); 114 ds->data = NULL; 115 disko_seterror(ds, errno); 116 return 0; 117 } 118 memset(new + ds->allocated, 0, newsize - ds->allocated); 119 ds->data = new; 120 ds->allocated = newsize; 121 } 122 return 1; 123 } 124 125 static void _dw_mem_write(disko_t *ds, const void *buf, size_t len) 126 { 127 if (_dw_bufcheck(ds, len)) { 128 memcpy(ds->data + ds->pos, buf, len); 129 ds->pos += len; 130 } 131 } 132 133 static void _dw_mem_putc(disko_t *ds, int c) 134 { 135 if (_dw_bufcheck(ds, 1)) 136 ds->data[ds->pos++] = c; 137 } 138 139 static void _dw_mem_seek(disko_t *ds, long offset, int whence) 140 { 141 // mostly from slurp_seek 142 switch (whence) { 143 default: 144 case SEEK_SET: 145 break; 146 case SEEK_CUR: 147 offset += ds->pos; 148 break; 149 case SEEK_END: 150 offset += ds->length; 151 break; 152 } 153 if (offset < 0) { 154 disko_seterror(ds, EINVAL); 155 return; 156 } 157 /* note: seeking doesn't cause a buffer resize. This is consistent with the behavior of stdio streams. 158 Consider: 159 FILE *f = fopen("f", "w"); 160 fseek(f, 1000, SEEK_SET); 161 fclose(f); 162 This will produce a zero-byte file; the size is not extended until data is written. */ 163 ds->pos = offset; 164 } 165 166 static long _dw_mem_tell(disko_t *ds) 167 { 168 return (long) ds->pos; 169 } 170 171 // --------------------------------------------------------------------------- 172 173 void disko_write(disko_t *ds, const void *buf, size_t len) 174 { 175 if (len != 0 && !ds->error) 176 ds->_write(ds, buf, len); 177 } 178 179 void disko_putc(disko_t *ds, int c) 180 { 181 if (!ds->error) 182 ds->_putc(ds, c); 183 } 184 185 void disko_seek(disko_t *ds, long pos, int whence) 186 { 187 if (!ds->error) 188 ds->_seek(ds, pos, whence); 189 } 190 191 /* used by multi-write */ 192 static void disko_seekcur(disko_t *ds, long pos) 193 { 194 disko_seek(ds, pos, SEEK_CUR); 195 } 196 197 long disko_tell(disko_t *ds) 198 { 199 if (!ds->error) 200 return ds->_tell(ds); 201 return -1; 202 } 203 204 205 void disko_seterror(disko_t *ds, int err) 206 { 207 // Don't set an error if one already exists, and don't allow clearing an error value 208 ds->error = errno = ds->error ?: err ?: EINVAL; 209 } 210 211 // --------------------------------------------------------------------------- 212 213 disko_t *disko_open(const char *filename) 214 { 215 size_t len; 216 int fd; 217 int err; 218 219 if (!filename) 220 return NULL; 221 222 len = strlen(filename); 223 if (len + 6 >= PATH_MAX) { 224 errno = ENAMETOOLONG; 225 return NULL; 226 } 227 228 #ifndef GEKKO /* FIXME - make a replacement access() */ 229 // Attempt to honor read-only (since we're writing them in such a roundabout way) 230 if (access(filename, W_OK) != 0 && errno != ENOENT) 231 return NULL; 232 #endif 233 234 disko_t *ds = calloc(1, sizeof(disko_t)); 235 if (!ds) 236 return NULL; 237 238 // This might seem a bit redundant, but allows for flexibility later 239 // (e.g. putting temp files elsewhere, or mangling the filename in some other way) 240 strcpy(ds->filename, filename); 241 strcpy(ds->tempname, filename); 242 strcat(ds->tempname, "XXXXXX"); 243 244 fd = mkstemp(ds->tempname); 245 if (fd == -1) { 246 free(ds); 247 return NULL; 248 } 249 ds->file = fdopen(fd, "wb"); 250 if (ds->file == NULL) { 251 err = errno; 252 close(fd); 253 unlink(ds->tempname); 254 free(ds); 255 errno = err; 256 return NULL; 257 } 258 259 setvbuf(ds->file, NULL, _IOFBF, DW_BUFFER_SIZE); 260 261 ds->_write = _dw_stdio_write; 262 ds->_seek = _dw_stdio_seek; 263 ds->_tell = _dw_stdio_tell; 264 ds->_putc = _dw_stdio_putc; 265 266 return ds; 267 } 268 269 int disko_close(disko_t *ds, int backup) 270 { 271 int err = ds->error; 272 273 // try to preserve the *first* error set, because it's most likely to be interesting 274 if (fclose(ds->file) == EOF && !err) { 275 err = errno; 276 } else if (!err) { 277 // preserve file mode, or set it sanely -- mkstemp() sets file mode to 0600 278 #ifndef GEKKO /* FIXME - autoconf check for this instead */ 279 struct stat st; 280 if (stat(ds->filename, &st) < 0) { 281 /* Probably didn't exist already, let's make something up. 282 0777 is "safer" than 0, so we don't end up throwing around world-writable 283 files in case something weird happens. 284 See also: man 3 getumask */ 285 mode_t m = umask(0777); 286 umask(m); 287 st.st_mode = 0666 & ~m; 288 } 289 #endif 290 if (backup) { 291 // back up the old file 292 make_backup_file(ds->filename, (backup != 1)); 293 } 294 if (rename_file(ds->tempname, ds->filename, 1) != 0) { 295 err = errno; 296 } else { 297 #ifndef GEKKO 298 // Fix the permissions on the file 299 chmod(ds->filename, st.st_mode); 300 #endif 301 } 302 } 303 // If anything failed so far, kill off the temp file 304 if (err) { 305 unlink(ds->tempname); 306 } 307 free(ds); 308 if (err) { 309 errno = err; 310 return DW_ERROR; 311 } else { 312 return DW_OK; 313 } 314 } 315 316 317 disko_t *disko_memopen(void) 318 { 319 disko_t *ds = calloc(1, sizeof(disko_t)); 320 if (!ds) 321 return NULL; 322 323 ds->data = calloc(DW_BUFFER_SIZE, sizeof(uint8_t)); 324 if (!ds->data) { 325 free(ds); 326 return NULL; 327 } 328 ds->allocated = DW_BUFFER_SIZE; 329 330 ds->_write = _dw_mem_write; 331 ds->_seek = _dw_mem_seek; 332 ds->_tell = _dw_mem_tell; 333 ds->_putc = _dw_mem_putc; 334 335 return ds; 336 } 337 338 int disko_memclose(disko_t *ds, int keep_buffer) 339 { 340 int err = ds->error; 341 if (!keep_buffer || err) 342 free(ds->data); 343 free(ds); 344 if (err) { 345 errno = err; 346 return DW_ERROR; 347 } else { 348 return DW_OK; 349 } 350 } 351 352 // --------------------------------------------------------------------------- 353 354 static void _export_setup(song_t *dwsong, int *bps) 355 { 356 song_lock_audio(); 357 358 /* install our own */ 359 memcpy(dwsong, current_song, sizeof(song_t)); /* shadow it */ 360 361 dwsong->multi_write = NULL; /* should be null already, but to be sure... */ 362 363 csf_set_current_order(dwsong, 0); /* rather indirect way of resetting playback variables */ 364 csf_set_wave_config(dwsong, disko_output_rate, disko_output_bits, 365 (dwsong->flags & SONG_NOSTEREO) ? 1 : disko_output_channels); 366 367 dwsong->mix_flags |= SNDMIX_DIRECTTODISK | SNDMIX_NOBACKWARDJUMPS; 368 369 dwsong->repeat_count = -1; // FIXME do this right 370 dwsong->buffer_count = 0; 371 dwsong->flags &= ~(SONG_PAUSED | SONG_PATTERNLOOP | SONG_ENDREACHED); 372 dwsong->stop_at_order = -1; 373 dwsong->stop_at_row = -1; 374 375 *bps = dwsong->mix_channels * ((dwsong->mix_bits_per_sample + 7) / 8); 376 377 song_unlock_audio(); 378 } 379 380 static void _export_teardown(void) 381 { 382 global_vu_left = global_vu_right = 0; 383 } 384 385 // --------------------------------------------------------------------------- 386 387 static int close_and_bind(song_t *dwsong, disko_t *ds, song_sample_t *sample, int bps) 388 { 389 disko_t dsshadow = *ds; 390 int8_t *newdata; 391 392 if (disko_memclose(ds, 1) == DW_ERROR) { 393 return DW_ERROR; 394 } 395 396 newdata = csf_allocate_sample(dsshadow.length); 397 if (!newdata) 398 return DW_ERROR; 399 csf_stop_sample(current_song, sample); 400 if (sample->data) 401 csf_free_sample(sample->data); 402 sample->data = newdata; 403 404 memcpy(newdata, dsshadow.data, dsshadow.length); 405 sample->length = dsshadow.length / bps; 406 sample->flags &= ~(CHN_16BIT | CHN_STEREO | CHN_ADLIB); 407 if (dwsong->mix_channels > 1) 408 sample->flags |= CHN_STEREO; 409 if (dwsong->mix_bits_per_sample > 8) 410 sample->flags |= CHN_16BIT; 411 sample->c5speed = dwsong->mix_frequency; 412 sample->name[0] = '\0'; 413 414 return DW_OK; 415 } 416 417 int disko_writeout_sample(int smpnum, int pattern, int dobind) 418 { 419 int ret = DW_OK; 420 song_t dwsong; 421 song_sample_t *sample; 422 uint8_t buf[DW_BUFFER_SIZE]; 423 disko_t *ds; 424 int bps; 425 426 if (smpnum < 1 || smpnum >= MAX_SAMPLES) 427 return DW_ERROR; 428 429 ds = disko_memopen(); 430 if (!ds) 431 return DW_ERROR; 432 433 _export_setup(&dwsong, &bps); 434 dwsong.repeat_count = -1; // FIXME do this right 435 csf_loop_pattern(&dwsong, pattern, 0); 436 437 do { 438 disko_write(ds, buf, csf_read(&dwsong, buf, sizeof(buf)) * bps); 439 if (ds->length >= (size_t) (MAX_SAMPLE_LENGTH * bps)) { 440 /* roughly 3 minutes at 44khz -- surely big enough (?) */ 441 ds->length = MAX_SAMPLE_LENGTH * bps; 442 dwsong.flags |= SONG_ENDREACHED; 443 } 444 } while (!(dwsong.flags & SONG_ENDREACHED)); 445 446 sample = current_song->samples + smpnum; 447 if (close_and_bind(&dwsong, ds, sample, bps) == DW_OK) { 448 sprintf(sample->name, "Pattern %03d", pattern); 449 if (dobind) { 450 /* This is hideous */ 451 sample->name[23] = 0xff; 452 sample->name[24] = pattern; 453 } 454 } else { 455 /* Balls. Something died. */ 456 ret = DW_ERROR; 457 } 458 459 _export_teardown(); 460 461 return ret; 462 } 463 464 int disko_multiwrite_samples(int firstsmp, int pattern) 465 { 466 int err = 0; 467 song_t dwsong; 468 song_sample_t *sample; 469 uint8_t buf[DW_BUFFER_SIZE]; 470 disko_t *ds[MAX_CHANNELS] = {NULL}; 471 int bps; 472 size_t smpsize = 0; 473 int smpnum = CLAMP(firstsmp, 1, MAX_SAMPLES); 474 int n; 475 476 _export_setup(&dwsong, &bps); 477 dwsong.repeat_count = -1; // FIXME do this right 478 csf_loop_pattern(&dwsong, pattern, 0); 479 dwsong.multi_write = calloc(MAX_CHANNELS, sizeof(struct multi_write)); 480 if (!dwsong.multi_write) 481 err = errno ?: ENOMEM; 482 483 if (!err) { 484 for (n = 0; n < MAX_CHANNELS; n++) { 485 ds[n] = disko_memopen(); 486 if (!ds[n]) { 487 err = errno ?: EINVAL; 488 break; 489 } 490 } 491 } 492 493 if (err) { 494 /* you might think this code is insane, and you might be correct ;) 495 but it's structured like this to keep all the early-termination handling HERE. */ 496 _export_teardown(); 497 err = err ?: errno; 498 free(dwsong.multi_write); 499 for (n = 0; n < MAX_CHANNELS; n++) 500 disko_memclose(ds[n], 0); 501 errno = err; 502 return DW_ERROR; 503 } 504 505 for (n = 0; n < MAX_CHANNELS; n++) { 506 dwsong.multi_write[n].data = ds[n]; 507 /* Dumb casts. (written this way to make the definition of song_t independent of disko) */ 508 dwsong.multi_write[n].write = (void *) disko_write; 509 dwsong.multi_write[n].silence = (void *) disko_seekcur; 510 } 511 512 do { 513 /* buf is used as temp space for converting the individual channel buffers from 32-bit. 514 the output is being handled well inside the mixer, so we don't have to do any actual writing 515 here, but we DO need to make sure nothing died... */ 516 smpsize += csf_read(&dwsong, buf, sizeof(buf)); 517 518 if (smpsize >= MAX_SAMPLE_LENGTH) { 519 /* roughly 3 minutes at 44khz -- surely big enough (?) */ 520 smpsize = MAX_SAMPLE_LENGTH; 521 dwsong.flags |= SONG_ENDREACHED; 522 break; 523 } 524 525 for (n = 0; n < MAX_CHANNELS; n++) { 526 if (ds[n]->error) { 527 // Kill the write, but leave the other files alone 528 dwsong.flags |= SONG_ENDREACHED; 529 break; 530 } 531 } 532 } while (!(dwsong.flags & SONG_ENDREACHED)); 533 534 for (n = 0; n < MAX_CHANNELS; n++) { 535 if (!dwsong.multi_write[n].used) { 536 /* this channel was completely empty - don't bother with it */ 537 disko_memclose(ds[n], 0); 538 continue; 539 } 540 541 ds[n]->length = MIN(ds[n]->length, smpsize * bps); 542 smpnum = csf_first_blank_sample(current_song, smpnum); 543 if (smpnum < 0) 544 break; 545 sample = current_song->samples + smpnum; 546 if (close_and_bind(&dwsong, ds[n], sample, bps) == DW_OK) { 547 sprintf(sample->name, "Pattern %03d, channel %02d", pattern, n + 1); 548 } else { 549 /* Balls. Something died. */ 550 err = errno; 551 } 552 } 553 554 for (; n < MAX_CHANNELS; n++) { 555 if (disko_memclose(ds[n], 0) != DW_OK) { 556 err = errno; 557 } 558 } 559 560 _export_teardown(); 561 free(dwsong.multi_write); 562 563 if (err) { 564 errno = err; 565 return DW_ERROR; 566 } else { 567 return DW_OK; 568 } 569 } 570 571 // --------------------------------------------------------------------------- 572 573 static song_t export_dwsong; 574 static int export_bps; 575 static disko_t *export_ds[MAX_CHANNELS + 1]; /* only [0] is used unless multichannel */ 576 static const struct save_format *export_format = NULL; /* NULL == not running */ 577 static struct widget diskodlg_widgets[1]; 578 static size_t est_len; 579 static int prgh; 580 static struct timeval export_start_time; 581 static int canceled = 0; /* this sucks, but so do I */ 582 583 static int disko_finish(void); 584 585 static void diskodlg_draw(void) 586 { 587 int sec, pos; 588 char buf[32]; 589 590 if (!export_ds[0]) { 591 /* what are we doing here?! */ 592 dialog_destroy_all(); 593 log_appendf(4, "disk export dialog was eaten by a grue!"); 594 return; 595 } 596 597 sec = export_ds[0]->length / export_dwsong.mix_frequency; 598 pos = export_ds[0]->length * 64 / est_len; 599 snprintf(buf, 32, "Exporting song...%6d:%02d", sec / 60, sec % 60); 600 buf[31] = '\0'; 601 draw_text(buf, 27, 27, 0, 2); 602 draw_fill_chars(24, 30, 55, 30, 0); 603 draw_vu_meter(24, 30, 32, pos, prgh, prgh); 604 draw_box(23, 29, 56, 31, BOX_THIN | BOX_INNER | BOX_INSET); 605 } 606 607 static void diskodlg_cancel(UNUSED void *ignored) 608 { 609 canceled = 1; 610 export_dwsong.flags |= SONG_ENDREACHED; 611 if (!export_ds[0]) { 612 log_appendf(4, "export was already dead on the inside"); 613 return; 614 } 615 for (int n = 0; export_ds[n]; n++) 616 disko_seterror(export_ds[n], EINTR); 617 618 /* The next disko_sync will notice the (artifical) error status and call disko_finish, 619 which will clean up all the files. 620 'canceled' prevents disko_finish from making a second call to dialog_destroy (since 621 this function is already being called in response to the dialog being canceled) and 622 also affects the message it prints at the end. */ 623 } 624 625 static void disko_dialog_setup(size_t len); 626 627 // this needs to be done to work around stupid inconsistent key-up code 628 static void diskodlg_reset(UNUSED void *ignored) 629 { 630 disko_dialog_setup(est_len); 631 } 632 633 static void disko_dialog_setup(size_t len) 634 { 635 struct dialog *d = dialog_create_custom(22, 25, 36, 8, diskodlg_widgets, 0, 0, diskodlg_draw, NULL); 636 d->action_yes = diskodlg_reset; 637 d->action_no = diskodlg_reset; 638 d->action_cancel = diskodlg_cancel; 639 640 canceled = 0; /* stupid */ 641 642 est_len = len; 643 switch ((rand() >> 8) & 63) { /* :) */ 644 case 0 ... 7: prgh = 6; break; 645 case 8 ... 18: prgh = 3; break; 646 case 19 ... 31: prgh = 5; break; 647 default: prgh = 4; break; 648 } 649 } 650 651 // --------------------------------------------------------------------------- 652 653 static char *get_filename(const char *template, int n) 654 { 655 char *s, *sub, buf[4]; 656 657 s = strdup(template); 658 if (!s) 659 return NULL; 660 sub = strcasestr(s, "%c"); 661 if (!sub) { 662 errno = EINVAL; 663 free(s); 664 return NULL; 665 } 666 num99tostr(n, buf); 667 sub[0] = buf[0]; 668 sub[1] = buf[1]; 669 return s; 670 } 671 672 int disko_export_song(const char *filename, const struct save_format *format) 673 { 674 int err = 0; 675 int numfiles, n; 676 677 if (export_format) { 678 log_appendf(4, "Another export is already active"); 679 errno = EAGAIN; 680 return DW_ERROR; 681 } 682 683 gettimeofday(&export_start_time, NULL); 684 685 numfiles = format->f.export.multi ? MAX_CHANNELS : 1; 686 687 _export_setup(&export_dwsong, &export_bps); 688 if (numfiles > 1) { 689 export_dwsong.multi_write = calloc(numfiles, sizeof(struct multi_write)); 690 if (!export_dwsong.multi_write) 691 err = errno ?: ENOMEM; 692 } 693 694 memset(export_ds, 0, sizeof(export_ds)); 695 for (n = 0; n < numfiles; n++) { 696 if (numfiles > 1) { 697 char *tmp = get_filename(filename, n + 1); 698 if (tmp) { 699 export_ds[n] = disko_open(tmp); 700 free(tmp); 701 } 702 } else { 703 export_ds[n] = disko_open(filename); 704 } 705 if (!(export_ds[n] && format->f.export.head(export_ds[n], export_dwsong.mix_bits_per_sample, 706 export_dwsong.mix_channels, export_dwsong.mix_frequency) == DW_OK)) { 707 err = errno ?: EINVAL; 708 break; 709 } 710 } 711 712 if (err) { 713 _export_teardown(); 714 free(export_dwsong.multi_write); 715 for (n = 0; export_ds[n]; n++) { 716 disko_seterror(export_ds[n], err); /* keep from writing a bunch of useless files */ 717 disko_close(export_ds[n], 0); 718 } 719 errno = err ?: EINVAL; 720 log_perror(filename); 721 return DW_ERROR; 722 } 723 724 if (numfiles > 1) { 725 for (n = 0; n < numfiles; n++) { 726 export_dwsong.multi_write[n].data = export_ds[n]; 727 /* Dumb casts, again */ 728 export_dwsong.multi_write[n].write = (void *) format->f.export.body; 729 export_dwsong.multi_write[n].silence = (void *) format->f.export.silence; 730 } 731 } 732 733 log_appendf(5, " %d Hz, %d bit, %s", 734 export_dwsong.mix_frequency, export_dwsong.mix_bits_per_sample, 735 export_dwsong.mix_channels == 1 ? "mono" : "stereo"); 736 export_format = format; 737 status.flags |= DISKWRITER_ACTIVE; /* tell main to care about us */ 738 739 disko_dialog_setup((csf_get_length(&export_dwsong) * export_dwsong.mix_frequency) ?: 1); 740 741 return DW_OK; 742 } 743 744 745 /* main calls this periodically when the .wav exporter is busy */ 746 int disko_sync(void) 747 { 748 uint8_t buf[DW_BUFFER_SIZE]; 749 size_t frames; 750 int n; 751 752 if (!export_format) { 753 log_appendf(4, "disko_sync: unexplained bacon"); 754 return DW_SYNC_ERROR; /* no writer running (why are we here?) */ 755 } 756 757 frames = csf_read(&export_dwsong, buf, sizeof(buf)); 758 759 if (!export_dwsong.multi_write) 760 export_format->f.export.body(export_ds[0], buf, frames * export_bps); 761 /* always check if something died, multi-write or not */ 762 for (n = 0; export_ds[n]; n++) { 763 if (export_ds[n]->error) { 764 disko_finish(); 765 return DW_SYNC_ERROR; 766 } 767 } 768 769 /* update the progress bar (kind of messy, yes...) */ 770 export_ds[0]->length += frames; 771 status.flags |= NEED_UPDATE; 772 773 if (export_dwsong.flags & SONG_ENDREACHED) { 774 disko_finish(); 775 return DW_SYNC_DONE; 776 } else { 777 return DW_SYNC_MORE; 778 } 779 } 780 781 static int disko_finish(void) 782 { 783 int ret = DW_OK, n, tmp; 784 struct timeval export_end_time; 785 double elapsed; 786 int num_files = 0; 787 size_t samples_0 = 0; 788 789 if (!export_format) { 790 log_appendf(4, "disko_finish: unexplained eggs"); 791 return DW_ERROR; /* no writer running (why are we here?) */ 792 } 793 794 if (!canceled) 795 dialog_destroy(); 796 797 samples_0 = export_ds[0]->length; 798 for (n = 0; export_ds[n]; n++) { 799 if (export_dwsong.multi_write && !export_dwsong.multi_write[n].used) { 800 /* this channel was completely empty - don't bother with it */ 801 disko_seterror(export_ds[n], EINVAL); /* kludge */ 802 disko_close(export_ds[n], 0); 803 } else { 804 /* there was noise on this channel */ 805 num_files++; 806 if (export_format->f.export.tail(export_ds[n]) != DW_OK) 807 disko_seterror(export_ds[n], errno); 808 tmp = disko_close(export_ds[n], 0); 809 if (ret == DW_OK) 810 ret = tmp; 811 } 812 } 813 memset(export_ds, 0, sizeof(export_ds)); 814 815 _export_teardown(); 816 free(export_dwsong.multi_write); 817 export_format = NULL; 818 819 status.flags &= ~DISKWRITER_ACTIVE; /* please unsubscribe me from your mailing list */ 820 821 switch (ret) { 822 case DW_OK: 823 gettimeofday(&export_end_time, NULL); 824 elapsed = (export_end_time.tv_sec - export_start_time.tv_sec) 825 + ((export_end_time.tv_usec - export_start_time.tv_usec) / 1000000.0); 826 char fmt[80] = " %.2f mb (%d:%02d) written in %.2lf sec"; 827 if (elapsed >= 9.5 && elapsed < 10.5) { 828 strcpy(strrchr(fmt, '%'), "ten seconds flat"); 829 } 830 log_appendf(5, fmt, 831 ((double) samples_0 * (disko_output_bits / 8) * export_dwsong.mix_channels * num_files) / 1048576.0, 832 samples_0 / disko_output_rate / 60, (samples_0 / disko_output_rate) % 60, 833 elapsed); 834 break; 835 case DW_ERROR: 836 /* hey, what was the filename? oops */ 837 if (canceled) 838 log_appendf(5, " Canceled"); 839 else 840 log_perror(" Write error"); 841 break; 842 default: 843 log_appendf(5, " Internal error exporting song"); 844 break; 845 } 846 847 return ret; 848 } 849 850 // --------------------------------------------------------------------------- 851 852 struct pat2smp { 853 int pattern, sample, bind; 854 }; 855 856 static void pat2smp_single(void *data) 857 { 858 struct pat2smp *ps = data; 859 860 if (disko_writeout_sample(ps->sample, ps->pattern, ps->bind) == DW_OK) { 861 set_page(PAGE_SAMPLE_LIST); 862 } else { 863 log_perror("Sample write"); 864 status_text_flash("Error writing to sample"); 865 } 866 867 free(ps); 868 } 869 870 static void pat2smp_multi(void *data) 871 { 872 struct pat2smp *ps = data; 873 if (disko_multiwrite_samples(ps->sample, ps->pattern) == DW_OK) { 874 set_page(PAGE_SAMPLE_LIST); 875 } else { 876 log_perror("Sample multi-write"); 877 status_text_flash("Error writing to samples"); 878 } 879 880 free(ps); 881 } 882 883 void song_pattern_to_sample(int pattern, int split, int bind) 884 { 885 struct pat2smp *ps; 886 int n; 887 888 if (split && bind) { 889 log_appendf(4, "song_pattern_to_sample: internal error!"); 890 return; 891 } 892 893 if (pattern < 0 || pattern >= MAX_PATTERNS) { 894 return; 895 } 896 897 /* this is horrid */ 898 for (n = 1; n < MAX_SAMPLES; n++) { 899 song_sample_t *samp = song_get_sample(n); 900 if (!samp) continue; 901 if (((unsigned char) samp->name[23]) != 0xFF) continue; 902 if (((unsigned char) samp->name[24]) != pattern) continue; 903 status_text_flash("Pattern %d already linked to sample %d", pattern, n); 904 return; 905 } 906 907 ps = mem_alloc(sizeof(struct pat2smp)); 908 ps->pattern = pattern; 909 ps->sample = sample_get_current() ?: 1; 910 ps->bind = bind; 911 912 if (split) { 913 /* Nothing to confirm, as this never overwrites samples */ 914 pat2smp_multi(ps); 915 } else { 916 if (current_song->samples[ps->sample].data == NULL) { 917 pat2smp_single(ps); 918 } else { 919 dialog_create(DIALOG_OK_CANCEL, "This will replace the current sample.", 920 pat2smp_single, free, 1, ps); 921 } 922 } 923 } 924 925 // --------------------------------------------------------------------------- 926 927 /* called from audio_playback.c _schism_midi_out_raw() */ 928 int _disko_writemidi(UNUSED const void *data, UNUSED unsigned int len, UNUSED unsigned int delay) 929 { 930 return DW_ERROR; 931 } 932