Beispiel #1
0
            public s16 m_user_gain;                                                              // user-controlled gain to apply to this input


            // construction/destruction
            //-------------------------------------------------
            //  stream_input - constructor
            //-------------------------------------------------
            public stream_input()
            {
                m_source = null;
                m_latency_attoseconds = 0;
                m_gain      = 0x100;
                m_user_gain = 0x100f;
            }
Beispiel #2
0
        //-------------------------------------------------
        //  generate_samples - generate the requested
        //  number of samples for a stream, making sure
        //  all inputs have the appropriate number of
        //  samples generated
        //-------------------------------------------------
        void generate_samples(int samples)
        {
            ListPointer <stream_sample_t> [] inputs  = null; //stream_sample_t **inputs = nullptr;
            ListPointer <stream_sample_t> [] outputs = null; //stream_sample_t **outputs = nullptr;

            sound_global.VPRINTF("generate_samples({0}, {1})\n", this, samples);
            assert(samples > 0);

            // ensure all inputs are up to date and generate resampled data
            for (int inputnum = 0; inputnum < m_input.size(); inputnum++)
            {
                // update the stream to the current time
                stream_input input = m_input[inputnum];
                if (input.m_source != null)
                {
                    input.m_source.m_stream.update();
                }

                // generate the resampled data
                m_input_array[inputnum] = generate_resampled_data(input, (UInt32)samples);
            }

            if (!m_input.empty())
            {
                inputs = m_input_array;
            }

            // loop over all outputs and compute the output pointer
            for (int outputnum = 0; outputnum < m_output.size(); outputnum++)
            {
                stream_output output = m_output[outputnum];
                m_output_array[outputnum] = new ListPointer <stream_sample_t>(output.m_buffer, m_output_sampindex - m_output_base_sampindex);  // m_output_array[outputnum] = &output.m_buffer[m_output_sampindex - m_output_base_sampindex];
            }

            if (!m_output.empty())
            {
                outputs = m_output_array;
            }

            // run the callback
            sound_global.VPRINTF("  callback({0}, {1})\n", this, samples);
            m_callback(this, inputs, outputs, samples);
            sound_global.VPRINTF("  callback done\n");
        }
Beispiel #3
0
        //void set_user_gain(int inputnum, float gain);
        //void set_input_gain(int inputnum, float gain);
        //void set_output_gain(int outputnum, float gain);


        // helpers called by our friends only

        //-------------------------------------------------
        //  update_with_accounting - do a regular update,
        //  but also do periodic accounting
        //-------------------------------------------------
        public void update_with_accounting(bool second_tick)
        {
            // do the normal update
            update();

            // if we've ticked over another second, adjust all the counters that are relative to
            // the current second
            int output_bufindex = m_output_sampindex - m_output_base_sampindex;

            if (second_tick)
            {
                m_output_sampindex      -= (int)m_sample_rate;
                m_output_base_sampindex -= (int)m_sample_rate;
            }

            // note our current output sample
            m_output_update_sampindex = m_output_sampindex;

            // if we don't have enough output buffer space to hold two updates' worth of samples,
            // we need to shuffle things down
            if (m_output_bufalloc - output_bufindex < 2 * m_max_samples_per_update)
            {
                int samples_to_lose = output_bufindex - m_max_samples_per_update;
                if (samples_to_lose > 0)
                {
                    // if we have samples to move, do so for each output
                    if (output_bufindex > 0)
                    {
                        for (int outputnum = 0; outputnum < m_output.size(); outputnum++)
                        {
                            stream_output output = m_output[outputnum];
                            //memmove(&output.m_buffer[0], &output.m_buffer[samples_to_lose], sizeof(output.m_buffer[0]) * (output_bufindex - samples_to_lose));
                            output.m_buffer.copy(0, samples_to_lose, output.m_buffer, output_bufindex - samples_to_lose);  // TODO: not sure if there's supposed to be overlap here
                        }
                    }

                    // update the base position
                    m_output_base_sampindex += samples_to_lose;
                }
            }
        }
