Mercurial > octave-nkf
comparison libinterp/dldfcn/audiodevinfo.cc @ 19589:9bd2f0a07c95
improve performance of audio callback functions
* audiodevinfo.cc (octave_play_callback, portaudio_play_callback):
Avoid unnecessary copying of data.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 09 Jan 2015 13:19:50 -0500 |
parents | 8dce81f7448d |
children | d7057df2968e |
comparison
equal
deleted
inserted
replaced
19588:398e42431dcc | 19589:9bd2f0a07c95 |
---|---|
546 { | 546 { |
547 error ("audio player callback function failed"); | 547 error ("audio player callback function failed"); |
548 return paAbort; | 548 return paAbort; |
549 } | 549 } |
550 | 550 |
551 Matrix sound = retval(0).matrix_value (); | 551 const Matrix sound = retval(0).matrix_value (); |
552 int return_status = retval(1).int_value (); | 552 int return_status = retval(1).int_value (); |
553 | 553 |
554 if (error_state || frames != sound.rows () | 554 if (error_state || frames != sound.rows () |
555 || sound.columns () < 1 || sound.columns () > 2) | 555 || sound.columns () < 1 || sound.columns () > 2) |
556 { | 556 { |
557 error ("audio player callback function failed"); | 557 error ("audio player callback function failed"); |
558 return paAbort; | 558 return paAbort; |
559 } | 559 } |
560 | 560 |
561 double scale_factor = 1.0; | 561 // Don't multiply the audio data by scale_factor here. Although it |
562 | 562 // does move the operation outside of the loops below, it also causes |
563 switch (player->get_nbits ()) | 563 // a second copy of the data array to be made. |
564 { | 564 |
565 case 8: | 565 const ColumnVector sound_l = sound.column (0); |
566 scale_factor = pow (2.0, 7) - 1.0; | 566 const ColumnVector sound_r = (sound.columns () == 1) |
567 break; | 567 ? sound_l : sound.column (1); |
568 | |
569 case 16: | |
570 scale_factor = pow (2.0, 15) - 1.0; | |
571 break; | |
572 | |
573 case 24: | |
574 scale_factor = pow (2.0, 23) - 1.0; | |
575 break; | |
576 | |
577 default: | |
578 error ("invalid player bit depth in callback function"); | |
579 break; | |
580 } | |
581 | |
582 sound = sound * scale_factor; | |
583 | |
584 const RowVector sound_l = (sound.column (0)).transpose (); | |
585 const RowVector sound_r = (sound.columns () == 1) | |
586 ? sound_l : (sound.column (1)).transpose (); | |
587 | 568 |
588 const double *p_l = sound_l.data (); | 569 const double *p_l = sound_l.data (); |
589 const double *p_r = sound_r.data (); | 570 const double *p_r = sound_r.data (); |
590 | 571 |
591 switch (player->get_nbits ()) | 572 switch (player->get_nbits ()) |
592 { | 573 { |
593 case 8: | 574 case 8: |
594 { | 575 { |
576 static double scale_factor = pow (2.0, 7) - 1.0; | |
577 | |
595 int8_t *buffer = static_cast<int8_t *> (output); | 578 int8_t *buffer = static_cast<int8_t *> (output); |
596 | 579 |
597 for (unsigned long i = 0; i < frames; i++) | 580 for (unsigned long i = 0; i < frames; i++) |
598 { | 581 { |
599 buffer[2*i] = p_l[i]; | 582 buffer[2*i] = p_l[i] * scale_factor; |
600 buffer[2*i+1] = p_r[i]; | 583 buffer[2*i+1] = p_r[i] * scale_factor; |
601 } | 584 } |
602 } | 585 } |
603 break; | 586 break; |
604 | 587 |
605 case 16: | 588 case 16: |
606 { | 589 { |
590 static double scale_factor = pow (2.0, 15) - 1.0; | |
591 | |
607 int16_t *buffer = static_cast<int16_t *> (output); | 592 int16_t *buffer = static_cast<int16_t *> (output); |
608 | 593 |
609 for (unsigned long i = 0; i < frames; i++) | 594 for (unsigned long i = 0; i < frames; i++) |
610 { | 595 { |
611 buffer[2*i] = p_l[i]; | 596 buffer[2*i] = p_l[i] * scale_factor; |
612 buffer[2*i+1] = p_r[i]; | 597 buffer[2*i+1] = p_r[i] * scale_factor; |
613 } | 598 } |
614 } | 599 } |
615 break; | 600 break; |
616 | 601 |
617 case 24: | 602 case 24: |
618 { | 603 { |
619 int big_endian = is_big_endian (); | 604 static double scale_factor = pow (2.0, 23) - 1.0; |
605 | |
606 static int big_endian = is_big_endian (); | |
620 | 607 |
621 uint8_t *buffer = static_cast<uint8_t *> (output); | 608 uint8_t *buffer = static_cast<uint8_t *> (output); |
622 | 609 |
623 for (unsigned long i = 0; i < frames; i++) | 610 for (unsigned long i = 0; i < frames; i++) |
624 { | 611 { |
632 uint8_t *_sample_l = reinterpret_cast<uint8_t *> (&sample_l); | 619 uint8_t *_sample_l = reinterpret_cast<uint8_t *> (&sample_l); |
633 uint8_t *_sample_r = reinterpret_cast<uint8_t *> (&sample_r); | 620 uint8_t *_sample_r = reinterpret_cast<uint8_t *> (&sample_r); |
634 | 621 |
635 unsigned long offset = i * 6; | 622 unsigned long offset = i * 6; |
636 | 623 |
637 buffer[offset+0] = _sample_l[0+big_endian]; | 624 buffer[offset+0] = _sample_l[0+big_endian] * scale_factor; |
638 buffer[offset+1] = _sample_l[1+big_endian]; | 625 buffer[offset+1] = _sample_l[1+big_endian] * scale_factor; |
639 buffer[offset+2] = _sample_l[2+big_endian]; | 626 buffer[offset+2] = _sample_l[2+big_endian] * scale_factor; |
640 | 627 |
641 buffer[offset+3] = _sample_r[0+big_endian]; | 628 buffer[offset+3] = _sample_r[0+big_endian] * scale_factor; |
642 buffer[offset+4] = _sample_r[1+big_endian]; | 629 buffer[offset+4] = _sample_r[1+big_endian] * scale_factor; |
643 buffer[offset+5] = _sample_r[2+big_endian]; | 630 buffer[offset+5] = _sample_r[2+big_endian] * scale_factor; |
644 } | 631 } |
645 } | 632 } |
646 break; | 633 break; |
647 | 634 |
648 default: | 635 default: |
664 { | 651 { |
665 error ("audio player callback function called without player"); | 652 error ("audio player callback function called without player"); |
666 return paAbort; | 653 return paAbort; |
667 } | 654 } |
668 | 655 |
669 double scale_factor = 1.0; | 656 // Don't multiply the audio data by scale_factor here. Although it |
670 | 657 // would move the operation outside of the loops below, it also causes |
671 switch (player->get_nbits ()) | 658 // a second copy of the *entire* data array to be made when only a |
672 { | 659 // small portion (BUFFER_SIZE elements) is usually needed for this |
673 case 8: | 660 // callback. |
674 scale_factor = pow (2.0, 7) - 1.0; | 661 |
675 break; | 662 const RowVector sound_l = player->get_left (); |
676 | 663 const RowVector sound_r = player->get_right (); |
677 case 16: | |
678 scale_factor = pow (2.0, 15) - 1.0; | |
679 break; | |
680 | |
681 case 24: | |
682 scale_factor = pow (2.0, 23) - 1.0; | |
683 break; | |
684 | |
685 default: | |
686 error ("invalid player bit depth in callback function"); | |
687 break; | |
688 } | |
689 | |
690 const RowVector sound_l = player->get_left () * scale_factor; | |
691 const RowVector sound_r = player->get_right () * scale_factor; | |
692 | 664 |
693 const double *pl = sound_l.data (); | 665 const double *pl = sound_l.data (); |
694 const double *pr = sound_l.data (); | 666 const double *pr = sound_l.data (); |
695 | 667 |
696 if (player->get_type () == DOUBLE) | 668 if (player->get_type () == DOUBLE) |
697 { | 669 { |
698 switch (player->get_nbits ()) | 670 switch (player->get_nbits ()) |
699 { | 671 { |
700 case 8: | 672 case 8: |
701 { | 673 { |
674 static double scale_factor = pow (2.0, 7) - 1.0; | |
675 | |
702 int8_t *buffer = static_cast<int8_t *> (output); | 676 int8_t *buffer = static_cast<int8_t *> (output); |
703 | 677 |
704 for (unsigned long j = 0; j < frames; j++) | 678 for (unsigned long j = 0; j < frames; j++) |
705 { | 679 { |
706 unsigned int sample_number = player->get_sample_number (); | 680 unsigned int sample_number = player->get_sample_number (); |
708 if (sample_number >= player->get_end_sample ()) | 682 if (sample_number >= player->get_end_sample ()) |
709 return paComplete; | 683 return paComplete; |
710 | 684 |
711 unsigned long offset = j * 2; | 685 unsigned long offset = j * 2; |
712 | 686 |
713 buffer[offset+0] = pl[sample_number]; | 687 buffer[offset+0] = pl[sample_number] * scale_factor; |
714 buffer[offset+1] = pr[sample_number]; | 688 buffer[offset+1] = pr[sample_number] * scale_factor; |
715 | 689 |
716 player->set_sample_number (sample_number + 1); | 690 player->set_sample_number (sample_number + 1); |
717 } | 691 } |
718 } | 692 } |
719 break; | 693 break; |
720 | 694 |
721 case 16: | 695 case 16: |
722 { | 696 { |
697 static double scale_factor = pow (2.0, 15) - 1.0; | |
698 | |
723 int16_t *buffer = static_cast<int16_t *> (output); | 699 int16_t *buffer = static_cast<int16_t *> (output); |
724 | 700 |
725 for (unsigned long j = 0; j < frames; j++) | 701 for (unsigned long j = 0; j < frames; j++) |
726 { | 702 { |
727 unsigned int sample_number = player->get_sample_number (); | 703 unsigned int sample_number = player->get_sample_number (); |
729 if (sample_number >= player->get_end_sample ()) | 705 if (sample_number >= player->get_end_sample ()) |
730 return paComplete; | 706 return paComplete; |
731 | 707 |
732 unsigned long offset = j * 2; | 708 unsigned long offset = j * 2; |
733 | 709 |
734 buffer[offset+0] = pl[sample_number]; | 710 buffer[offset+0] = pl[sample_number] * scale_factor; |
735 buffer[offset+1] = pr[sample_number]; | 711 buffer[offset+1] = pr[sample_number] * scale_factor; |
736 | 712 |
737 player->set_sample_number (sample_number + 1); | 713 player->set_sample_number (sample_number + 1); |
738 } | 714 } |
739 } | 715 } |
740 break; | 716 break; |
741 | 717 |
742 case 24: | 718 case 24: |
743 { | 719 { |
720 static double scale_factor = pow (2.0, 23) - 1.0; | |
721 | |
722 static int big_endian = is_big_endian (); | |
723 | |
744 uint8_t *buffer = static_cast<uint8_t *> (output); | 724 uint8_t *buffer = static_cast<uint8_t *> (output); |
745 | 725 |
746 for (unsigned long j = 0; j < frames; j++) | 726 for (unsigned long j = 0; j < frames; j++) |
747 { | 727 { |
748 unsigned int sample_number = player->get_sample_number (); | 728 unsigned int sample_number = player->get_sample_number (); |
749 | 729 |
750 if (sample_number >= player->get_end_sample ()) | 730 if (sample_number >= player->get_end_sample ()) |
751 return paComplete; | 731 return paComplete; |
752 | 732 |
753 int32_t sample_l = pl[sample_number]; | 733 int32_t sample_l = pl[sample_number] * scale_factor; |
754 int32_t sample_r = pr[sample_number]; | 734 int32_t sample_r = pr[sample_number] * scale_factor; |
755 | 735 |
756 sample_l &= 0x00ffffff; | 736 sample_l &= 0x00ffffff; |
757 sample_r &= 0x00ffffff; | 737 sample_r &= 0x00ffffff; |
758 | |
759 int big_endian = is_big_endian (); | |
760 | 738 |
761 // FIXME: Would a mask work better? | 739 // FIXME: Would a mask work better? |
762 uint8_t *_sample_l = reinterpret_cast<uint8_t *> (&sample_l); | 740 uint8_t *_sample_l = reinterpret_cast<uint8_t *> (&sample_l); |
763 uint8_t *_sample_r = reinterpret_cast<uint8_t *> (&sample_r); | 741 uint8_t *_sample_r = reinterpret_cast<uint8_t *> (&sample_r); |
764 | 742 |