1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "SimpleResampler.hxx"
19
20// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
21SimpleResampler::SimpleResampler(
22 Resampler::Format formatFrom,
23 Resampler::Format formatTo,
24 Resampler::NextFragmentCallback nextFragmentCallback)
25 : Resampler(formatFrom, formatTo, nextFragmentCallback),
26 myCurrentFragment(nullptr),
27 myTimeIndex(0),
28 myFragmentIndex(0),
29 myIsUnderrun(true)
30{
31}
32
33// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34void SimpleResampler::fillFragment(float* fragment, uInt32 length)
35{
36 if (myIsUnderrun) {
37 Int16* nextFragment = myNextFragmentCallback();
38
39 if (nextFragment) {
40 myCurrentFragment = nextFragment;
41 myFragmentIndex = 0;
42 myIsUnderrun = false;
43 }
44 }
45
46 if (!myCurrentFragment) {
47 std::fill_n(fragment, length, 0.f);
48 return;
49 }
50
51 const uInt32 outputSamples = myFormatTo.stereo ? (length >> 1) : length;
52
53 // For the following math, remember that myTimeIndex = time * myFormatFrom.sampleRate * myFormatTo.sampleRate
54 for (uInt32 i = 0; i < outputSamples; ++i) {
55 if (myFormatFrom.stereo) {
56 float sampleL = static_cast<float>(myCurrentFragment[2*myFragmentIndex]) / static_cast<float>(0x7fff);
57 float sampleR = static_cast<float>(myCurrentFragment[2*myFragmentIndex + 1]) / static_cast<float>(0x7fff);
58
59 if (myFormatTo.stereo) {
60 fragment[2*i] = sampleL;
61 fragment[2*i + 1] = sampleR;
62 }
63 else
64 fragment[i] = (sampleL + sampleR) / 2.f;
65 } else {
66 float sample = static_cast<float>(myCurrentFragment[myFragmentIndex] / static_cast<float>(0x7fff));
67
68 if (myFormatTo.stereo)
69 fragment[2*i] = fragment[2*i + 1] = sample;
70 else
71 fragment[i] = sample;
72 }
73
74 // time += 1 / myFormatTo.sampleRate
75 myTimeIndex += myFormatFrom.sampleRate;
76
77 // time >= 1 / myFormatFrom.sampleRate
78 if (myTimeIndex >= myFormatTo.sampleRate) {
79 // myFragmentIndex += time * myFormatFrom.sampleRate
80 myFragmentIndex += myTimeIndex / myFormatTo.sampleRate;
81 myTimeIndex %= myFormatTo.sampleRate;
82 }
83
84 if (myFragmentIndex >= myFormatFrom.fragmentSize) {
85 myFragmentIndex %= myFormatFrom.fragmentSize;
86
87 Int16* nextFragment = myNextFragmentCallback();
88 if (nextFragment)
89 myCurrentFragment = nextFragment;
90 else {
91 myUnderrunLogger.log();
92 myIsUnderrun = true;
93 }
94 }
95 }
96}
97