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#ifndef AUDIO_QUEUE_HXX
19#define AUDIO_QUEUE_HXX
20
21#include <mutex>
22
23#include "bspf.hxx"
24#include "StaggeredLogger.hxx"
25
26/**
27 This class implements a an audio queue that acts both like a ring buffer
28 and a pool of audio fragments. The TIA emulation core fills a fragment
29 with samples and then returns it to the queue, receiving a new fragment
30 in return. The sound driver removes fragments for playback from the
31 queue and returns the used fragment in this process.
32
33 The queue needs to be threadsafe as the (SDL) audio driver runs on a
34 separate thread. Samples are stored as signed 16 bit integers
35 (platform endian).
36*/
37class AudioQueue
38{
39 public:
40
41 /**
42 Create a new AudioQueue.
43
44 @param fragmentSize The size (in stereo / mono samples) of each fragment
45 @param capacity The number of fragments that can be queued before wrapping.
46 @param isStereo Whether samples are stereo or mono.
47 */
48 AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo);
49
50 /**
51 Capacity getter.
52 */
53 uInt32 capacity() const;
54
55 /**
56 Size getter.
57 */
58 uInt32 size();
59
60 /**
61 Stereo / mono getter.
62 */
63 bool isStereo() const;
64
65 /**
66 Fragment size getter.
67 */
68 uInt32 fragmentSize() const;
69
70 /**
71 Enqueue a new fragment and get a new fragmen to fill.
72
73 @param fragment The returned fragment. This must be empty on the first call (when
74 there is nothing to return)
75 */
76 Int16* enqueue(Int16* fragment = nullptr);
77
78 /**
79 Dequeue a fragment for playback and return the played fragment. This may
80 return 0 if there is no queued fragment to return (in this case, the returned
81 fragment is not enqueued and must be passed in the next invocation).
82
83 @param fragment The returned fragment. This must be empty on the first call (when
84 there is nothing to return).
85 */
86 Int16* dequeue(Int16* fragment = nullptr);
87
88 /**
89 Return the currently playing fragment without drawing a new one. This is called
90 if the sink is closed and prepares the queue to be reopened.
91 */
92 void closeSink(Int16* fragment);
93
94 /**
95 Should we ignore overflows?
96 */
97 void ignoreOverflows(bool shouldIgnoreOverflows);
98
99 private:
100
101 // The size of an individual fragment (in stereo / mono samples)
102 uInt32 myFragmentSize;
103
104 // Are we using stereo samples?
105 bool myIsStereo;
106
107 // The fragment queue
108 vector<Int16*> myFragmentQueue;
109
110 // All fragments, including the two fragments that are in circulation.
111 vector<Int16*> myAllFragments;
112
113 // We allocate a consecutive slice of memory for the fragments.
114 unique_ptr<Int16[]> myFragmentBuffer;
115
116 // The nubmer if queued fragments
117 uInt32 mySize;
118
119 // The next fragment.
120 uInt32 myNextFragment;
121
122 // We need a mutex for thread safety.
123 std::mutex myMutex;
124
125 // The first (empty) enqueue call returns this fragment.
126 Int16* myFirstFragmentForEnqueue;
127 // The first (empty) dequeue call replaces the returned fragment with this fragment.
128 Int16* myFirstFragmentForDequeue;
129
130 // Log overflows?
131 bool myIgnoreOverflows;
132
133 StaggeredLogger myOverflowLogger;
134
135 private:
136
137 AudioQueue() = delete;
138 AudioQueue(const AudioQueue&) = delete;
139 AudioQueue(AudioQueue&&) = delete;
140 AudioQueue& operator=(const AudioQueue&) = delete;
141 AudioQueue& operator=(AudioQueue&&) = delete;
142};
143
144#endif // AUDIO_QUEUE_HXX
145