Skip to content

Commit c7d05f4

Browse files
author
siska
committedSep 21, 2018
Initial commit
0 parents  commit c7d05f4

23 files changed

+1590
-0
lines changed
 

‎.gitmodules

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[submodule "foobar2000_sdk"]
2+
path = foobar2000_sdk
3+
url = https://github.com/nixnodes/foobar2000_sdk
4+
[submodule "WTL10"]
5+
path = WTL10
6+
url = https://github.com/nixnodes/WTL10
7+
[submodule "WTL10_7336"]
8+
path = WTL10_7336
9+
url = https://github.com/nixnodes/WTL10

‎PCH.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#include "resource.h"
2+
#include "stdafx.h"
3+
4+
// This is a dummy source code file that just generates the precompiled header (PCH) file for use when compiling the rest of the source code, to speed compilation up.

‎WTL10_7336

Submodule WTL10_7336 added at db3c152

‎event_enums.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
enum events {
4+
EVENT_PLAYBACK_STARTING = 0,
5+
EVENT_PLAYBACK_NEW_TRACK,
6+
EVENT_PLAYBACK_STOP,
7+
EVENT_PLAYBACK_SEEK,
8+
EVENT_PLAYBACK_PAUSE,
9+
EVENT_PLAYBACK_EDITED,
10+
EVENT_PLAYBACK_DINFO,
11+
EVENT_PLAYBACK_DINFO_TRACK,
12+
EVENT_PLAYBACK_TIME,
13+
EVENT_VOLCHANGE,
14+
EVENT_COUNT
15+
};

‎events.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "stdafx.h"
2+
#include "events.h"
3+
#include "writer.h"
4+
5+
CEvents *IEvents::m_Events = nullptr;
6+
7+
event_item CEvents::UpdateInstance(instance_item *item)
8+
{
9+
RemoveInstance(item->name);
10+
11+
event_item evitem(item);
12+
13+
for (uint32_t i = 0; i < EVENT_COUNT; i++) {
14+
if (item->events[i] == true) {
15+
m_instancemap[i][item->name] = evitem;
16+
}
17+
}
18+
19+
return evitem;
20+
}
21+
22+
void CEvents::RemoveInstance(pfc::string8 name) {
23+
for (uint32_t i = 0; i < EVENT_COUNT; i++) {
24+
for (const auto &p : m_instancemap[i]) {
25+
if (name == p.first) {
26+
m_instancemap[i].erase(p.first);
27+
break;
28+
}
29+
}
30+
}
31+
}
32+
33+
void CEvents::event_update(uint32_t event) {
34+
for (const auto &p : m_instancemap[event]) {
35+
pfc::string_formatter str;
36+
37+
titleformat_object::ptr m_script = p.second.m_script;
38+
pfc::string_formatter state = format_title(m_script);
39+
40+
if (p.second.item.write_to_file) {
41+
write_job j(p.second.item.filename, state);
42+
if (p.second.item.enable_delay) {
43+
IWriter::WriteAsync(&j, p.second.item.delay);
44+
}
45+
else {
46+
IWriter::Write(&j);
47+
}
48+
}
49+
}
50+
};

