AudioQueue.cxx 4.22 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
//============================================================================
//
//   SSSS    tt          lll  lll
//  SS  SS   tt           ll   ll
//  SS     tttttt  eeee   ll   ll   aaaa
//   SSSS    tt   ee  ee  ll   ll      aa
//      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
//  SS  SS   tt   ee      ll   ll  aa  aa
//   SSSS     ttt  eeeee llll llll  aaaaa
//
11
// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12
13
14
15
16
17
18
19
20
21
22
23
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================

#include "AudioQueue.hxx"

using std::mutex;
using std::lock_guard;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24
AudioQueue::AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo, StaggeredLogger::Logger logger)
25
26
27
28
29
  : myFragmentSize(fragmentSize),
    myIsStereo(isStereo),
    myFragmentQueue(capacity),
    myAllFragments(capacity + 2),
    mySize(0),
30
    myNextFragment(0),
31
32
    myIgnoreOverflows(true),
    myOverflowLogger("audio buffer overflow", logger)
33
34
35
{
  const uInt8 sampleSize = myIsStereo ? 2 : 1;

36
  myFragmentBuffer = make_unique<Int16[]>(myFragmentSize * sampleSize * (capacity + 2));
37

38
  for (uInt32 i = 0; i < capacity; ++i)
39
    myFragmentQueue[i] = myAllFragments[i] = myFragmentBuffer.get() + i * sampleSize * myFragmentSize;
40
41

  myAllFragments[capacity] = myFirstFragmentForEnqueue =
42
    myFragmentBuffer.get() + capacity * sampleSize * myFragmentSize;
43
44

  myAllFragments[capacity + 1] = myFirstFragmentForDequeue =
45
    myFragmentBuffer.get() + (capacity + 1) * sampleSize * myFragmentSize;
46
47
48
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49
uInt32 AudioQueue::capacity() const
50
{
51
  return uInt32(myFragmentQueue.size());
52
53
54
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
55
uInt32 AudioQueue::size()
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{
  lock_guard<mutex> guard(myMutex);

  return mySize;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AudioQueue::isStereo() const
{
  return myIsStereo;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 AudioQueue::fragmentSize() const
{
  return myFragmentSize;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int16* AudioQueue::enqueue(Int16* fragment)
{
  lock_guard<mutex> guard(myMutex);

  Int16* newFragment;

  if (!fragment) {
    if (!myFirstFragmentForEnqueue) throw runtime_error("enqueue called empty");

    newFragment = myFirstFragmentForEnqueue;
85
    myFirstFragmentForEnqueue = nullptr;
86
87
88
89

    return newFragment;
  }

90
  const uInt8 capacity = uInt8(myFragmentQueue.size());
91
92
93
94
95
  const uInt8 fragmentIndex = (myNextFragment + mySize) % capacity;

  newFragment = myFragmentQueue.at(fragmentIndex);
  myFragmentQueue.at(fragmentIndex) = fragment;

96
  if (mySize < capacity) ++mySize;
97
98
  else {
    myNextFragment = (myNextFragment + 1) % capacity;
99
    if (!myIgnoreOverflows) myOverflowLogger.log();
100
  }
101
102
103
104
105
106
107
108
109

  return newFragment;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int16* AudioQueue::dequeue(Int16* fragment)
{
  lock_guard<mutex> guard(myMutex);

110
  if (mySize == 0) return nullptr;
111
112
113
114
115

  if (!fragment) {
    if (!myFirstFragmentForDequeue) throw runtime_error("dequeue called empty");

    fragment = myFirstFragmentForDequeue;
116
    myFirstFragmentForDequeue = nullptr;
117
118
119
120
121
  }

  Int16* nextFragment = myFragmentQueue.at(myNextFragment);
  myFragmentQueue.at(myNextFragment) = fragment;

122
  --mySize;
123
124
125
126
  myNextFragment = (myNextFragment + 1) % myFragmentQueue.size();

  return nextFragment;
}
127
128
129
130
131
132
133
134
135
136
137
138

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioQueue::closeSink(Int16* fragment)
{
  lock_guard<mutex> guard(myMutex);

  if (myFirstFragmentForDequeue && fragment)
    throw new runtime_error("attempt to return unknown buffer on closeSink");

  if (!myFirstFragmentForDequeue)
    myFirstFragmentForDequeue = fragment;
}
139
140
141
142
143
144

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioQueue::ignoreOverflows(bool shouldIgnoreOverflows)
{
  myIgnoreOverflows = shouldIgnoreOverflows;
}