1 /***************************************************************************
2  *   Copyright (C) 2008-2021 by Andrzej Rybczak                            *
3  *   andrzej@rybczak.net                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
19  ***************************************************************************/
20 
21 #include "global.h"
22 #include "helpers.h"
23 #include "screens/song_info.h"
24 #include "screens/tag_editor.h"
25 #include "tags.h"
26 #include "title.h"
27 #include "screens/screen_switcher.h"
28 
29 #ifdef HAVE_TAGLIB_H
30 # include "fileref.h"
31 # include "tag.h"
32 # include <boost/lexical_cast.hpp>
33 #endif // HAVE_TAGLIB_H
34 
35 using Global::MainHeight;
36 using Global::MainStartY;
37 
38 SongInfo *mySongInfo;
39 
40 const SongInfo::Metadata SongInfo::Tags[] =
41 {
42  { "Title",        &MPD::Song::getTitle,       &MPD::MutableSong::setTitle       },
43  { "Artist",       &MPD::Song::getArtist,      &MPD::MutableSong::setArtist      },
44  { "Album Artist", &MPD::Song::getAlbumArtist, &MPD::MutableSong::setAlbumArtist },
45  { "Album",        &MPD::Song::getAlbum,       &MPD::MutableSong::setAlbum       },
46  { "Date",         &MPD::Song::getDate,        &MPD::MutableSong::setDate        },
47  { "Track",        &MPD::Song::getTrack,       &MPD::MutableSong::setTrack       },
48  { "Genre",        &MPD::Song::getGenre,       &MPD::MutableSong::setGenre       },
49  { "Composer",     &MPD::Song::getComposer,    &MPD::MutableSong::setComposer    },
50  { "Performer",    &MPD::Song::getPerformer,   &MPD::MutableSong::setPerformer   },
51  { "Disc",         &MPD::Song::getDisc,        &MPD::MutableSong::setDisc        },
52  { "Comment",      &MPD::Song::getComment,     &MPD::MutableSong::setComment     },
53  { 0,              0,                          0                                 }
54 };
55 
SongInfo()56 SongInfo::SongInfo()
57 : Screen(NC::Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, NC::Border()))
58 { }
59 
resize()60 void SongInfo::resize()
61 {
62 	size_t x_offset, width;
63 	getWindowResizeParams(x_offset, width);
64 	w.resize(width, MainHeight);
65 	w.moveTo(x_offset, MainStartY);
66 	hasToBeResized = 0;
67 }
68 
title()69 std::wstring SongInfo::title()
70 {
71 	return L"Song info";
72 }
73 
switchTo()74 void SongInfo::switchTo()
75 {
76 	using Global::myScreen;
77 	if (myScreen != this)
78 	{
79 		auto s = currentSong(myScreen);
80 		if (!s)
81 			return;
82 		SwitchTo::execute(this);
83 		w.clear();
84 		w.reset();
85 		PrepareSong(*s);
86 		w.flush();
87 		// redraw header after we're done with the file, since reading it from disk
88 		// takes a bit of time and having header updated before content of a window
89 		// is displayed doesn't look nice.
90 		drawHeader();
91 	}
92 	else
93 		switchToPreviousScreen();
94 }
95 
PrepareSong(const MPD::Song & s)96 void SongInfo::PrepareSong(const MPD::Song &s)
97 {
98 	auto print_key_value = [this](const char *key, const auto &value) {
99 		w << NC::Format::Bold
100 		  << Config.color1
101 		  << key
102 		  << ":"
103 		  << NC::FormattedColor::End<>(Config.color1)
104 		  << NC::Format::NoBold
105 		  << " "
106 		  << Config.color2
107 		  << value
108 		  << NC::FormattedColor::End<>(Config.color2)
109 		  << "\n";
110 	};
111 
112 	print_key_value("Filename", s.getName());
113 	print_key_value("Directory", ShowTag(s.getDirectory()));
114 	w << "\n";
115 	print_key_value("Length", s.getLength());
116 
117 #	ifdef HAVE_TAGLIB_H
118 	if (!Config.mpd_music_dir.empty() && !s.isStream())
119 	{
120 		std::string path_to_file;
121 		if (s.isFromDatabase())
122 			path_to_file += Config.mpd_music_dir;
123 		path_to_file += s.getURI();
124 		TagLib::FileRef f(path_to_file.c_str());
125 		if (!f.isNull())
126 		{
127 			print_key_value(
128 				"Bitrate",
129 				boost::lexical_cast<std::string>(f.audioProperties()->bitrate()) + " kbps");
130 			print_key_value(
131 				"Sample rate",
132 				boost::lexical_cast<std::string>(f.audioProperties()->sampleRate()) + " Hz");
133 			print_key_value("Channels", channelsToString(f.audioProperties()->channels()));
134 
135 			auto rginfo = Tags::readReplayGain(f.file());
136 			if (!rginfo.empty())
137 			{
138 				w << "\n";
139 				print_key_value("Reference loudness", rginfo.referenceLoudness());
140 				print_key_value("Track gain", rginfo.trackGain());
141 				print_key_value("Track peak", rginfo.trackPeak());
142 				print_key_value("Album gain", rginfo.albumGain());
143 				print_key_value("Album peak", rginfo.albumPeak());
144 			}
145 		}
146 	}
147 #	endif // HAVE_TAGLIB_H
148 	w << NC::Color::Default;
149 
150 	for (const Metadata *m = Tags; m->Name; ++m)
151 	{
152 		w << NC::Format::Bold << "\n" << m->Name << ":" << NC::Format::NoBold << " ";
153 		ShowTag(w, s.getTags(m->Get));
154 	}
155 }
156