‎events.h

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#pragma once
2+
3+
#include "stdafx.h"
4+
#include "prefs_instance.h"
5+
#include "event_enums.h"
6+
7+
#include <map>
8+
#include <vector>
9+
10+
#include <math.h>
11+
12+
static std::map<int, std::vector<pfc::string8>> _evtostr = {
13+
{EVENT_PLAYBACK_STARTING, {"Playback start","Trigger when playback starts"}},
14+
{EVENT_PLAYBACK_NEW_TRACK, {"New track","Trigger when new track starts playing"}},
15+
{EVENT_PLAYBACK_STOP, {"Playback stop","Trigger when playback stops"}},
16+
{EVENT_PLAYBACK_SEEK, {"Playback seek","Trigger on seek"}},
17+
{EVENT_PLAYBACK_PAUSE, {"Playback pause","Triger when playback is paused"}},
18+
{EVENT_PLAYBACK_EDITED, {"Playback edited",""}},
19+
{EVENT_PLAYBACK_DINFO, {"Playback dynamic info",""}},
20+
{EVENT_PLAYBACK_DINFO_TRACK, {"Playback dynamic info track",""}},
21+
{EVENT_PLAYBACK_TIME, {"Playback time","Trigger every second"}},
22+
{EVENT_VOLCHANGE, {"Volume change",""}},
23+
};
24+
25+
26+
class titleformat_hook_test : public titleformat_hook {
27+
public:
28+
titleformat_hook_test(metadb_handle_ptr p_track) : track(p_track) {}
29+
30+
bool process_field(titleformat_text_out * p_out, const char * p_name, t_size p_name_length, bool & p_found_flag) {
31+
if ( pfc::stricmp_ascii_ex(p_name, p_name_length, "isplaying", ~0) == 0) {
32+
if (m_playback_control->is_playing()) {
33+
p_out->write(titleformat_inputtypes::unknown, "1");
34+
p_found_flag = true; return true;
35+
}
36+
}
37+
else if (pfc::stricmp_ascii_ex(p_name, p_name_length, "ispaused", ~0) == 0) {
38+
if (m_playback_control->is_paused()) {
39+
p_out->write(titleformat_inputtypes::unknown, "1");
40+
p_found_flag = true; return true;
41+
}
42+
}
43+
else if (pfc::stricmp_ascii_ex(p_name, p_name_length, "playback_time", ~0) == 0) {
44+
pfc::string_formatter s;
45+
t_int64 total = (t_int64)m_playback_control->playback_get_position(), seconds, hours, minutes;
46+
minutes = total / 60;
47+
seconds = total % 60;
48+
hours = minutes / 60;
49+
minutes = minutes % 60;
50+
if (hours > 0)
51+
s << hours << ":";
52+
if (minutes > 0)
53+
s << minutes << ":";
54+
s << seconds;
55+
56+
p_out->write(titleformat_inputtypes::unknown, s);
57+
p_found_flag = true; return true;
58+
}
59+
else if (pfc::stricmp_ascii_ex(p_name, p_name_length, "title", ~0) == 0 ||
60+
pfc::stricmp_ascii_ex(p_name, p_name_length, "artist", ~0) == 0 ||
61+
pfc::stricmp_ascii_ex(p_name, p_name_length, "album", ~0) == 0) {
62+
if (!m_playback_control->is_playing()) {
63+
p_out->write(titleformat_inputtypes::unknown, "");
64+
p_found_flag = true; return true;
65+
}
66+
}
67+
else if (pfc::stricmp_ascii_ex(p_name, p_name_length, "volume", ~0) == 0) {
68+
pfc::string8 s;
69+
s << m_playback_control->get_volume();
70+
p_out->write(titleformat_inputtypes::unknown, s );
71+
p_found_flag = true; return true;
72+
}
73+
/*
74+
else if (pfc::stricmp_ascii_ex(p_name, p_name_length, "test", ~0) == 0) {
75+
if (m_playback_control->is_playing()) {
76+
//track->metadb_lock();
77+
file_info_impl fi;
78+
track->get_info(fi);
79+
p_out->write_int(titleformat_inputtypes::unknown,track->codec );
80+
p_found_flag = true; return true;
81+
}
82+
}
83+
*/
84+
85+
p_found_flag = false; return false;
86+
87+
}
88+
89+
bool process_function(titleformat_text_out * p_out, const char * p_name, t_size p_name_length, titleformat_hook_function_params * p_params, bool & p_found_flag) { return false; }
90+
91+
private:
92+
static_api_ptr_t<playback_control> m_playback_control;
93+
metadb_handle_ptr track;
94+
};
95+
96+
typedef struct event_item_s {
97+
instance_item item;
98+
titleformat_object::ptr m_script;
99+
100+
event_item_s(instance_item *p_item) {
101+
item = *p_item;
102+
static_api_ptr_t<titleformat_compiler>()->compile_safe_ex(m_script, item.format_string);
103+
}
104+
event_item_s() {}
105+
106+
} event_item;
107+
108+
class CEventsBase : private play_callback_impl_base {
109+
public:
110+
pfc::string8 format_title(titleformat_object::ptr &m_script) {
111+
pfc::string8 state;
112+
113+
if (last_track.is_empty()) {
114+
metadb_handle_ptr t;
115+
if (m_playback_control->get_now_playing(t)) {
116+
last_track = t;
117+
}
118+
}
119+
120+
if (!last_track.is_empty()) {
121+
m_playback_control->playback_format_title_ex(last_track, &titleformat_hook_test(last_track), state, m_script, NULL, playback_control::display_level_all);
122+
}
123+
else {
124+
m_playback_control->playback_format_title(NULL, state, m_script, NULL, playback_control::display_level_all);
125+
}
126+
127+
return state;
128+
}
129+
130+
static_api_ptr_t<playback_control> m_playback_control;
131+
metadb_handle_ptr last_track{ 0 };
132+
private:
133+
virtual void on_playback_starting(play_control::t_track_command p_command, bool p_paused) {
134+
event_pre(EVENT_PLAYBACK_STARTING);
135+
};
136+
virtual void on_playback_new_track(metadb_handle_ptr p_track) {
137+
last_track = p_track;
138+
event_pre(EVENT_PLAYBACK_NEW_TRACK);
139+
140+
}
141+
virtual void on_playback_stop(play_control::t_stop_reason p_reason) {
142+
if (p_reason != play_control::stop_reason_starting_another) {
143+
event_pre(EVENT_PLAYBACK_STOP);
144+
}
145+
}
146+
virtual void on_playback_pause(bool p_state) {
147+
event_pre(EVENT_PLAYBACK_PAUSE);
148+
}
149+
virtual void on_playback_seek(double p_time) {
150+
event_pre(EVENT_PLAYBACK_SEEK);
151+
}
152+
virtual void on_playback_edited(metadb_handle_ptr p_track) {
153+
event_pre(EVENT_PLAYBACK_EDITED);
154+
}
155+
virtual void on_playback_dynamic_info(const file_info & p_info) {
156+
event_pre(EVENT_PLAYBACK_DINFO);
157+
}
158+
virtual void on_playback_dynamic_info_track(const file_info & p_info) {
159+
event_pre(EVENT_PLAYBACK_DINFO_TRACK);
160+
}
161+
virtual void on_playback_time(double p_time) {
162+
event_pre(EVENT_PLAYBACK_TIME);
163+
}
164+
virtual void on_volume_change(float p_new_val) {
165+
event_pre(EVENT_VOLCHANGE);
166+
}
167+
168+
void event_pre(uint32_t event)
169+
{
170+
event_update(event);
171+
}
172+
173+
virtual void event_update(uint32_t event) {}
174+
175+
};
176+
177+
class CEvents : private CEventsBase {
178+
public:
179+
180+
event_item UpdateInstance(instance_item *item);
181+
void RemoveInstance(pfc::string8 name);
182+
private:
183+
184+
virtual void event_update(uint32_t event);
185+
186+
std::map<pfc::string8, event_item> m_instancemap[EVENT_COUNT];
187+
188+
};
189+
190+
class IEvents {
191+
public:
192+
193+
static void Initialize() {
194+
if (m_Events == nullptr) {
195+
m_Events = new CEvents();
196+
}
197+
}
198+
199+
static void Destroy() {
200+
if (m_Events != nullptr) {
201+
delete m_Events;
202+
}
203+
}
204+
205+
static event_item UpdateInstance(instance_item *item) {
206+
return m_Events->UpdateInstance(item);
207+
}
208+
209+
static void RemoveInstance(pfc::string8 name) {
210+
m_Events->RemoveInstance(name);
211+
}
212+
213+
static pfc::string8 EventToString(int ev)
214+
{
215+
if (_evtostr.count(ev) > 0) {
216+
return _evtostr[ev][0];
217+
}
218+
else {
219+
return "EVENT_UNKNOWN";
220+
}
221+
}
222+
223+
static pfc::string8 GetEventDescription(int ev)
224+
{
225+
if (_evtostr.count(ev) > 0) {
226+
return _evtostr[ev][1];
227+
}
228+
else {
229+
return "EVENT_UNKNOWN";
230+
}
231+
}
232+
233+
private:
234+
static CEvents *m_Events;
235+
};

