I HAVE CONQUERED BASS HELL
BEHOLD, LOOP_START AND LOOP_END MUSIC POINTS! It reads the songname.mp3.txt file, looking for loop_start, loop_length and loop_end in samples MUSIC EFFECTS SYSTEM THAT CAN ***COMMUNICATE WITH THE SERVER***, WOAHHHHHHHHH! RIGHT-CLICK CONTEXT MENUS TO ENABLE/DISABLE SPECIFIC MUSIC EFFECTS MUSIC EFFECTS ENUMS Fix an issue with music looping
This commit is contained in:
parent
65332f209c
commit
9f543f9ef7
@ -29,7 +29,7 @@ public:
|
|||||||
QWORD loop_end = 0;
|
QWORD loop_end = 0;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void play(QString p_song, int channel=0, bool crossfade=false);
|
void play(QString p_song, int channel=0, bool loop=false, int effect_flags=0);
|
||||||
void stop(int channel=0);
|
void stop(int channel=0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -396,6 +396,9 @@ private:
|
|||||||
|
|
||||||
QString effect = "";
|
QString effect = "";
|
||||||
|
|
||||||
|
//Music effect flags we want to send to server when we play music
|
||||||
|
int music_flags = 0;
|
||||||
|
|
||||||
int defense_bar_state = 0;
|
int defense_bar_state = 0;
|
||||||
int prosecution_bar_state = 0;
|
int prosecution_bar_state = 0;
|
||||||
|
|
||||||
@ -643,6 +646,9 @@ private slots:
|
|||||||
void on_music_search_edited(QString p_text);
|
void on_music_search_edited(QString p_text);
|
||||||
void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column);
|
void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column);
|
||||||
void on_music_list_context_menu_requested(const QPoint &pos);
|
void on_music_list_context_menu_requested(const QPoint &pos);
|
||||||
|
void music_fade_out(bool toggle);
|
||||||
|
void music_fade_in(bool toggle);
|
||||||
|
void music_synchronize(bool toggle);
|
||||||
void music_list_expand_all();
|
void music_list_expand_all();
|
||||||
void music_list_collapse_all();
|
void music_list_collapse_all();
|
||||||
void on_area_list_double_clicked(QModelIndex p_model);
|
void on_area_list_double_clicked(QModelIndex p_model);
|
||||||
|
@ -110,4 +110,11 @@ enum CHAT_MESSAGE
|
|||||||
EFFECTS
|
EFFECTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MUSIC_EFFECT
|
||||||
|
{
|
||||||
|
FADE_IN = 1,
|
||||||
|
FADE_OUT = 2,
|
||||||
|
SYNC_POS = 4
|
||||||
|
};
|
||||||
|
|
||||||
#endif // DATATYPES_H
|
#endif // DATATYPES_H
|
||||||
|
@ -15,7 +15,7 @@ AOMusicPlayer::~AOMusicPlayer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
void AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags)
|
||||||
{
|
{
|
||||||
channel = channel % m_channelmax;
|
channel = channel % m_channelmax;
|
||||||
if (channel < 0) //wtf?
|
if (channel < 0) //wtf?
|
||||||
@ -23,8 +23,9 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
|||||||
QString f_path = ao_app->get_music_path(p_song);
|
QString f_path = ao_app->get_music_path(p_song);
|
||||||
|
|
||||||
unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE;
|
unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE;
|
||||||
if (m_looping)
|
if (loop)
|
||||||
flags |= BASS_SAMPLE_LOOP;
|
flags |= BASS_SAMPLE_LOOP;
|
||||||
|
|
||||||
DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags);
|
DWORD newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags);
|
||||||
|
|
||||||
if (ao_app->get_audio_output_device() != "default")
|
if (ao_app->get_audio_output_device() != "default")
|
||||||
@ -33,8 +34,8 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
|||||||
QString d_path = f_path + ".txt";
|
QString d_path = f_path + ".txt";
|
||||||
|
|
||||||
loop_start = 0;
|
loop_start = 0;
|
||||||
loop_end = 0;
|
loop_end = BASS_ChannelGetLength(newstream, BASS_POS_BYTE);
|
||||||
if (m_looping && file_exists(d_path)) //Contains loop/etc. information file
|
if (loop && file_exists(d_path)) //Contains loop/etc. information file
|
||||||
{
|
{
|
||||||
QStringList lines = ao_app->read_file(d_path).split("\n");
|
QStringList lines = ao_app->read_file(d_path).split("\n");
|
||||||
foreach (QString line, lines)
|
foreach (QString line, lines)
|
||||||
@ -46,49 +47,60 @@ void AOMusicPlayer::play(QString p_song, int channel, bool crossfade)
|
|||||||
|
|
||||||
float sample_rate;
|
float sample_rate;
|
||||||
BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate);
|
BASS_ChannelGetAttribute(newstream, BASS_ATTRIB_FREQ, &sample_rate);
|
||||||
qDebug() << sample_rate << args[1].trimmed();
|
|
||||||
|
|
||||||
|
//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")
|
if (arg == "loop_start")
|
||||||
loop_start = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast<double>(sample_rate));
|
loop_start = bytes;
|
||||||
else if (arg == "loop_length")
|
else if (arg == "loop_length")
|
||||||
loop_end = loop_start + BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast<double>(sample_rate));
|
loop_end = loop_start + bytes;
|
||||||
else if (arg == "loop_end")
|
else if (arg == "loop_end")
|
||||||
loop_end = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble() / static_cast<double>(sample_rate));
|
loop_end = bytes;
|
||||||
}
|
}
|
||||||
qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end;
|
qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << loop_start << "loop end" << loop_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crossfade)
|
if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING)
|
||||||
{
|
{
|
||||||
DWORD oldstream = m_stream_list[channel];
|
DWORD oldstream = m_stream_list[channel];
|
||||||
//Mute the new sample
|
|
||||||
BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0);
|
if (effect_flags & SYNC_POS)
|
||||||
//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);
|
BASS_ChannelLock(oldstream, true);
|
||||||
//Sync it with the new sample
|
//Sync it with the new sample
|
||||||
BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE);
|
BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE);
|
||||||
BASS_ChannelLock(oldstream, false);
|
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[channel] / 100.0f), 1000);
|
|
||||||
|
|
||||||
m_stream_list[channel] = newstream;
|
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
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
BASS_ChannelStop(m_stream_list[channel]);
|
BASS_ChannelStop(m_stream_list[channel]);
|
||||||
m_stream_list[channel] = newstream;
|
|
||||||
BASS_ChannelPlay(m_stream_list[channel], false);
|
|
||||||
this->set_volume(m_volume[channel], channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->set_looping(m_looping); //Have to do this here due to any crossfading-related changes, etc.
|
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); //Have to do this here due to any crossfading-related changes, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOMusicPlayer::stop(int channel)
|
void AOMusicPlayer::stop(int channel)
|
||||||
@ -115,29 +127,36 @@ void AOMusicPlayer::set_volume(int p_value, int channel)
|
|||||||
|
|
||||||
void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user)
|
void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user)
|
||||||
{
|
{
|
||||||
AOMusicPlayer *self= static_cast<AOMusicPlayer*>(user);
|
QWORD loop_start = *(static_cast<unsigned *>(user));
|
||||||
qDebug() << BASS_ChannelGetPosition(channel, BASS_POS_BYTE);
|
BASS_ChannelLock(channel, true);
|
||||||
BASS_ChannelSetPosition(channel, self->loop_start, BASS_POS_BYTE);
|
BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE);
|
||||||
|
BASS_ChannelLock(channel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOMusicPlayer::set_looping(bool toggle, int channel)
|
void AOMusicPlayer::set_looping(bool toggle, int channel)
|
||||||
{
|
{
|
||||||
m_looping = toggle;
|
m_looping = toggle;
|
||||||
qDebug() << "looping" << m_looping;
|
if (!m_looping)
|
||||||
if (m_looping == false && 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
|
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]);
|
BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]);
|
||||||
|
loop_sync[channel] = 0;
|
||||||
}
|
}
|
||||||
else if (m_looping == true)
|
else
|
||||||
{
|
{
|
||||||
BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag
|
BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag
|
||||||
BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]);
|
if (loop_sync[channel] != 0)
|
||||||
qDebug() << loop_end;
|
|
||||||
if (loop_end > 0)
|
|
||||||
{
|
{
|
||||||
loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end, loopProc, this);
|
BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); //remove the sync
|
||||||
qDebug() << "Started loop sync";
|
loop_sync[channel] = 0;
|
||||||
|
}
|
||||||
|
if (loop_start > 0)
|
||||||
|
{
|
||||||
|
if (loop_end == 0)
|
||||||
|
loop_end = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE);
|
||||||
|
if (loop_end > 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, loopProc, &loop_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2813,7 +2813,7 @@ void Courtroom::handle_song(QStringList *p_contents)
|
|||||||
|
|
||||||
bool looping = true;
|
bool looping = true;
|
||||||
int channel = 0;
|
int channel = 0;
|
||||||
bool crossfade = false;
|
int effect_flags = 0;
|
||||||
if (n_char < 0 || n_char >= char_list.size())
|
if (n_char < 0 || n_char >= char_list.size())
|
||||||
{
|
{
|
||||||
int channel = 0;
|
int channel = 0;
|
||||||
@ -2823,13 +2823,12 @@ void Courtroom::handle_song(QStringList *p_contents)
|
|||||||
if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh
|
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
|
channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list
|
||||||
|
|
||||||
if (p_contents->length() > 5) //CROSSFADE!? Are you MAD?
|
if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc.
|
||||||
{
|
{
|
||||||
crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list
|
effect_flags = p_contents->at(5).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
music_player->set_looping(looping, channel);
|
music_player->play(f_song, channel, looping, effect_flags);
|
||||||
music_player->play(f_song, channel, crossfade);
|
|
||||||
if (channel == 0)
|
if (channel == 0)
|
||||||
ui_music_name->setText(f_song);
|
ui_music_name->setText(f_song);
|
||||||
}
|
}
|
||||||
@ -2854,8 +2853,10 @@ void Courtroom::handle_song(QStringList *p_contents)
|
|||||||
if (p_contents->length() > 4) //eyyy we want to change this song's CHANNEL huh
|
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
|
channel = p_contents->at(4).toInt(); //let the music player handle it if it's bigger than the channel list
|
||||||
|
|
||||||
if (p_contents->length() > 5) //CROSSFADE!? Are you MAD?
|
if (p_contents->length() > 5) //Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc.
|
||||||
crossfade = p_contents->at(5) == "1"; //let the music player handle it if it's bigger than the channel list
|
{
|
||||||
|
effect_flags = p_contents->at(5).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
if (!mute_map.value(n_char))
|
if (!mute_map.value(n_char))
|
||||||
{
|
{
|
||||||
@ -2869,8 +2870,8 @@ void Courtroom::handle_song(QStringList *p_contents)
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_ic_text(f_song_clear, str_show, true);
|
append_ic_text(f_song_clear, str_show, true);
|
||||||
music_player->set_looping(looping, channel);
|
|
||||||
music_player->play(f_song, channel, crossfade);
|
music_player->play(f_song, channel, looping, effect_flags);
|
||||||
if (channel == 0)
|
if (channel == 0)
|
||||||
ui_music_name->setText(f_song);
|
ui_music_name->setText(f_song);
|
||||||
}
|
}
|
||||||
@ -3763,14 +3764,14 @@ void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column
|
|||||||
|
|
||||||
QString p_song = p_item->text(column);
|
QString p_song = p_item->text(column);
|
||||||
|
|
||||||
if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled)
|
QStringList packet_contents;
|
||||||
{
|
packet_contents.append(p_song);
|
||||||
ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#" + ui_ic_chat_name->text() + "#%"), false);
|
packet_contents.append(QString::number(m_cid));
|
||||||
}
|
if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled) || ao_app->effects_enabled)
|
||||||
else
|
packet_contents.append(ui_ic_chat_name->text());
|
||||||
{
|
if (ao_app->effects_enabled)
|
||||||
ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), false);
|
packet_contents.append(QString::number(music_flags));
|
||||||
}
|
ao_app->send_server_packet(new AOPacket("MC", packet_contents), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Courtroom::on_music_list_context_menu_requested(const QPoint &pos)
|
void Courtroom::on_music_list_context_menu_requested(const QPoint &pos)
|
||||||
@ -3779,9 +3780,50 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos)
|
|||||||
|
|
||||||
menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all()));
|
menu->addAction(QString("Expand All Categories"), this, SLOT(music_list_expand_all()));
|
||||||
menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all()));
|
menu->addAction(QString("Collapse All Categories"), this, SLOT(music_list_collapse_all()));
|
||||||
// menu->addSeparator();
|
menu->addSeparator();
|
||||||
|
|
||||||
|
menu->addAction(new QAction("Fade Out Previous", this));
|
||||||
|
menu->actions().back()->setCheckable(true);
|
||||||
|
menu->actions().back()->setChecked(music_flags & FADE_OUT);
|
||||||
|
connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_out(bool)));
|
||||||
|
|
||||||
|
menu->addAction(new QAction("Fade In", this));
|
||||||
|
menu->actions().back()->setCheckable(true);
|
||||||
|
menu->actions().back()->setChecked(music_flags & FADE_IN);
|
||||||
|
connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_fade_in(bool)));
|
||||||
|
|
||||||
|
menu->addAction(new QAction("Synchronize", this));
|
||||||
|
menu->actions().back()->setCheckable(true);
|
||||||
|
menu->actions().back()->setChecked(music_flags & SYNC_POS);
|
||||||
|
connect(menu->actions().back(), SIGNAL(toggled(bool)), this, SLOT(music_synchronize(bool)));
|
||||||
|
|
||||||
menu->popup(ui_music_list->mapToGlobal(pos));
|
menu->popup(ui_music_list->mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Courtroom::music_fade_out(bool toggle)
|
||||||
|
{
|
||||||
|
if (toggle)
|
||||||
|
music_flags |= FADE_OUT;
|
||||||
|
else
|
||||||
|
music_flags &= ~FADE_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Courtroom::music_fade_in(bool toggle)
|
||||||
|
{
|
||||||
|
if (toggle)
|
||||||
|
music_flags |= FADE_IN;
|
||||||
|
else
|
||||||
|
music_flags &= ~FADE_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Courtroom::music_synchronize(bool toggle)
|
||||||
|
{
|
||||||
|
if (toggle)
|
||||||
|
music_flags |= SYNC_POS;
|
||||||
|
else
|
||||||
|
music_flags &= ~SYNC_POS;
|
||||||
|
}
|
||||||
|
|
||||||
void Courtroom::music_list_expand_all()
|
void Courtroom::music_list_expand_all()
|
||||||
{
|
{
|
||||||
ui_music_list->expandAll();
|
ui_music_list->expandAll();
|
||||||
|
Loading…
Reference in New Issue
Block a user