1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "RecordingDevice.h"
22#include "Audio.h"
23#include "sound/Sound.h"
24
25namespace love
26{
27namespace audio
28{
29namespace openal
30{
31
32#define soundInstance() (Module::getInstance<love::sound::Sound>(Module::M_SOUND))
33
34class InvalidFormatException : public love::Exception
35{
36public:
37
38 InvalidFormatException(int channels, int bitdepth)
39 : Exception("Recording %d channels with %d bits per sample is not supported.", channels, bitdepth)
40 {
41 }
42
43};
44
45RecordingDevice::RecordingDevice(const char *name)
46 : name(name)
47{
48}
49
50RecordingDevice::~RecordingDevice()
51{
52 stop();
53}
54
55bool RecordingDevice::start(int samples, int sampleRate, int bitDepth, int channels)
56{
57 ALenum format = Audio::getFormat(bitDepth, channels);
58 if (format == AL_NONE)
59 throw InvalidFormatException(channels, bitDepth);
60
61 if (samples <= 0)
62 throw love::Exception("Invalid number of samples.");
63
64 if (sampleRate <= 0)
65 throw love::Exception("Invalid sample rate.");
66
67 if (isRecording())
68 stop();
69
70 device = alcCaptureOpenDevice(name.c_str(), sampleRate, format, samples);
71 if (device == nullptr)
72 return false;
73
74 alcCaptureStart(device);
75
76 this->samples = samples;
77 this->sampleRate = sampleRate;
78 this->bitDepth = bitDepth;
79 this->channels = channels;
80
81 return true;
82}
83
84void RecordingDevice::stop()
85{
86 if (!isRecording())
87 return;
88
89 alcCaptureStop(device);
90 alcCaptureCloseDevice(device);
91 device = nullptr;
92}
93
94love::sound::SoundData *RecordingDevice::getData()
95{
96 if (!isRecording())
97 return nullptr;
98
99 int samples = getSampleCount();
100 if (samples == 0)
101 return nullptr;
102
103 love::sound::SoundData *soundData = soundInstance()->newSoundData(samples, sampleRate, bitDepth, channels);
104
105 alcCaptureSamples(device, soundData->getData(), samples);
106
107 return soundData;
108}
109
110int RecordingDevice::getSampleCount() const
111{
112 if (!isRecording())
113 return 0;
114
115 ALCint samples;
116 alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(ALCint), &samples);
117 return (int)samples;
118}
119
120int RecordingDevice::getMaxSamples() const
121{
122 return samples;
123}
124
125int RecordingDevice::getSampleRate() const
126{
127 return sampleRate;
128}
129
130int RecordingDevice::getBitDepth() const
131{
132 return bitDepth;
133}
134
135int RecordingDevice::getChannelCount() const
136{
137 return channels;
138}
139
140const char *RecordingDevice::getName() const
141{
142 return name.c_str();
143}
144
145bool RecordingDevice::isRecording() const
146{
147 return device != nullptr;
148}
149
150} //openal
151} //audio
152} //love
153