furnace/src/audio/sdlAudio.cpp

189 lines
4.5 KiB
C++
Raw Normal View History

2022-02-14 22:12:20 -05:00
/**
* Furnace Tracker - multi-system chiptune tracker
2025-01-28 18:49:19 -05:00
* Copyright (C) 2021-2025 tildearrow and contributors
2022-02-14 22:12:20 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include "../ta-log.h"
2022-06-23 17:25:51 -04:00
#include "sdlAudio.h"
void taSDLProcess(void* inst, unsigned char* buf, int nframes) {
TAAudioSDL* in=(TAAudioSDL*)inst;
in->onProcess(buf,nframes);
}
void TAAudioSDL::onProcess(unsigned char* buf, int nframes) {
2025-05-12 18:29:29 -04:00
unsigned int unframes=nframes/(sizeof(float)*MAX(1,desc.outChans));
if (nframes<0) {
logE("nframes is negative! (%d)",nframes);
return;
}
2025-05-12 18:29:29 -04:00
if (desc.outChans<1) {
logE("outChans is less than 1!");
return;
}
for (int i=0; i<desc.inChans; i++) {
if (unframes>desc.bufsize) {
delete[] inBufs[i];
inBufs[i]=new float[unframes];
}
}
for (int i=0; i<desc.outChans; i++) {
if (unframes>desc.bufsize) {
delete[] outBufs[i];
outBufs[i]=new float[unframes];
}
}
if (audioProcCallback!=NULL) {
if (midiIn!=NULL) midiIn->gather();
audioProcCallback(audioProcCallbackUser,inBufs,outBufs,desc.inChans,desc.outChans,unframes);
}
float* fbuf=(float*)buf;
for (size_t j=0; j<unframes; j++) {
2021-05-11 19:23:35 -04:00
for (size_t i=0; i<desc.outChans; i++) {
fbuf[j*desc.outChans+i]=outBufs[i][j];
}
}
if (unframes!=desc.bufsize) {
desc.bufsize=unframes;
}
}
void* TAAudioSDL::getContext() {
return (void*)&ac;
}
bool TAAudioSDL::quit() {
if (!initialized) return false;
if (ai!=0) {
SDL_CloseAudioDevice(ai);
}
if (running) {
running=false;
}
for (int i=0; i<desc.outChans; i++) {
delete[] outBufs[i];
}
delete[] outBufs;
initialized=false;
return true;
}
bool TAAudioSDL::setRun(bool run) {
if (!initialized) return false;
SDL_PauseAudioDevice(ai,!run);
running=run;
return running;
}
2022-02-13 21:42:57 -05:00
std::vector<String> TAAudioSDL::listAudioDevices() {
std::vector<String> ret;
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL to list audio devices");
2022-02-13 21:42:57 -05:00
} else {
audioSysStarted=true;
}
}
int count=SDL_GetNumAudioDevices(false);
if (count<0) return ret;
for (int i=0; i<count; i++) {
const char* devName=SDL_GetAudioDeviceName(i,false);
if (devName!=NULL) {
ret.push_back(String(devName));
}
}
return ret;
}
bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
if (initialized) {
logE("audio already initialized");
return false;
}
2022-02-13 21:42:57 -05:00
if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL");
2022-02-13 21:42:57 -05:00
return false;
}
audioSysStarted=true;
}
2022-12-04 16:12:30 -05:00
const char* audioDriver=SDL_GetCurrentAudioDriver();
if (audioDriver==NULL) {
logD("SDL audio driver: NULL!");
} else {
logD("SDL audio driver: %s",audioDriver);
}
desc=request;
desc.outFormat=TA_AUDIO_FORMAT_F32;
ac.freq=desc.rate;
2022-08-19 15:36:22 -04:00
#ifdef TA_BIG_ENDIAN
ac.format=AUDIO_F32MSB;
#else
ac.format=AUDIO_F32;
2022-08-19 15:36:22 -04:00
#endif
ac.channels=desc.outChans;
ac.samples=desc.bufsize;
ac.callback=taSDLProcess;
ac.userdata=this;
2023-08-26 20:18:39 -04:00
logV("opening audio device...");
2023-07-06 19:29:29 -04:00
ai=SDL_OpenAudioDevice(request.deviceName.empty()?NULL:request.deviceName.c_str(),0,&ac,&ar,0);
if (ai==0) {
logE("could not open audio device: %s",SDL_GetError());
return false;
}
2023-07-06 19:29:29 -04:00
const char* backendName=SDL_GetCurrentAudioDriver();
2022-02-13 21:42:57 -05:00
desc.deviceName=request.deviceName;
2023-07-06 19:29:29 -04:00
if (backendName==NULL) {
desc.name="";
} else {
desc.name=backendName;
}
desc.rate=ar.freq;
desc.inChans=0;
desc.outChans=ar.channels;
desc.bufsize=ar.samples;
desc.fragments=1;
2023-08-26 20:18:39 -04:00
logV("got info: %d channels, %d bufsize",desc.outChans,desc.bufsize);
if (desc.outChans>0) {
outBufs=new float*[desc.outChans];
for (int i=0; i<desc.outChans; i++) {
outBufs[i]=new float[desc.bufsize];
}
}
response=desc;
initialized=true;
return true;
}