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