‎foo_np_advanced.sln

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.27130.2027
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foo_npa", "foo_npa.vcxproj", "{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}"
7+
EndProject
8+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_ATL_helpers", "..\foobar2000_sdk\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj", "{622E8B19-8109-4717-BD4D-9657AA78363E}"
9+
EndProject
10+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_SDK", "..\foobar2000_sdk\foobar2000\SDK\foobar2000_SDK.vcxproj", "{E8091321-D79D-4575-86EF-064EA1A4A20D}"
11+
EndProject
12+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pfc", "..\foobar2000_sdk\pfc\pfc.vcxproj", "{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}"
13+
EndProject
14+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_sdk_helpers", "..\foobar2000_sdk\foobar2000\helpers\foobar2000_sdk_helpers.vcxproj", "{EE47764E-A202-4F85-A767-ABDAB4AFF35F}"
15+
EndProject
16+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_component_client", "..\foobar2000_sdk\foobar2000\foobar2000_component_client\foobar2000_component_client.vcxproj", "{71AD2674-065B-48F5-B8B0-E1F9D3892081}"
17+
EndProject
18+
Global
19+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
20+
Debug|x86 = Debug|x86
21+
Release|x86 = Release|x86
22+
EndGlobalSection
23+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
24+
{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Debug|x86.ActiveCfg = Debug|Win32
25+
{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Debug|x86.Build.0 = Debug|Win32
26+
{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Release|x86.ActiveCfg = Release|Win32
27+
{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Release|x86.Build.0 = Release|Win32
28+
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|x86.ActiveCfg = Debug|Win32
29+
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|x86.Build.0 = Debug|Win32
30+
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|x86.ActiveCfg = Release|Win32
31+
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|x86.Build.0 = Release|Win32
32+
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|x86.ActiveCfg = Debug|Win32
33+
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|x86.Build.0 = Debug|Win32
34+
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|x86.ActiveCfg = Release|Win32
35+
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|x86.Build.0 = Release|Win32
36+
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x86.ActiveCfg = Debug|Win32
37+
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x86.Build.0 = Debug|Win32
38+
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x86.ActiveCfg = Release|Win32
39+
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x86.Build.0 = Release|Win32
40+
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|x86.ActiveCfg = Debug|Win32
41+
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|x86.Build.0 = Debug|Win32
42+
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|x86.ActiveCfg = Release|Win32
43+
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|x86.Build.0 = Release|Win32
44+
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|x86.ActiveCfg = Debug|Win32
45+
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|x86.Build.0 = Debug|Win32
46+
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|x86.ActiveCfg = Release|Win32
47+
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|x86.Build.0 = Release|Win32
48+
EndGlobalSection
49+
GlobalSection(SolutionProperties) = preSolution
50+
HideSolutionNode = FALSE
51+
EndGlobalSection
52+
GlobalSection(ExtensibilityGlobals) = postSolution
53+
SolutionGuid = {C30C2B27-E29B-4792-B392-ED729AF2CF49}
54+
EndGlobalSection
55+
EndGlobal

‎foo_npa.aps

37.7 KB
Binary file not shown.

‎foo_npa.rc

7.42 KB
Binary file not shown.

‎foo_npa.vcxproj

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Debug|Win32">
5+
<Configuration>Debug</Configuration>
6+
<Platform>Win32</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Release|Win32">
9+
<Configuration>Release</Configuration>
10+
<Platform>Win32</Platform>
11+
</ProjectConfiguration>
12+
</ItemGroup>
13+
<PropertyGroup Label="Globals">
14+
<ProjectGuid>{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}</ProjectGuid>
15+
<RootNamespace>foo_input_raw</RootNamespace>
16+
<Keyword>Win32Proj</Keyword>
17+
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
18+
<ProjectName>foo_np_advanced</ProjectName>
19+
</PropertyGroup>
20+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
21+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
22+
<ConfigurationType>DynamicLibrary</ConfigurationType>
23+
<CharacterSet>Unicode</CharacterSet>
24+
<WholeProgramOptimization>true</WholeProgramOptimization>
25+
<PlatformToolset>v141_xp</PlatformToolset>
26+
</PropertyGroup>
27+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
28+
<ConfigurationType>DynamicLibrary</ConfigurationType>
29+
<CharacterSet>Unicode</CharacterSet>
30+
<PlatformToolset>v141_xp</PlatformToolset>
31+
</PropertyGroup>
32+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
33+
<ImportGroup Label="ExtensionSettings">
34+
</ImportGroup>
35+
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
36+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
37+
</ImportGroup>
38+
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
39+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
40+
</ImportGroup>
41+
<PropertyGroup Label="UserMacros" />
42+
<PropertyGroup>
43+
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
44+
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
45+
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
46+
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
47+
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
48+
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
49+
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
50+
</PropertyGroup>
51+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
52+
<IncludePath>$(VC_IncludePath);$(WindowsSdk_71A_IncludePath);..\WTL10_7336\Include</IncludePath>
53+
</PropertyGroup>
54+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
55+
<IncludePath>..\WTL10_7336\Include;$(IncludePath)</IncludePath>
56+
</PropertyGroup>
57+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
58+
<ClCompile>
59+
<Optimization>Disabled</Optimization>
60+
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FOO_INPUT_RAW_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
61+
<MinimalRebuild>true</MinimalRebuild>
62+
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
63+
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
64+
<PrecompiledHeader>Use</PrecompiledHeader>
65+
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
66+
<WarningLevel>Level3</WarningLevel>
67+
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
68+
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
69+
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
70+
</ClCompile>
71+
<Link>
72+
<GenerateDebugInformation>true</GenerateDebugInformation>
73+
<SubSystem>Windows</SubSystem>
74+
<RandomizedBaseAddress>false</RandomizedBaseAddress>
75+
<DataExecutionPrevention>
76+
</DataExecutionPrevention>
77+
<TargetMachine>MachineX86</TargetMachine>
78+
<AdditionalDependencies>../foobar2000_sdk/foobar2000/shared/shared.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
79+
</Link>
80+
</ItemDefinitionGroup>
81+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
82+
<ClCompile>
83+
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FOO_INPUT_RAW_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
84+
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
85+
<PrecompiledHeader>Use</PrecompiledHeader>
86+
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
87+
<WarningLevel>Level3</WarningLevel>
88+
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
89+
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
90+
<AdditionalOptions>/d2notypeopt %(AdditionalOptions)</AdditionalOptions>
91+
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
92+
<BufferSecurityCheck>false</BufferSecurityCheck>
93+
<StringPooling>true</StringPooling>
94+
<OmitFramePointers>true</OmitFramePointers>
95+
</ClCompile>
96+
<Link>
97+
<GenerateDebugInformation>true</GenerateDebugInformation>
98+
<SubSystem>Windows</SubSystem>
99+
<OptimizeReferences>true</OptimizeReferences>
100+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
101+
<RandomizedBaseAddress>false</RandomizedBaseAddress>
102+
<DataExecutionPrevention>
103+
</DataExecutionPrevention>
104+
<TargetMachine>MachineX86</TargetMachine>
105+
<AdditionalDependencies>../foobar2000_sdk/foobar2000/shared/shared.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
106+
</Link>
107+
<ResourceCompile>
108+
<Culture>0x0809</Culture>
109+
</ResourceCompile>
110+
</ItemDefinitionGroup>
111+
<ItemGroup>
112+
<ClCompile Include="initquit.cpp" />
113+
<ClCompile Include="main.cpp" />
114+
<ClCompile Include="PCH.cpp">
115+
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
116+
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
117+
</ClCompile>
118+
<ClCompile Include="preferences.cpp" />
119+
<ClCompile Include="events.cpp" />
120+
<ClCompile Include="writer.cpp" />
121+
</ItemGroup>
122+
<ItemGroup>
123+
<ClInclude Include="events.h" />
124+
<ClInclude Include="prefs_instance.h" />
125+
<ClInclude Include="event_enums.h" />
126+
<ClInclude Include="preferences.h" />
127+
<ClInclude Include="queue.h" />
128+
<ClInclude Include="resource.h" />
129+
<ClInclude Include="stdafx.h" />
130+
<ClInclude Include="writer.h" />
131+
</ItemGroup>
132+
<ItemGroup>
133+
<ResourceCompile Include="foo_npa.rc" />
134+
</ItemGroup>
135+
<ItemGroup>
136+
<ProjectReference Include="..\foobar2000_sdk\pfc\pfc.vcxproj">
137+
<Project>{ebfffb4e-261d-44d3-b89c-957b31a0bf9c}</Project>
138+
</ProjectReference>
139+
<ProjectReference Include="..\foobar2000_sdk\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj">
140+
<Project>{622e8b19-8109-4717-bd4d-9657aa78363e}</Project>
141+
</ProjectReference>
142+
<ProjectReference Include="..\foobar2000_sdk\foobar2000\foobar2000_component_client\foobar2000_component_client.vcxproj">
143+
<Project>{71ad2674-065b-48f5-b8b0-e1f9d3892081}</Project>
144+
</ProjectReference>
145+
<ProjectReference Include="..\foobar2000_sdk\foobar2000\helpers\foobar2000_sdk_helpers.vcxproj">
146+
<Project>{ee47764e-a202-4f85-a767-abdab4aff35f}</Project>
147+
</ProjectReference>
148+
<ProjectReference Include="..\foobar2000_sdk\foobar2000\SDK\foobar2000_SDK.vcxproj">
149+
<Project>{e8091321-d79d-4575-86ef-064ea1a4a20d}</Project>
150+
</ProjectReference>
151+
</ItemGroup>
152+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
153+
<ImportGroup Label="ExtensionTargets">
154+
</ImportGroup>
155+
</Project>

‎foo_npa.vcxproj.filters

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup>
4+
<Filter Include="Source Files">
5+
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
6+
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
7+
</Filter>
8+
<Filter Include="Header Files">
9+
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
10+
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
11+
</Filter>
12+
<Filter Include="Resource Files">
13+
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14+
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
15+
</Filter>
16+
</ItemGroup>
17+
<ItemGroup>
18+
<ClCompile Include="initquit.cpp">
19+
<Filter>Source Files</Filter>
20+
</ClCompile>
21+
<ClCompile Include="main.cpp">
22+
<Filter>Source Files</Filter>
23+
</ClCompile>
24+
<ClCompile Include="PCH.cpp">
25+
<Filter>Source Files</Filter>
26+
</ClCompile>
27+
<ClCompile Include="preferences.cpp">
28+
<Filter>Source Files</Filter>
29+
</ClCompile>
30+
<ClCompile Include="events.cpp">
31+
<Filter>Source Files</Filter>
32+
</ClCompile>
33+
<ClCompile Include="writer.cpp">
34+
<Filter>Source Files</Filter>
35+
</ClCompile>
36+
</ItemGroup>
37+
<ItemGroup>
38+
<ClInclude Include="resource.h">
39+
<Filter>Header Files</Filter>
40+
</ClInclude>
41+
<ClInclude Include="stdafx.h">
42+
<Filter>Header Files</Filter>
43+
</ClInclude>
44+
<ClInclude Include="preferences.h">
45+
<Filter>Header Files</Filter>
46+
</ClInclude>
47+
<ClInclude Include="events.h">
48+
<Filter>Header Files</Filter>
49+
</ClInclude>
50+
<ClInclude Include="event_enums.h">
51+
<Filter>Header Files</Filter>
52+
</ClInclude>
53+
<ClInclude Include="prefs_instance.h">
54+
<Filter>Header Files</Filter>
55+
</ClInclude>
56+
<ClInclude Include="writer.h">
57+
<Filter>Header Files</Filter>
58+
</ClInclude>
59+
<ClInclude Include="queue.h">
60+
<Filter>Header Files</Filter>
61+
</ClInclude>
62+
</ItemGroup>
63+
<ItemGroup>
64+
<ResourceCompile Include="foo_npa.rc">
65+
<Filter>Resource Files</Filter>
66+
</ResourceCompile>
67+
</ItemGroup>
68+
</Project>

‎foo_npa.vcxproj.user

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<RESOURCE_FILE>foo_npa.rc</RESOURCE_FILE>
5+
</PropertyGroup>
6+
</Project>

‎foobar2000_sdk

Submodule foobar2000_sdk added at 1deb62c

‎initquit.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "stdafx.h"
2+
#include "events.h"
3+
#include "writer.h"
4+
#include "preferences.h"
5+
6+
class npa_initquit : public initquit {
7+
public:
8+
void on_init() {
9+
console::print(COMMON_NAME " - plugin initialized");
10+
}
11+
void on_quit() {
12+
IEvents::Destroy();
13+
IWriter::Destroy();
14+
}
15+
private:
16+
};
17+
18+
static initquit_factory_t<npa_initquit> g_npainitquit_factory;
19+
20+
class InitHandler : public init_stage_callback {
21+
public:
22+
void on_init_stage(t_uint32 stage) {
23+
if (stage == init_stages::before_config_read) {
24+
IEvents::Initialize();
25+
IWriter::Initialize();
26+
}
27+
else if (stage == init_stages::after_config_read) {
28+
for (t_size i = 0; i < IConfig::Count(); i++) {
29+
instance_item item = IConfig::Get(i);
30+
IEvents::UpdateInstance(&item);
31+
}
32+
}
33+
}
34+
};
35+
static service_factory_single_t<InitHandler> initHandler;

‎main.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "stdafx.h"
2+
3+
DECLARE_COMPONENT_VERSION(COMMON_NAME,"0.8","Writes different formatted strings to different files.");
4+
VALIDATE_COMPONENT_FILENAME("foo_np_advanced.dll");
5+

‎preferences.cpp

+499
Large diffs are not rendered by default.

‎preferences.h

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
3+
#include "resource.h"
4+
#include "stdafx.h"
5+
#include "events.h"
6+
#include "prefs_instance.h"
7+
8+
9+
class CNPAPreferences : public CDialogImpl<CNPAPreferences>,
10+
public preferences_page_instance,
11+
private CEventsBase {
12+
public:
13+
14+
CNPAPreferences(preferences_page_callback::ptr callback)
15+
: m_callback(callback) {
16+
ResetFlags();
17+
}
18+
19+
enum {
20+
IDD = IDD_NPAPREFERENCES
21+
};
22+
23+
t_uint32 get_state();
24+
void apply();
25+
void reset();
26+
27+
BEGIN_MSG_MAP(CNPAPreferences)
28+
MSG_WM_INITDIALOG(OnInitDialog)
29+
COMMAND_HANDLER_EX(IDC_BOGO1, EN_CHANGE, OnChangeDefault)
30+
COMMAND_HANDLER_EX(IDC_BOGO2, EN_CHANGE, OnChangeDefault)
31+
COMMAND_HANDLER_EX(IDC_FILENAME, EN_CHANGE, OnChangeDefault)
32+
COMMAND_HANDLER_EX(IDC_COMBO1, CBN_EDITCHANGE, OnComboTextChange)
33+
COMMAND_HANDLER_EX(IDC_COMBO1, CBN_SELCHANGE, OnComboSelChange)
34+
COMMAND_HANDLER_EX(IDC_CHECK1, BN_CLICKED, OnChangeDefault)
35+
COMMAND_HANDLER_EX(IDC_DELAY, EN_CHANGE, OnEditDelayChange)
36+
COMMAND_HANDLER_EX(IDC_CHECK2, BN_CLICKED, OnCheckFileClicked)
37+
COMMAND_HANDLER_EX(IDC_CHECK3, BN_CLICKED, OnCheckDelayClicked)
38+
COMMAND_HANDLER_EX(IDC_BUTTON1, BN_CLICKED, OnBnClickedAdd)
39+
COMMAND_HANDLER_EX(IDC_BUTTON2, BN_CLICKED, OnBnClickedRemove)
40+
COMMAND_HANDLER_EX(IDC_BUTTON3, BN_CLICKED, OnBnClickedFileChooser)
41+
COMMAND_HANDLER_EX(IDC_PATTERN, EN_CHANGE, OnEditPatternChange)
42+
MSG_WM_CONTEXTMENU(OnContextMenu)
43+
END_MSG_MAP()
44+
private:
45+
BOOL OnInitDialog(CWindow, LPARAM);
46+
void OnChangeDefault(UINT, int, CWindow);
47+
void OnComboSelChange(UINT, int, CWindow);
48+
void OnComboTextChange(UINT, int, CWindow);
49+
void OnBnClickedAdd(UINT, int, CWindow);
50+
void OnBnClickedRemove(UINT, int, CWindow);
51+
void OnCheckFileClicked(UINT, int, CWindow);
52+
void OnCheckDelayClicked(UINT, int, CWindow);
53+
void OnBnClickedFileChooser(UINT, int, CWindow);
54+
void OnEditPatternChange(UINT, int, CWindow);
55+
void OnEditDelayChange(UINT, int, CWindow);
56+
void OnContextMenu(CWindow wnd, CPoint point);
57+
void PatternPreviewUpdate(uint32_t ev);
58+
bool HasChanged();
59+
void OnChanged();
60+
void PopulateContextList();
61+
void SetControlAvailabilityFile();
62+
void SetControlAvailabilityDelay();
63+
void ResetToUnselectedState();
64+
void ResetToDefault();
65+
66+
void ResetFlags()
67+
{
68+
for (int i = 0; i < EVENT_COUNT; i++) {
69+
event_flags[i] = false;
70+
}
71+
event_flags[EVENT_PLAYBACK_STARTING] = true;
72+
event_flags[EVENT_PLAYBACK_STOP] = true;
73+
event_flags[EVENT_PLAYBACK_PAUSE] = true;
74+
event_flags[EVENT_PLAYBACK_NEW_TRACK] = true;
75+
}
76+
77+
virtual void event_update(uint32_t event) {
78+
PatternPreviewUpdate(event);
79+
}
80+
81+
CComboBox m_ComboBoxInstance;
82+
CCheckBox m_CheckBoxLogMode;
83+
CCheckBox m_CheckBoxWriteToFile;
84+
CCheckBox m_CheckBoxDelay;
85+
CEdit m_EditFilename;
86+
CEdit m_Pattern;
87+
CEdit m_EditDelay;
88+
CButton m_ButtonAddInstance;
89+
CButton m_ButtonRemoveInstance;
90+
CButton m_ButtonEvent;
91+
CButton m_ButtonFileChooser;
92+
CWindow m_DelaySpin;
93+
94+
const preferences_page_callback::ptr m_callback;
95+
titleformat_object::ptr m_script;
96+
static_api_ptr_t<playback_control> m_playback_control;
97+
98+
bool event_flags[EVENT_COUNT];
99+
100+
static const INT idc_delay_hardlimit = 3600000;
101+
};
102+
103+
class IConfig{
104+
public:
105+
106+
static t_size Count()
107+
{
108+
return m_cfg_objlist->get_count();
109+
}
110+
111+
static instance_item Get(t_size i)
112+
{
113+
return m_cfg_objlist->get_item(i);
114+
}
115+
private:
116+
static cfg_objList<instance_item> *m_cfg_objlist;
117+
};

‎prefs_instance.h

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#pragma once
2+
3+
#include "stdafx.h"
4+
#include "event_enums.h"
5+
6+
typedef struct instance_item_s {
7+
pfc::string8 name;
8+
pfc::string8 filename;
9+
pfc::string8 format_string;
10+
bool write_to_file;
11+
bool log_mode;
12+
bool enable_delay;
13+
uint32_t delay = 0;
14+
bool events[EVENT_COUNT];
15+
16+
instance_item_s(const char * p_name, const char * p_filename, const char * p_format_string,
17+
const bool p_write_to_file, const bool p_log_mode, const bool p_enable_delay, const uint32_t p_delay,
18+
const bool(&p_events)[EVENT_COUNT])
19+
: name(p_name), filename(p_filename), format_string(p_format_string), log_mode(p_log_mode),
20+
enable_delay(p_enable_delay), delay(p_delay)
21+
{
22+
for (uint32_t i = 0; i < EVENT_COUNT; i++) {
23+
events[i] = p_events[i];
24+
pfc::string_formatter str;
25+
console::print(str << p_events[i]);
26+
}
27+
}
28+
instance_item_s(const char * p_name, const char * p_filename, const char * p_format_string, const bool p_write_to_file,
29+
const bool p_log_mode, const bool p_enable_delay, const uint32_t p_delay, const std::initializer_list <uint32_t> p_events)
30+
: name(p_name), filename(p_filename), format_string(p_format_string), log_mode(p_log_mode),
31+
enable_delay(p_enable_delay), delay(p_delay), write_to_file(p_write_to_file)
32+
{
33+
reset_events();
34+
35+
for (auto f : p_events) {
36+
if (f >= EVENT_COUNT) {
37+
pfc::string_formatter str;
38+
console::print(str << "WARNING: got invalid event during 'instance_item_s' initialization: " << f);
39+
}
40+
else {
41+
events[f] = true;
42+
}
43+
}
44+
}
45+
instance_item_s(const struct instance_item_s *data) {
46+
memcpy((void*)this, (const void *)data, sizeof(struct instance_item_s));
47+
}
48+
instance_item_s() {
49+
reset_events();
50+
}
51+
void reset_events()
52+
{
53+
for (uint32_t i = 0; i < EVENT_COUNT; i++) {
54+
events[i] = false;
55+
}
56+
events[EVENT_PLAYBACK_STOP] = true;
57+
events[EVENT_PLAYBACK_PAUSE] = true;
58+
events[EVENT_PLAYBACK_NEW_TRACK] = true;
59+
}
60+
/*
61+
bool operator!=(instance_item &other) {
62+
return bool(name != other.name || value != other.value || contextmenu != other.contextmenu);
63+
}
64+
*/
65+
} instance_item;
66+
67+
68+
FB2K_STREAM_READER_OVERLOAD(instance_item) {
69+
stream >> value.name >> value.filename >> value.format_string >>
70+
value.write_to_file >> value.log_mode >> value.enable_delay >>
71+
value.delay >> value.events;
72+
return stream;
73+
}
74+
75+
FB2K_STREAM_WRITER_OVERLOAD(instance_item) {
76+
stream << value.name << value.filename << value.format_string <<
77+
value.write_to_file << value.log_mode << value.enable_delay <<
78+
value.delay << value.events;
79+
return stream;
80+
}

‎queue.h

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#pragma once
2+
3+
#include <queue>
4+
#include <mutex>
5+
#include <map>
6+
#include <condition_variable>
7+
8+
// producer-consumer queue taken from https://github.com/juanchopanza/cppblog/tree/master/Concurrency/Queue
9+
10+
template <typename T>
11+
class Queue
12+
{
13+
public:
14+
15+
T pop()
16+
{
17+
std::unique_lock<std::mutex> mlock(mutex_);
18+
while (queue_.empty())
19+
{
20+
cond_.wait(mlock);
21+
}
22+
auto val = queue_.front();
23+
queue_.pop();
24+
return val;
25+
}
26+
27+
void pop(T& item)
28+
{
29+
std::unique_lock<std::mutex> mlock(mutex_);
30+
while (queue_.empty())
31+
{
32+
cond_.wait(mlock);
33+
}
34+
item = queue_.front();
35+
queue_.pop();
36+
}
37+
38+
void push(const T& item, bool lock = false)
39+
{
40+
std::unique_lock<std::mutex> mlock(mutex_);
41+
42+
if (locked) {
43+
return;
44+
}
45+
queue_.push(item);
46+
if (lock) {
47+
locked = true;
48+
}
49+
mlock.unlock();
50+
cond_.notify_one();
51+
}
52+
53+
Queue() = default;
54+
Queue(const Queue&) = delete; // disable copying
55+
Queue& operator=(const Queue&) = delete; // disable assignment
56+
57+
bool locked = false;
58+
59+
private:
60+
std::queue<T> queue_;
61+
std::mutex mutex_;
62+
std::condition_variable cond_;
63+
};

‎resource.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//{{NO_DEPENDENCIES}}
2+
// Microsoft Visual C++ generated include file.
3+
// Used by foo_npa.rc
4+
//
5+
#define IDD_NPAPREFERENCES 148
6+
#define IDC_BOGO1 1001
7+
#define IDC_BOGO2 1002
8+
#define IDC_LIST1 1004
9+
#define IDC_COMBO1 1005
10+
#define IDC_EDIT1 1007
11+
#define IDC_FILENAME 1007
12+
#define IDC_CHECK1 1008
13+
#define IDC_BUTTON1 1009
14+
#define IDC_BUTTON2 1010
15+
#define IDC_CHECK2 1011
16+
#define IDC_SLIDER1 1012
17+
#define IDC_PATTERN 1012
18+
#define IDC_PREVIEW 1013
19+
#define IDC_CONTEXTMENU 1014
20+
#define IDC_BUTTON3 1015
21+
#define IDC_CHECK3 1016
22+
#define IDC_DELAY 1018
23+
#define IDC_SPIN2 1019
24+
#define IDC_SPIN1 1019
25+
26+
// Next default values for new objects
27+
//
28+
#ifdef APSTUDIO_INVOKED
29+
#ifndef APSTUDIO_READONLY_SYMBOLS
30+
#define _APS_NEXT_RESOURCE_VALUE 106
31+
#define _APS_NEXT_COMMAND_VALUE 40001
32+
#define _APS_NEXT_CONTROL_VALUE 1020
33+
#define _APS_NEXT_SYMED_VALUE 101
34+
#endif
35+
#endif

‎stdafx.h

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
#include "../foobar2000_sdk/foobar2000/ATLHelpers/ATLHelpersLean.h"
3+
#include "../foobar2000_sdk/foobar2000/helpers/helpers.h"
4+
#include "../foobar2000_sdk/foobar2000/ATLHelpers/WTL-PP.h"
5+
#include "../foobar2000_sdk/foobar2000/ATLHelpers/misc.h"
6+
7+
8+
#define COMMON_NAME "Now Playing Advanced"

‎writer.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include "stdafx.h"
2+
#include "writer.h"
3+
4+
#include <iostream>
5+
#include <fstream>
6+
#include <thread>
7+
#include <chrono>
8+
#include <ratio>
9+
#include <ctime>
10+
11+
using namespace std;
12+
using namespace std::chrono;
13+
14+
std::condition_variable CWriter::cv_quit;
15+
std::mutex CWriter::cvq_mutex;
16+
std::atomic<int> CWriter::pending_destroy{ 0 };
17+
18+
CWriter *IWriter::m_Writer = nullptr;
19+
20+
void CWriter::worker()
21+
{
22+
console::info("NPA: writer thread starting");
23+
while (true)
24+
{
25+
write_job j = q.pop();
26+
if (j.flags & F_WRITER_ABORT) {
27+
break;
28+
}
29+
//console::info("NPA: writer got a job");
30+
Write(&j);
31+
}
32+
console::info("NPA: writer thread exiting");
33+
}
34+
35+
void CWriter::Write(write_job *j) {
36+
try {
37+
ofstream fs;
38+
unsigned int flags = ios::out;
39+
if (j->flags & F_WRITER_APPEND) {
40+
flags |= ios::app;
41+
}
42+
else {
43+
flags |= ios::trunc;
44+
}
45+
fs.open(j->file, flags);
46+
fs << j->data;
47+
fs.close();
48+
}
49+
catch (std::exception const & e) {
50+
console::complain("NPA: write failed", e);
51+
}
52+
}
53+
54+
void CWriter::QueueWriteAsync(const write_job *j, long long timeout ) {
55+
std::thread([](const write_job j, CWriter *c, long long t) {
56+
std::unique_lock<std::mutex> lk(CWriter::cvq_mutex);
57+
58+
if (CWriter::pending_destroy == 0) {
59+
CWriter::cv_quit.wait_for(lk, std::chrono::milliseconds(t),
60+
[] {
61+
return CWriter::pending_destroy == 1;
62+
}
63+
);
64+
}
65+
66+
c->q.push(j);
67+
}, *j, this, timeout).detach();
68+
69+
}

‎writer.h

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#pragma once
2+
3+
#include "stdafx.h"
4+
#include "events.h"
5+
#include "queue.h"
6+
7+
#include <future>
8+
9+
#define F_WRITER_APPEND (uint32_t) 0x00000001
10+
#define F_WRITER_ABORT (uint32_t) 0x00000002
11+
12+
typedef struct write_job_s {
13+
pfc::string8 file;
14+
pfc::string8 data;
15+
uint32_t flags = 0;
16+
17+
write_job_s(pfc::string8 p_file, pfc::string8 p_data, uint32_t p_flags) :
18+
file(p_file), data(p_data), flags(p_flags) {}
19+
write_job_s(pfc::string8 p_file, pfc::string8 p_data) :
20+
file(p_file), data(p_data) {}
21+
write_job_s(uint32_t p_flags) : flags(p_flags) {}
22+
write_job_s() {}
23+
24+
} write_job;
25+
26+
27+
28+
class CWriter {
29+
public:
30+
CWriter() {
31+
t = new std::thread(std::bind(&CWriter::worker, this));
32+
}
33+
~CWriter()
34+
{
35+
pending_destroy = 1;
36+
cv_quit.notify_all();
37+
write_job j(F_WRITER_ABORT);
38+
q.push(j, true);
39+
t->join();
40+
}
41+
42+
void QueueWrite(const write_job *j) { q.push(*j); }
43+
void QueueWriteAsync(const write_job *j, long long timeout);
44+
45+
private:
46+
void worker();
47+
void Write(write_job *j);
48+
49+
std::thread *t;
50+
Queue<write_job> q;
51+
52+
static std::condition_variable cv_quit;
53+
static std::mutex cvq_mutex;
54+
static std::atomic<int> pending_destroy;
55+
56+
};
57+
58+
class IWriter {
59+
public:
60+
static void Initialize() {
61+
if (m_Writer == nullptr) {
62+
m_Writer = new CWriter();
63+
}
64+
}
65+
static void Destroy() {
66+
if (m_Writer != nullptr) {
67+
delete m_Writer;
68+
}
69+
}
70+
71+
static void Write(const write_job *j) {
72+
m_Writer->QueueWrite(j);
73+
}
74+
75+
static void WriteAsync(const write_job *j, long long timeout = 0) {
76+
m_Writer->QueueWriteAsync(j, timeout);
77+
}
78+
private:
79+
static CWriter *m_Writer;
80+
};

0 commit comments

Comments
 (0)
Please sign in to comment.