aboutsummaryrefslogtreecommitdiff
path: root/src/aomusicplayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/aomusicplayer.cpp')
-rw-r--r--src/aomusicplayer.cpp240
1 files changed, 179 insertions, 61 deletions
diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp
index 3ba9cf1d..249e01e5 100644
--- a/src/aomusicplayer.cpp
+++ b/src/aomusicplayer.cpp
@@ -1,107 +1,225 @@
#include "aomusicplayer.h"
-#if defined(BASSAUDIO)
+
AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app)
- : QObject()
{
m_parent = parent;
ao_app = p_ao_app;
}
-AOMusicPlayer::~AOMusicPlayer() { kill_loop(); }
+#ifdef BASSAUDIO
-void AOMusicPlayer::play(QString p_song)
+AOMusicPlayer::~AOMusicPlayer()
{
- BASS_ChannelStop(m_stream);
-
- f_path = ao_app->get_music_path(p_song);
-
- if (p_song.startsWith("http")) {
- m_stream = BASS_StreamCreateURL(f_path.toStdWString().c_str(), 0,
- BASS_STREAM_AUTOFREE | BASS_UNICODE |
- BASS_ASYNCFILE, NULL, NULL);
- } else {
- m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0,
- BASS_STREAM_AUTOFREE | BASS_UNICODE |
- BASS_ASYNCFILE);
+ for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
+ BASS_ChannelStop(m_stream_list[n_stream]);
}
+}
+
+void AOMusicPlayer::play(QString p_song, int channel, bool loop,
+ int effect_flags)
+{
+ channel = channel % m_channelmax;
+ if (channel < 0) // wtf?
+ return;
+ QString f_path = ao_app->get_music_path(p_song);
- this->set_volume(m_volume);
+ unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE |
+ BASS_UNICODE | BASS_ASYNCFILE;
+ if (loop)
+ flags |= BASS_SAMPLE_LOOP;
+
+ DWORD newstream;
+ if (f_path.endsWith(".opus"))
+ newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags);
+ else
+ newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags);
if (ao_app->get_audio_output_device() != "default")
- BASS_ChannelSetDevice(m_stream, BASS_GetDevice());
- if (enable_looping) {
- BASS_ChannelFlags(m_stream, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP);
+ BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice());
+
+ QString d_path = f_path + ".txt";
+
+ loop_start[channel] = 0;
+ loop_end[channel] = BASS_ChannelGetLength(newstream, BASS_POS_BYTE);
+ if (loop && file_exists(d_path)) // Contains loop/etc. information file
+ {
+ QStringList lines = ao_app->read_file(d_path).split("\n");
+ foreach (QString line, lines) {
+ QStringList args = line.split("=");
+ if (args.size() < 2)
+ continue;
+ QString arg = args[0].trimmed();
+
+ float sample_rate;
+ BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate);
+
+ // Grab number of bytes for sample size
+ int sample_size = 16 / 8;
+
+ // number of channels (stereo/mono)
+ int num_channels = 2;
+
+ // Calculate the bytes for loop_start/loop_end to use with the sync proc
+ QWORD bytes = static_cast<QWORD>(args[1].trimmed().toFloat() *
+ sample_size * num_channels);
+ if (arg == "loop_start")
+ loop_start[channel] = bytes;
+ else if (arg == "loop_length")
+ loop_end[channel] = loop_start[channel] + bytes;
+ else if (arg == "loop_end")
+ loop_end[channel] = bytes;
+ }
+ qDebug() << "Found data file for song" << p_song << "length"
+ << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start"
+ << loop_start << "loop end" << loop_end;
}
- else {
- BASS_ChannelFlags(m_stream, 0, BASS_SAMPLE_LOOP);
+
+ if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) {
+ DWORD oldstream = m_stream_list[channel];
+
+ if (effect_flags & SYNC_POS) {
+ BASS_ChannelLock(oldstream, true);
+ // Sync it with the new sample
+ BASS_ChannelSetPosition(newstream,
+ BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE),
+ BASS_POS_BYTE);
+ BASS_ChannelLock(oldstream, false);
+ }
+
+ if (effect_flags & FADE_OUT) {
+ // Fade out the other sample and stop it (due to -1)
+ BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG,
+ -1, 4000);
+ }
+ else
+ BASS_ChannelStop(
+ oldstream); // Stop the sample since we don't need it anymore
}
- BASS_ChannelPlay(m_stream, false);
+ else
+ BASS_ChannelStop(m_stream_list[channel]);
+
+ m_stream_list[channel] = newstream;
+ BASS_ChannelPlay(m_stream_list[channel], false);
+ if (effect_flags & FADE_IN) {
+ // Fade in our sample
+ BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0);
+ BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL,
+ static_cast<float>(m_volume[channel] / 100.0f),
+ 1000);
+ }
+ else
+ this->set_volume(m_volume[channel], channel);
+
+ this->set_looping(loop, channel); // Have to do this here due to any
+ // crossfading-related changes, etc.
}
-void AOMusicPlayer::set_volume(int p_value)
+void AOMusicPlayer::stop(int channel)
{
- m_volume = p_value;
- float volume = m_volume / 100.0f;
- BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume);
+ BASS_ChannelStop(m_stream_list[channel]);
}
-QString AOMusicPlayer::get_path() { return f_path; }
+void AOMusicPlayer::set_volume(int p_value, int channel)
+{
+ m_volume[channel] = p_value;
+ float volume = m_volume[channel] / 100.0f;
+ if (channel < 0) {
+ for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
+ BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL,
+ volume);
+ }
+ }
+ else {
+ BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume);
+ }
+}
-void AOMusicPlayer::kill_loop() { BASS_ChannelStop(m_stream); }
+void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user)
+{
+ QWORD loop_start = *(static_cast<unsigned *>(user));
+ BASS_ChannelLock(channel, true);
+ BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE);
+ BASS_ChannelLock(channel, false);
+}
-#elif defined(QTAUDIO)
-AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app)
- : QObject()
+void AOMusicPlayer::set_looping(bool toggle, int channel)
{
- m_parent = parent;
- ao_app = p_ao_app;
+ qDebug() << "Setting looping for channel" << channel << "to" << toggle;
+ m_looping = toggle;
+ if (!m_looping) {
+ if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP)
+ BASS_ChannelFlags(m_stream_list[channel], 0,
+ BASS_SAMPLE_LOOP); // remove the LOOP flag
+ BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]);
+ loop_sync[channel] = 0;
+ }
+ else {
+ BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP,
+ BASS_SAMPLE_LOOP); // set the LOOP flag
+ if (loop_sync[channel] != 0) {
+ BASS_ChannelRemoveSync(m_stream_list[channel],
+ loop_sync[channel]); // remove the sync
+ loop_sync[channel] = 0;
+ }
+ if (loop_start[channel] > 0) {
+ if (loop_end[channel] == 0)
+ loop_end[channel] = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE);
+ if (loop_end[channel] > 0) // Don't loop zero length songs even if we're asked to
+ loop_sync[channel] = BASS_ChannelSetSync(
+ m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end[channel],
+ loopProc, &loop_start[channel]);
+ }
+ }
}
+#elif defined(QTAUDIO)
-AOMusicPlayer::~AOMusicPlayer() { m_player.stop(); }
+AOMusicPlayer::~AOMusicPlayer() {
+ for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
+ m_stream_list[n_stream].stop();
+ }
+}
-void AOMusicPlayer::play(QString p_song)
+void AOMusicPlayer::play(QString p_song, int channel, bool loop,
+ int effect_flags)
{
- m_player.stop();
-
+ channel = channel % m_channelmax;
+ if (channel < 0) // wtf?
+ return;
QString f_path = ao_app->get_music_path(p_song);
- m_player.setMedia(QUrl::fromLocalFile(f_path));
+ m_stream_list[channel].stop();
- this->set_volume(100);
+ m_stream_list[channel].setMedia(QUrl::fromLocalFile(f_path));
- m_player.play();
+ this->set_volume(m_volume[channel], channel);
+
+ m_stream_list[channel].play();
}
-void AOMusicPlayer::set_volume(int p_value)
+void AOMusicPlayer::stop(int channel)
{
- m_volume = p_value;
-
- qreal linearVolume = QAudio::convertVolume(m_volume / qreal(100),
- QAudio::LogarithmicVolumeScale,
- QAudio::LinearVolumeScale);
-
- m_player.setVolume(linearVolume * 100);
+ m_stream_list[channel].stop();
}
-QString AOMusicPlayer::get_path() { return f_path; }
-
-void AOMusicPlayer::kill_loop() { m_player.stop(); }
-#else
-AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app)
- : QObject()
+void AOMusicPlayer::set_volume(int p_value, int channel)
{
- m_parent = parent;
- ao_app = p_ao_app;
+ m_volume[channel] = p_value;
+ m_stream_list[channel].setVolume(m_volume[channel]);
}
+#else
+
AOMusicPlayer::~AOMusicPlayer() {}
-void AOMusicPlayer::play(QString p_song) {}
+void AOMusicPlayer::play(QString p_song, int channel, bool loop,
+ int effect_flags) {}
+
+void AOMusicPlayer::stop(int channel) {}
-void AOMusicPlayer::set_volume(int p_value) {}
+void AOMusicPlayer::set_volume(int p_value, int channel) {}
-QString AOMusicPlayer::get_path() { return f_path; }
+void loopProc(int handle, int channel, int data, int *user) {}
-void AOMusicPlayer::kill_loop() {}
+void AOMusicPlayer::set_looping(bool toggle, int channel) {}
#endif