Tweak the ambience/crosfade layer to fade in regardless of another sample being there
Fix music not being looped sometimes Prevent channel less than 0 from being passed Set up a new music display element with an attached music name, it displays a scrolling text of the currently playing music Fix music packet processing issues Make SFX slider responsible for all music channels besides 0 (actual music) scrolltext.cpp code recipe was taken from https://stackoverflow.com/questions/10651514/text-scrolling-marquee-in-qlabel - thanks to leemes for that one, I only adapted it for newer C++ version and tweaked some stuff.
This commit is contained in:
parent
497901e8c3
commit
842b829bee
@ -19,16 +19,19 @@ class AOMusicPlayer
|
||||
public:
|
||||
AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app);
|
||||
virtual ~AOMusicPlayer();
|
||||
|
||||
void play(QString p_song, int channel=0, bool crossfade=false);
|
||||
void stop(int channel=0);
|
||||
void set_volume(int p_value, int channel=0);
|
||||
void set_volume(int p_value, int channel=-1);
|
||||
void set_looping(bool toggle, int channel=0);
|
||||
|
||||
const int m_channelmax = 4;
|
||||
|
||||
//These have to be public for the stupid sync thing
|
||||
// QWORD loop_start = 0;
|
||||
// QWORD loop_end = 0;
|
||||
|
||||
public slots:
|
||||
void play(QString p_song, int channel=0, bool crossfade=false);
|
||||
void stop(int channel=0);
|
||||
|
||||
private:
|
||||
QWidget *m_parent;
|
||||
AOApplication *ao_app;
|
||||
@ -36,7 +39,6 @@ private:
|
||||
bool m_looping = false;
|
||||
int m_volume = 0;
|
||||
|
||||
const int m_channelmax = 4;
|
||||
// Channel 0 = music
|
||||
// Channel 1 = ambience
|
||||
// Channel 2 = extra
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "datatypes.h"
|
||||
#include "debug_functions.h"
|
||||
#include "chatlogpiece.h"
|
||||
#include "scrolltext.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QLineEdit>
|
||||
@ -445,6 +446,9 @@ private:
|
||||
QListWidget *ui_area_list;
|
||||
QListWidget *ui_music_list;
|
||||
|
||||
ScrollText *ui_music_name;
|
||||
AOMovie *ui_music_display;
|
||||
|
||||
AOButton *ui_pair_button;
|
||||
QListWidget *ui_pair_list;
|
||||
QSpinBox *ui_pair_offset_spinbox;
|
||||
|
50
include/scrolltext.h
Normal file
50
include/scrolltext.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef SCROLLTEXT_H
|
||||
#define SCROLLTEXT_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QStaticText>
|
||||
#include <QTimer>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
class ScrollText : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QString separator READ separator WRITE setSeparator)
|
||||
|
||||
public:
|
||||
explicit ScrollText(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
QString text() const;
|
||||
void setText(QString text);
|
||||
|
||||
QString separator() const;
|
||||
void setSeparator(QString separator);
|
||||
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *);
|
||||
virtual void resizeEvent(QResizeEvent *);
|
||||
|
||||
private:
|
||||
void updateText();
|
||||
QString _text;
|
||||
QString _separator;
|
||||
QStaticText staticText;
|
||||
int singleTextWidth;
|
||||
QSize wholeTextSize;
|
||||
int leftMargin;
|
||||
bool scrollEnabled;
|
||||
int scrollPos;
|
||||
QImage alphaChannel;
|
||||
QImage buffer;
|
||||
QTimer timer;
|
||||
|
||||
private slots:
|
||||
virtual void timer_timeout();
|
||||
};
|
||||
|
||||
#endif // SCROLLTEXT_H
|
@ -18,6 +18,8 @@ AOMusicPlayer::~AOMusicPlayer()
|
||||
void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
||||
{
|
||||
channel = channel % m_channelmax;
|
||||
if (channel < 0) //wtf?
|
||||
return;
|
||||
QString f_path = ao_app->get_music_path(p_song);
|
||||
// QString d_path = f_path + ".txt";
|
||||
|
||||
@ -39,27 +41,33 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
||||
// }
|
||||
|
||||
unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE;
|
||||
if (m_looping)
|
||||
flags |= BASS_SAMPLE_LOOP;
|
||||
DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags);
|
||||
|
||||
if (ao_app->get_audio_output_device() != "default")
|
||||
BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice());
|
||||
|
||||
if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING && crossfade)
|
||||
if (crossfade)
|
||||
{
|
||||
DWORD oldstream = m_stream_list[channel];
|
||||
|
||||
//Fade out the other sample and stop it
|
||||
BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 5000);
|
||||
BASS_ChannelLock(oldstream, true);
|
||||
//Mute the new sample
|
||||
BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0);
|
||||
//Sync it with the new sample
|
||||
BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE);
|
||||
//Crossfade time
|
||||
if (BASS_ChannelIsActive(oldstream) == BASS_ACTIVE_PLAYING)
|
||||
{
|
||||
//Fade out the other sample and stop it
|
||||
BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL|BASS_SLIDE_LOG, -1, 5000);
|
||||
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);
|
||||
}
|
||||
//Start it
|
||||
BASS_ChannelPlay(newstream, false);
|
||||
//Fade in our sample
|
||||
BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast<float>(m_volume / 100.0f), 1000);
|
||||
BASS_ChannelLock(oldstream, false);
|
||||
|
||||
m_stream_list[channel] = newstream;
|
||||
}
|
||||
else
|
||||
@ -67,7 +75,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
||||
BASS_ChannelStop(m_stream_list[channel]);
|
||||
m_stream_list[channel] = newstream;
|
||||
BASS_ChannelPlay(m_stream_list[channel], false);
|
||||
this->set_volume(m_volume);
|
||||
this->set_volume(m_volume, channel);
|
||||
}
|
||||
|
||||
this->set_looping(m_looping); //Have to do this here due to any crossfading-related changes, etc.
|
||||
@ -82,7 +90,17 @@ void AOMusicPlayer::set_volume(int p_value, int channel)
|
||||
{
|
||||
m_volume = p_value;
|
||||
float volume = m_volume / 100.0f;
|
||||
BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume);
|
||||
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 CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user)
|
||||
|
@ -125,6 +125,14 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
|
||||
ui_area_list->hide();
|
||||
ui_music_list = new QListWidget(this);
|
||||
|
||||
ui_music_display = new AOMovie(this, ao_app);
|
||||
ui_music_display->set_play_once(false);
|
||||
ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
ui_music_name = new ScrollText(ui_music_display);
|
||||
ui_music_name->setText(tr("None"));
|
||||
ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
ui_ic_chat_name = new QLineEdit(this);
|
||||
ui_ic_chat_name->setFrame(false);
|
||||
ui_ic_chat_name->setPlaceholderText(tr("Showname"));
|
||||
@ -544,6 +552,24 @@ void Courtroom::set_widgets()
|
||||
set_size_and_pos(ui_area_list, "music_list");
|
||||
set_size_and_pos(ui_music_list, "music_list");
|
||||
|
||||
set_size_and_pos(ui_music_name, "music_name");
|
||||
|
||||
ui_music_display->move(0, 0);
|
||||
design_ini_result = ao_app->get_element_dimensions("music_display", "courtroom_design.ini");
|
||||
|
||||
if (design_ini_result.width < 0 || design_ini_result.height < 0)
|
||||
{
|
||||
qDebug() << "W: could not find \"music_name\" in courtroom_design.ini";
|
||||
ui_music_display->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
ui_music_display->move(design_ini_result.x, design_ini_result.y);
|
||||
ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height);
|
||||
}
|
||||
|
||||
ui_music_display->play("music_display");
|
||||
|
||||
if (is_ao2_bg)
|
||||
{
|
||||
set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message");
|
||||
@ -827,6 +853,7 @@ void Courtroom::set_fonts()
|
||||
set_font(ui_server_chatlog, "", "server_chatlog");
|
||||
set_font(ui_music_list, "", "music_list");
|
||||
set_font(ui_area_list, "", "area_list");
|
||||
set_font(ui_music_name, "", "music_name");
|
||||
|
||||
set_dropdowns();
|
||||
}
|
||||
@ -1081,7 +1108,12 @@ void Courtroom::enter_courtroom()
|
||||
list_music();
|
||||
list_areas();
|
||||
|
||||
music_player->set_volume(ui_music_slider->value());
|
||||
music_player->set_volume(ui_music_slider->value(), 0); //set music
|
||||
//Set the ambience and other misc. music layers
|
||||
for (int i = 1; i < music_player->m_channelmax; ++i)
|
||||
{
|
||||
music_player->set_volume(ui_sfx_slider->value(), i);
|
||||
}
|
||||
sfx_player->set_volume(ui_sfx_slider->value());
|
||||
objection_player->set_volume(ui_sfx_slider->value());
|
||||
blip_player->set_volume(ui_blip_slider->value());
|
||||
@ -1145,14 +1177,12 @@ void Courtroom::list_areas()
|
||||
for (int n_area = 0 ; n_area < area_list.size() ; ++n_area)
|
||||
{
|
||||
QString i_area = "";
|
||||
i_area.append("[");
|
||||
i_area.append(QString::number(n_area));
|
||||
i_area.append("] ");
|
||||
|
||||
i_area.append(area_list.at(n_area));
|
||||
|
||||
if (ao_app->arup_enabled)
|
||||
{
|
||||
i_area.prepend("[" + QString::number(n_area) + "] "); //Give it the index
|
||||
|
||||
i_area.append("\n ");
|
||||
|
||||
i_area.append(arup_statuses.at(n_area));
|
||||
@ -2873,30 +2903,33 @@ void Courtroom::handle_song(QStringList *p_contents)
|
||||
f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf("."));
|
||||
int n_char = f_contents.at(1).toInt();
|
||||
|
||||
bool looping = true;
|
||||
int channel = 0;
|
||||
bool crossfade = false;
|
||||
if (n_char < 0 || n_char >= char_list.size())
|
||||
{
|
||||
music_player->set_looping(true);
|
||||
int channel = 0;
|
||||
if (p_contents->length() > 3 && p_contents->at(3) != "-1")
|
||||
music_player->set_looping(false);
|
||||
looping = false;
|
||||
|
||||
if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh
|
||||
channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list
|
||||
|
||||
bool crossfade = false;
|
||||
if (p_contents->length() > 5) //CROSSFADE!? Are you MAD?
|
||||
{
|
||||
qDebug() << p_contents->at(5);
|
||||
crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list
|
||||
}
|
||||
|
||||
qDebug() << f_song << channel << p_contents->at(3) << looping;
|
||||
music_player->set_looping(looping, channel);
|
||||
music_player->play(f_song, channel, crossfade);
|
||||
if (channel == 0)
|
||||
ui_music_name->setText(f_song);
|
||||
}
|
||||
else
|
||||
{
|
||||
QString str_char = char_list.at(n_char).name;
|
||||
QString str_show = char_list.at(n_char).name;
|
||||
music_player->set_looping(true);
|
||||
|
||||
if (p_contents->length() > 2)
|
||||
{
|
||||
@ -2905,20 +2938,15 @@ void Courtroom::handle_song(QStringList *p_contents)
|
||||
str_show = p_contents->at(2);
|
||||
}
|
||||
}
|
||||
if (p_contents->length() > 3)
|
||||
if (p_contents->length() > 3 && p_contents->at(3) != "-1")
|
||||
{
|
||||
//I am really confused why "-1" is "loop this song" and why anything else passes as "don't loop"
|
||||
//(if we even have this length) but alright
|
||||
if(p_contents->at(3) != "-1")
|
||||
{
|
||||
music_player->set_looping(false);
|
||||
}
|
||||
looping = false;
|
||||
}
|
||||
int channel = 0;
|
||||
if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh
|
||||
channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list
|
||||
|
||||
bool crossfade = false;
|
||||
if (p_contents->length() > 5) //CROSSFADE!? Are you MAD?
|
||||
crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list
|
||||
|
||||
@ -2934,7 +2962,10 @@ void Courtroom::handle_song(QStringList *p_contents)
|
||||
}
|
||||
|
||||
append_ic_text(f_song_clear, str_show, true);
|
||||
music_player->set_looping(looping, channel);
|
||||
music_player->play(f_song, channel, crossfade);
|
||||
if (channel == 0)
|
||||
ui_music_name->setText(f_song);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3915,13 +3946,18 @@ void Courtroom::on_text_color_changed(int p_color)
|
||||
|
||||
void Courtroom::on_music_slider_moved(int p_value)
|
||||
{
|
||||
music_player->set_volume(p_value);
|
||||
music_player->set_volume(p_value, 0); //Set volume on music layer
|
||||
ui_ic_chat_message->setFocus();
|
||||
}
|
||||
|
||||
void Courtroom::on_sfx_slider_moved(int p_value)
|
||||
{
|
||||
sfx_player->set_volume(p_value);
|
||||
//Set the ambience and other misc. music layers
|
||||
for (int i = 1; i < music_player->m_channelmax; ++i)
|
||||
{
|
||||
music_player->set_volume(p_value, i);
|
||||
}
|
||||
objection_player->set_volume(p_value);
|
||||
ui_ic_chat_message->setFocus();
|
||||
}
|
||||
@ -3986,7 +4022,6 @@ void Courtroom::on_change_character_clicked()
|
||||
{
|
||||
music_player->set_volume(0);
|
||||
sfx_player->set_volume(0);
|
||||
sfx_player->set_volume(0);
|
||||
blip_player->set_volume(0);
|
||||
|
||||
set_char_select();
|
||||
|
134
src/scrolltext.cpp
Normal file
134
src/scrolltext.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "scrolltext.h"
|
||||
|
||||
|
||||
ScrollText::ScrollText(QWidget *parent) :
|
||||
QWidget(parent), scrollPos(0)
|
||||
{
|
||||
staticText.setTextFormat(Qt::PlainText);
|
||||
|
||||
// setFixedHeight(fontMetrics().height()*2); //The theme sets this
|
||||
leftMargin = height() / 3;
|
||||
|
||||
setSeparator(" --- ");
|
||||
|
||||
connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout()));
|
||||
timer.setInterval(50);
|
||||
}
|
||||
|
||||
QString ScrollText::text() const
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
|
||||
void ScrollText::setText(QString text)
|
||||
{
|
||||
_text = text;
|
||||
updateText();
|
||||
update();
|
||||
}
|
||||
|
||||
QString ScrollText::separator() const
|
||||
{
|
||||
return _separator;
|
||||
}
|
||||
|
||||
void ScrollText::setSeparator(QString separator)
|
||||
{
|
||||
_separator = separator;
|
||||
updateText();
|
||||
update();
|
||||
}
|
||||
|
||||
void ScrollText::updateText()
|
||||
{
|
||||
timer.stop();
|
||||
|
||||
singleTextWidth = fontMetrics().horizontalAdvance(_text);
|
||||
scrollEnabled = (singleTextWidth > width() - leftMargin*2);
|
||||
|
||||
if(scrollEnabled)
|
||||
{
|
||||
scrollPos = -64;
|
||||
staticText.setText(_text + _separator);
|
||||
timer.start();
|
||||
}
|
||||
else
|
||||
staticText.setText(_text);
|
||||
|
||||
staticText.prepare(QTransform(), font());
|
||||
wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), fontMetrics().height());
|
||||
}
|
||||
|
||||
void ScrollText::paintEvent(QPaintEvent*)
|
||||
{
|
||||
QPainter p(this);
|
||||
|
||||
if(scrollEnabled)
|
||||
{
|
||||
buffer.fill(qRgba(0, 0, 0, 0));
|
||||
QPainter pb(&buffer);
|
||||
pb.setPen(p.pen());
|
||||
pb.setFont(p.font());
|
||||
|
||||
int x = qMin(-scrollPos, 0) + leftMargin;
|
||||
while(x < width())
|
||||
{
|
||||
pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), staticText);
|
||||
x += wholeTextSize.width();
|
||||
}
|
||||
|
||||
//Apply Alpha Channel
|
||||
pb.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||
pb.setClipRect(width() - 15, 0, 15, height());
|
||||
pb.drawImage(0, 0, alphaChannel);
|
||||
pb.setClipRect(0, 0, 15, height());
|
||||
//initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive
|
||||
if(scrollPos < 0)
|
||||
pb.setOpacity(static_cast<qreal>((qMax(-8, scrollPos) + 8) / 8.0));
|
||||
pb.drawImage(0, 0, alphaChannel);
|
||||
|
||||
//pb.end();
|
||||
p.drawImage(0, 0, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollText::resizeEvent(QResizeEvent*)
|
||||
{
|
||||
//When the widget is resized, we need to update the alpha channel.
|
||||
|
||||
alphaChannel = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
//Create Alpha Channel:
|
||||
if(width() > 64)
|
||||
{
|
||||
//create first scanline
|
||||
QRgb* scanline1 = reinterpret_cast<QRgb*>(alphaChannel.scanLine(0));
|
||||
for(int x = 1; x < 16; ++x)
|
||||
scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4);
|
||||
for(int x = 15; x < width() - 15; ++x)
|
||||
scanline1[x] = qRgb(0, 0, 0);
|
||||
//copy scanline to the other ones
|
||||
for(int y = 1; y < height(); ++y)
|
||||
memcpy(alphaChannel.scanLine(y), scanline1, static_cast<uint>(width() * 4));
|
||||
}
|
||||
else
|
||||
alphaChannel.fill(qRgb(0, 0, 0));
|
||||
|
||||
|
||||
//Update scrolling state
|
||||
bool newScrollEnabled = (singleTextWidth > width() - leftMargin);
|
||||
if(newScrollEnabled != scrollEnabled)
|
||||
updateText();
|
||||
}
|
||||
|
||||
void ScrollText::timer_timeout()
|
||||
{
|
||||
scrollPos = (scrollPos + 2)
|
||||
% wholeTextSize.width();
|
||||
update();
|
||||
}
|
Loading…
Reference in New Issue
Block a user