Beispiel #4
0
        //-------------------------------------------------
        //  generate_resampled_data - generate the
        //  resample buffer for a given input
        //-------------------------------------------------
        ListPointer <stream_sample_t> generate_resampled_data(stream_input input, UInt32 numsamples)
        {
            // if we don't have an output to pull data from, generate silence
            ListPointer <stream_sample_t> dest = new ListPointer <stream_sample_t>(input.m_resample);  // stream_sample_t *dest = input.m_resample;

            if (input.m_source == null || input.m_source.m_stream.m_attoseconds_per_sample == 0)
            {
                memset(dest, 0, numsamples);  //memset(dest, 0, numsamples * sizeof(*dest));
                return(new ListPointer <stream_sample_t>(input.m_resample));
            }

            // grab data from the output
            stream_output output       = input.m_source;  // stream_output &output = *input.m_source;
            sound_stream  input_stream = output.m_stream; // sound_stream &input_stream = *output.m_stream;
            s64           gain         = (input.m_gain * input.m_user_gain * output.m_gain) >> 16;

            // determine the time at which the current sample begins, accounting for the
            // latency we calculated between the input and output streams
            attoseconds_t basetime = m_output_sampindex * m_attoseconds_per_sample - input.m_latency_attoseconds;

            // now convert that time into a sample in the input stream
            s32 basesample;

            if (basetime >= 0)
            {
                basesample = (int)(basetime / input_stream.m_attoseconds_per_sample);
            }
            else
            {
                basesample = (int)(-(-basetime / input_stream.m_attoseconds_per_sample) - 1);
            }

            // compute a source pointer to the first sample
            assert(basesample >= input_stream.m_output_base_sampindex);
            ListPointer <stream_sample_t> source = new ListPointer <stream_sample_t>(output.m_buffer, basesample - input_stream.m_output_base_sampindex);  // stream_sample_t *source = &output.m_buffer[basesample - input_stream.m_output_base_sampindex];

            // determine the current fraction of a sample, expressed as a fraction of FRAC_ONE
            // (Note: this formula is valid as long as input_stream.m_attoseconds_per_sample signficantly exceeds FRAC_ONE > attoseconds = 4.2E-12 s)
            u32 basefrac = (u32)((basetime - basesample * input_stream.m_attoseconds_per_sample) / ((input_stream.m_attoseconds_per_sample + FRAC_ONE - 1) >> (int)FRAC_BITS));

            assert(basefrac < FRAC_ONE);

            // compute the stepping fraction
            u32 step = (u32)(((u64)(input_stream.m_sample_rate) << (int)FRAC_BITS) / m_sample_rate);

            // if we have equal sample rates, we just need to copy
            if (step == FRAC_ONE)
            {
                while (numsamples-- != 0)
                {
                    // compute the sample
                    s64 sample = source[0];                // *source++;
                    source++;
                    dest[0] = (int)((sample * gain) >> 8); // *dest++ = (sample * gain) >> 8;
                    dest++;
                }
            }

            // input is undersampled: point sample except where our sample period covers a boundary
            else if (step < FRAC_ONE)
            {
                while (numsamples != 0)
                {
                    // fill in with point samples until we hit a boundary
                    int nextfrac;
                    while ((nextfrac = (int)(basefrac + step)) < FRAC_ONE && numsamples-- != 0)
                    {
                        dest[0] = (int)((source[0] * gain) >> 8);  // *dest++ = (source[0] * gain) >> 8;
                        dest++;
                        basefrac = (UInt32)nextfrac;
                    }

                    // if we're done, we're done
                    if ((s32)(numsamples--) < 0)
                    {
                        break;
                    }

                    // compute starting and ending fractional positions
                    int startfrac = (int)(basefrac >> (int)(FRAC_BITS - 12));
                    int endfrac   = nextfrac >> (int)(FRAC_BITS - 12);

                    // blend between the two samples accordingly
                    s64 sample = ((s64)source[0] * (0x1000 - startfrac) + (s64)source[1] * (endfrac - 0x1000)) / (endfrac - startfrac);
                    dest[0] = (int)((sample * gain) >> 8);  // *dest++ = (sample * gain) >> 8;
                    dest++;

                    // advance
                    basefrac = (UInt32)(nextfrac & FRAC_MASK);
                    source++;
                }
            }

            // input is oversampled: sum the energy
            else
            {
                // use 8 bits to allow some extra headroom
                int smallstep = (int)(step >> (int)(FRAC_BITS - 8));
                while (numsamples-- != 0)
                {
                    s64 remainder = smallstep;
                    int tpos      = 0;

                    // compute the sample
                    s64 scale  = (FRAC_ONE - basefrac) >> (int)(FRAC_BITS - 8);
                    s64 sample = (s64)source[tpos++] * scale;
                    remainder -= scale;
                    while (remainder > 0x100)
                    {
                        sample    += (Int64)source[tpos++] * (Int64)0x100;
                        remainder -= 0x100;
                    }

                    sample += (Int64)source[tpos] * remainder;
                    sample /= smallstep;

                    dest[0] = (int)((sample * gain) >> 8);  // *dest++ = (sample * gain) >> 8;
                    dest++;

                    // advance
                    basefrac += step;
                    source   += basefrac >> (int)FRAC_BITS;
                    basefrac &= FRAC_MASK;
                }
            }

            return(new ListPointer <stream_sample_t>(input.m_resample));
        }