Mercurial > hg > sonic-visualiser
comparison audioio/AudioCallbackPlaySource.cpp @ 26:d88d117e0c34
* Add mono timestretch toggle button; some more work on getting blocksize etc
parameters through to plugins
author | Chris Cannam |
---|---|
date | Mon, 18 Sep 2006 16:43:17 +0000 |
parents | e74f508db18c |
children | 37af203dbd15 |
comparison
equal
deleted
inserted
replaced
25:e74f508db18c | 26:d88d117e0c34 |
---|---|
586 { | 586 { |
587 return m_sourceSampleRate; | 587 return m_sourceSampleRate; |
588 } | 588 } |
589 | 589 |
590 void | 590 void |
591 AudioCallbackPlaySource::setSlowdownFactor(float factor, bool sharpen) | 591 AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) |
592 { | 592 { |
593 // Avoid locks -- create, assign, mark old one for scavenging | 593 // Avoid locks -- create, assign, mark old one for scavenging |
594 // later (as a call to getSourceSamples may still be using it) | 594 // later (as a call to getSourceSamples may still be using it) |
595 | 595 |
596 PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher; | 596 PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher; |
597 | 597 |
598 size_t channels = getTargetChannelCount(); | |
599 if (mono) channels = 1; | |
600 | |
598 if (existingStretcher && | 601 if (existingStretcher && |
599 existingStretcher->getRatio() == factor && | 602 existingStretcher->getRatio() == factor && |
600 existingStretcher->getSharpening() == sharpen) { | 603 existingStretcher->getSharpening() == sharpen && |
604 existingStretcher->getChannelCount() == channels) { | |
601 return; | 605 return; |
602 } | 606 } |
603 | 607 |
604 if (factor != 1) { | 608 if (factor != 1) { |
605 | 609 |
606 if (existingStretcher && | 610 if (existingStretcher && |
607 existingStretcher->getSharpening() == sharpen) { | 611 existingStretcher->getSharpening() == sharpen && |
612 existingStretcher->getChannelCount() == channels) { | |
608 existingStretcher->setRatio(factor); | 613 existingStretcher->setRatio(factor); |
609 return; | 614 return; |
610 } | 615 } |
611 | 616 |
612 PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher | 617 PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher |
613 (getTargetSampleRate(), | 618 (getTargetSampleRate(), |
614 getTargetChannelCount(), | 619 channels, |
615 factor, | 620 factor, |
616 sharpen, | 621 sharpen, |
617 lrintf(getTargetBlockSize() / factor)); | 622 lrintf(getTargetBlockSize() / factor)); |
623 | |
618 m_timeStretcher = newStretcher; | 624 m_timeStretcher = newStretcher; |
625 | |
619 } else { | 626 } else { |
620 m_timeStretcher = 0; | 627 m_timeStretcher = 0; |
621 } | 628 } |
622 | 629 |
623 if (existingStretcher) { | 630 if (existingStretcher) { |
624 m_timeStretcherScavenger.claim(existingStretcher); | 631 m_timeStretcherScavenger.claim(existingStretcher); |
625 } | 632 } |
626 } | 633 } |
627 | 634 |
628 size_t | 635 size_t |
629 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) | 636 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) |
630 { | 637 { |
631 if (!m_playing) { | 638 if (!m_playing) { |
632 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { | 639 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { |
674 | 681 |
675 float ratio = ts->getRatio(); | 682 float ratio = ts->getRatio(); |
676 | 683 |
677 // std::cout << "ratio = " << ratio << std::endl; | 684 // std::cout << "ratio = " << ratio << std::endl; |
678 | 685 |
686 size_t channels = getTargetChannelCount(); | |
687 bool mix = (channels > 1 && ts->getChannelCount() == 1); | |
688 | |
679 size_t available; | 689 size_t available; |
680 | 690 |
681 while ((available = ts->getAvailableOutputSamples()) < count) { | 691 while ((available = ts->getAvailableOutputSamples()) < count) { |
682 | 692 |
683 size_t reqd = lrintf((count - available) / ratio); | 693 size_t reqd = lrintf((count - available) / ratio); |
684 reqd = std::max(reqd, ts->getRequiredInputSamples()); | 694 reqd = std::max(reqd, ts->getRequiredInputSamples()); |
685 if (reqd == 0) reqd = 1; | 695 if (reqd == 0) reqd = 1; |
686 | 696 |
687 size_t channels = getTargetChannelCount(); | |
688 | |
689 float *ib[channels]; | 697 float *ib[channels]; |
690 | 698 |
691 size_t got = reqd; | 699 size_t got = reqd; |
692 | 700 |
693 for (size_t c = 0; c < channels; ++c) { | 701 if (mix) { |
694 ib[c] = new float[reqd]; //!!! fix -- this is a rt function | 702 for (size_t c = 0; c < channels; ++c) { |
695 RingBuffer<float> *rb = getReadRingBuffer(c); | 703 if (c == 0) ib[c] = new float[reqd]; //!!! fix -- this is a rt function |
696 if (rb) { | 704 else ib[c] = 0; |
697 size_t gotHere = rb->read(ib[c], got); | 705 RingBuffer<float> *rb = getReadRingBuffer(c); |
698 if (gotHere < got) got = gotHere; | 706 if (rb) { |
707 size_t gotHere; | |
708 if (c > 0) gotHere = rb->readAdding(ib[0], got); | |
709 else gotHere = rb->read(ib[0], got); | |
710 if (gotHere < got) got = gotHere; | |
711 } | |
712 } | |
713 } else { | |
714 for (size_t c = 0; c < channels; ++c) { | |
715 ib[c] = new float[reqd]; //!!! fix -- this is a rt function | |
716 RingBuffer<float> *rb = getReadRingBuffer(c); | |
717 if (rb) { | |
718 size_t gotHere = rb->read(ib[c], got); | |
719 if (gotHere < got) got = gotHere; | |
720 } | |
699 } | 721 } |
700 } | 722 } |
701 | 723 |
702 if (got < reqd) { | 724 if (got < reqd) { |
703 std::cerr << "WARNING: Read underrun in playback (" | 725 std::cerr << "WARNING: Read underrun in playback (" |
717 break; | 739 break; |
718 } | 740 } |
719 } | 741 } |
720 | 742 |
721 ts->getOutput(buffer, count); | 743 ts->getOutput(buffer, count); |
744 | |
745 if (mix) { | |
746 for (size_t c = 1; c < channels; ++c) { | |
747 for (size_t i = 0; i < count; ++i) { | |
748 buffer[c][i] = buffer[0][i] / channels; | |
749 } | |
750 } | |
751 for (size_t i = 0; i < count; ++i) { | |
752 buffer[0][i] /= channels; | |
753 } | |
754 } | |
722 | 755 |
723 m_condition.wakeAll(); | 756 m_condition.wakeAll(); |
724 | 757 |
725 return count; | 758 return count; |
726 } | 759 } |