<commit_before>//
//  YASAudioInputTapNodeSampleViewController.mm
//

#import "YASAudioInputTapNodeSampleViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <Accelerate/Accelerate.h>
#import <audio/yas_audio_umbrella.h>
#import <objc_utils/yas_objc_macros.h>
#import "YASViewControllerUtils.h"

using namespace yas;

@interface YASAudioInputTapNodeSampleViewController ()

@property (nonatomic, strong) IBOutlet UIProgressView *progressView;
@property (nonatomic, strong) IBOutlet UILabel *label;
@property (nonatomic, strong) CADisplayLink *displayLink;

@end

namespace yas::sample {
struct input_tap_vc_cpp {
    audio::ios_session_ptr const session = audio::ios_session::shared();
    audio::io_device_ptr const device = audio::ios_device::make_renewable_device(this->session);
    audio::graph_ptr const graph = audio::graph::make_shared();
    audio::graph_tap_ptr const input_tap = audio::graph_tap::make_shared({.is_input = true});

    chaining::value::holder_ptr<float> input_level =
        chaining::value::holder<float>::make_shared(audio::math::decibel_from_linear(0.0f));

    void setup() {
        this->graph->add_io(this->device);
        this->reconnect();

        input_tap->set_render_handler([input_level = input_level](auto args) mutable {
            auto const &buffer = args.buffer;

            auto each = audio::make_each_data<float>(*buffer);
            int const frame_length = buffer->frame_length();
            float level = 0;

            while (yas_each_data_next_ch(each)) {
                auto const *const ptr = yas_each_data_ptr(each);
                level = std::max(fabsf(ptr[cblas_isamax(frame_length, ptr, 1)]), level);
            }

            double const sample_rate = buffer->format().sample_rate();
            float prev_level = input_level->raw() - frame_length / sample_rate * 30.0f;
            level = std::max(prev_level, audio::math::decibel_from_linear(level));
            input_level->set_value(level);
        });

        this->session->device_chain()
            .guard([](auto const &method) { return method == audio::ios_device_session::device_method::route_change; })
            .perform([this](auto const &) { this->reconnect(); })
            .end()
            ->add_to(this->_pool);
    }

    void dispose() {
        this->graph->stop();
        this->session->deactivate();
    }

    void reconnect() {
        auto const &io = this->graph->io();
        if (!io) {
            return;
        }

        graph->disconnect(io.value()->node());

        double const sample_rate = this->device->input_format()->sample_rate();
        uint32_t const ch_count = this->device->input_channel_count();
        audio::format format{{.sample_rate = sample_rate, .channel_count = ch_count}};
        graph->connect(io.value()->node(), input_tap->node(), format);<commit_msg>fix sample<commit_after>//
//  YASAudioInputTapNodeSampleViewController.mm
//

#import "YASAudioInputTapNodeSampleViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <Accelerate/Accelerate.h>
#import <audio/yas_audio_umbrella.h>
#import <objc_utils/yas_objc_macros.h>
#import "YASViewControllerUtils.h"

using namespace yas;

@interface YASAudioInputTapNodeSampleViewController ()

@property (nonatomic, strong) IBOutlet UIProgressView *progressView;
@property (nonatomic, strong) IBOutlet UILabel *label;
@property (nonatomic, strong) CADisplayLink *displayLink;

@end

namespace yas::sample {
struct input_tap_vc_cpp {
    audio::ios_session_ptr const session = audio::ios_session::shared();
    audio::io_device_ptr const device = audio::ios_device::make_renewable_device(this->session);
    audio::graph_ptr const graph = audio::graph::make_shared();
    audio::graph_tap_ptr const input_tap = audio::graph_tap::make_shared({.is_input = true});

    chaining::value::holder_ptr<float> input_level =
        chaining::value::holder<float>::make_shared(audio::math::decibel_from_linear(0.0f));

    void setup() {
        this->graph->add_io(this->device);
        this->reconnect();

        input_tap->set_render_handler([input_level = input_level](auto args) mutable {
            auto const &buffer = args.buffer;

            auto each = audio::make_each_data<float>(*buffer);
            int const frame_length = buffer->frame_length();
            float level = 0;

            while (yas_each_data_next_ch(each)) {
                auto const *const ptr = yas_each_data_ptr(each);
                level = std::max(fabsf(ptr[cblas_isamax(frame_length, ptr, 1)]), level);
            }

            double const sample_rate = buffer->format().sample_rate();
            float prev_level = input_level->raw() - frame_length / sample_rate * 30.0f;
            level = std::max(prev_level, audio::math::decibel_from_linear(level));
            input_level->set_value(level);
        });

        this->session->device_chain()
            .guard([](auto const &method) { return method == audio::ios_device_session::device_method::route_change; })
            .perform([this](auto const &) { this->reconnect(); })
            .end()
            ->add_to(this->_pool);
    }

    void dispose() {
        this->graph->stop();
        this->session->deactivate();
    }

    void reconnect() {
        auto const &io = this->graph->io();
        if (!io) {
            return;
        }

        graph->disconnect(io.value()->node());

        auto const input_format = this->device->input_format();
        if (!input_format || input_format->is_broken()) {
            return;
        }

        audio::format format{
            {.sample_rate = input_format->sample_rate(), .channel_count = input_format->channel_count()}};
        graph->connect(io.value()->node(), input_tap->node(), format);
{'fraction_non_alphanumeric': 0.13941390671059475, 'fraction_numerical': 0.002774406103693428, 'mean_word_length': 3.2725925925925927, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3875386', 'n_tokens_mistral': 1800, 'n_tokens_neox': 1721, 'n_words': 303}