Browse code

* Added more interpolation methods to in_ncsf. * Cleaned up a little of the code in the Interpolate function in in_ncsf. * Made it so changes in the config can apply to a running song, depending on the player. * Slight optimization of in_ncsf's interpolation so it doesn't have as much std::vector accessing. * Stopped trying to use the slope of the points to determine points outside the sample's range, hopefully will stop some of the clipping.

Naram Qashat authored on 2013/04/10 14:39:59
Showing 6 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Channel structures
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-02
4
+ * Last modification on 2013-04-10
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -586,66 +586,114 @@ int32_t Channel::Interpolate()
586 586
 	ratio -= static_cast<int32_t>(ratio);
587 587
 
588 588
 	uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
589
-	const auto &data = &this->reg.source->data[loc];
589
+	const auto &data = &this->reg.source->dataptr[loc];
590 590
 	int32_t a = data[0], b;
591 591
 	if (loc + 1 < this->reg.totalLength)
592 592
 		b = data[1];
593 593
 	else
594
-	{
595
-		if (loc)
596
-		{
597
-			int32_t am1 = data[-1];
598
-			b = 2 * a - am1;
599
-		}
600
-		else
601
-			b = a;
602
-	}
594
+		b = a;
603 595
 
604
-	if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL)
596
+	double c0, c1, c2, c3, c4, c5;
597
+	if (this->ply->interpolation > INTERPOLATION_2POINTOPTIMAL)
605 598
 	{
606 599
 		int32_t c, z;
607 600
 		if (loc + 2 < this->reg.totalLength)
608 601
 			c = data[2];
609 602
 		else
610
-		{
611
-			if (loc)
612
-			{
613
-				int32_t am1 = data[-1];
614
-				c = 3 * a - 2 * am1;
615
-			}
616
-			else
617
-				c = a;
618
-		}
603
+			c = a;
619 604
 		if (loc)
620 605
 			z = data[-1];
621 606
 		else
607
+			z = a;
608
+
609
+		if (this->ply->interpolation > INTERPOLATION_4POINTOPTIMAL)
622 610
 		{
623
-			if (loc + 1 < this->reg.totalLength)
611
+			int32_t d, y;
612
+			if (loc + 3 < this->reg.totalLength)
613
+				d = data[3];
614
+			else
615
+				d = a;
616
+			if (loc > 1)
617
+				y = data[-2];
618
+			else
619
+				y = a;
620
+
621
+			if (this->ply->interpolation == INTERPOLATION_6POINTHERMITE)
622
+			{
623
+				double eighthym2 = 0.125 * y;
624
+				double eleventwentyfourthy2 = 11 / 24.0 * c;
625
+				double twelfthy3 = 1 / 12.0 * d;
626
+				c0 = a;
627
+				c1 = 1 / 12.0 * (y - c) + 2 / 3.0 * (b - z);
628
+				c2 = 13 / 12.0 * z - 25 / 12.0 * a + 1.5 * b - eleventwentyfourthy2 + twelfthy3 - eighthym2;
629
+				c3 = 5 / 12.0 * a - 7 / 12.0 * b + 7 / 24.0 * c - 1 / 24.0 * (y + z + d);
630
+				c4 = eighthym2 - 7 / 12.0 * z + 13 / 12.0 * a - b + eleventwentyfourthy2 - twelfthy3;
631
+				c5 = 1 / 24.0 * (d - y) + 5 / 24.0 * (z - c) + 5 / 12.0 * (b - a);
632
+				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
633
+			}
634
+			else if (this->ply->interpolation == INTERPOLATION_6POINTLAGRANGE)
635
+			{
636
+				float ym1py1 = z + b;
637
+				float twentyfourthym2py2 = 1 / 24.0 * (y + c);
638
+				float c0 = a;
639
+				float c1 = 1 / 20.0 * y - 0.5 * z - 1 / 3.0 * a + b - 0.25 * c + 1 / 30.0 * d;
640
+				float c2 = 2 / 3.0 * ym1py1 - 1.25 * a - twentyfourthym2py2;
641
+				float c3 = 5 / 12.0 * a - 7 / 12.0 * b + 7 / 24.0 * c - 1 / 24.0 * (y + z + d);
642
+				float c4 = 0.25 * a - 1 / 6.0 * ym1py1 + twentyfourthym2py2;
643
+				float c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a);
644
+				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
645
+			}
646
+			else if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE)
624 647
 			{
625
-				int32_t ap1 = data[1];
626
-				z = 2 * a - ap1;
648
+				double ym2py2 = y + c, ym1py1 = z + b;
649
+				double y2mym2 = c - y, y1mym1 = b - z;
650
+				double sixthym1py1 = 1 / 6.0 * ym1py1;
651
+				c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * a;
652
+				c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1;
653
+				c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * a;
654
+				c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1;
655
+				c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * a;
656
+				c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a);
657
+				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
627 658
 			}
628 659
 			else
629
-				z = a;
660
+			{
661
+				ratio -= 0.5;
662
+				double even1 = b + a, odd1 = b - a;
663
+				double even2 = c + z, odd2 = c - z;
664
+				double even3 = d + y, odd3 = d - y;
665
+				c0 = even1 * 0.41809989254549901 + even2 * 0.08049339946273310 + even3 * 0.00140670799165932;
666
+				c1 = odd1 * 0.32767596257424964 + odd2 * 0.20978189376640677 + odd3 * 0.00859567104974701;
667
+				c2 = even1 * -0.206944618112960001 + even2 * 0.18541689550861262 + even3 * 0.02152772260740132;
668
+				c3 = odd1 * -0.21686095413034051 + odd2 * 0.02509557922091643 + odd3 * 0.02831484751363800;
669
+				c4 = even1 * 0.04163046817137675 + even2 * -0.06244556931623735 + even3 * 0.02081510113314315;
670
+				c5 = odd1 * 0.07990500783668089 + odd2 * -0.03994519162531633 + odd3 * 0.00798609327859495;
671
+				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
672
+			}
630 673
 		}
631
-
632
-		double c0, c1, c2, c3;
633
-
634
-		if (this->ply->interpolation == INTERPOLATION_BSPLINE)
674
+		else if (this->ply->interpolation == INTERPOLATION_4POINTHERMITE)
635 675
 		{
636
-			double zpb = z + b;
637
-			c0 = 1 / 6.0 * zpb + 2 / 3.0 * a;
676
+			c0 = a;
638 677
 			c1 = 0.5 * (b - z);
639
-			c2 = 0.5 * zpb - a;
640
-			c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z);
678
+			c2 = z - 2.5 * a + 2 * b - 0.5 * c;
679
+			c3 = 0.5 * (c - z) + 1.5 * (a - b);
641 680
 			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
642 681
 		}
643
-		else if (this->ply->interpolation == INTERPOLATION_HERMITE)
682
+		else if (this->ply->interpolation == INTERPOLATION_4POINTLAGRANGE)
644 683
 		{
645
-			c0 = a;
684
+			float c0 = a;
685
+			float c1 = b - 1 / 3.0 * z - 0.5 * a - 1 / 6.0 * c;
686
+			float c2 = 0.5 * (z + b) - a;
687
+			float c3 = 1 / 6.0 * (c - z) + 0.5 * (a - b);
688
+			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
689
+		}
690
+		else if (this->ply->interpolation == INTERPOLATION_4POINTBSPLINE)
691
+		{
692
+			double zpb = z + b;
693
+			c0 = 1 / 6.0 * zpb + 2 / 3.0 * a;
646 694
 			c1 = 0.5 * (b - z);
647
-			c2 = z - 2.5 * a + 2 * b - 0.5 * c;
648
-			c3 = 0.5 * (c - z) + 1.5 * (a - b);
695
+			c2 = 0.5 * zpb - a;
696
+			c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z);
649 697
 			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
650 698
 		}
651 699
 		else
... ...
@@ -653,14 +701,24 @@ int32_t Channel::Interpolate()
653 701
 			ratio -= 0.5;
654 702
 			double even1 = b + a, odd1 = b - a;
655 703
 			double even2 = c + z, odd2 = c - z;
656
-			c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309;
657
-			c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288;
658
-			c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131;
659
-			c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800;
660
-			double c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478;
704
+			c0 = even1 * 0.46822774170144532 + even2 * 0.03177225758005808;
705
+			c1 = odd1 * 0.55890365706150436 + odd2 * 0.14703258836343669;
706
+			c2 = even1 * -0.250153411893796031 + even2 * 0.25015343462990891;
707
+			c3 = odd1 * -0.49800710906733769 + odd2 * 0.16600005174304033;
708
+			c4 = even1 * 0.00064264050033187 + even2 * -0.00064273459469381;
661 709
 			return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
662 710
 		}
663 711
 	}
712
+	else if (this->ply->interpolation == INTERPOLATION_2POINTOPTIMAL)
713
+	{
714
+		ratio -= 0.5;
715
+		double even1 = b + a, odd1 = b - a;
716
+		c0 = even1 * 0.50001096675880796;
717
+		c1 = odd1 * 1.03585606328743830;
718
+		c2 = even1 * -0.000131601105693441;
719
+		c3 = odd1 * -0.38606621963374965;
720
+		return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
721
+	}
664 722
 	else if (this->ply->interpolation == INTERPOLATION_COSINE)
665 723
 	{
666 724
 		double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5;
... ...
@@ -678,7 +736,7 @@ int32_t Channel::GenerateSample()
678 736
 	if (this->reg.format != 3)
679 737
 	{
680 738
 		if (this->ply->interpolation == INTERPOLATION_NONE)
681
-			return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)];
739
+			return this->reg.source->dataptr[static_cast<uint32_t>(this->reg.samplePosition)];
682 740
 		else
683 741
 			return this->Interpolate();
684 742
 	}
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - SDAT SWAV (Waveform/Sample) structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-25
4
+ * Last modification on 2013-04-10
5 5
  *
6 6
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
7 7
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
... ...
@@ -28,7 +28,7 @@ static int ima_step_table[] =
28 28
 	15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
29 29
 };
30 30
 
31
-SWAV::SWAV() : waveType(0), loop(0), sampleRate(0), time(0), loopOffset(0), nonLoopLength(0), data()
31
+SWAV::SWAV() : waveType(0), loop(0), sampleRate(0), time(0), loopOffset(0), nonLoopLength(0), data(), dataptr(nullptr)
32 32
 {
33 33
 }
34 34
 
... ...
@@ -119,4 +119,5 @@ void SWAV::Read(PseudoFile &file)
119 119
 		this->loopOffset *= 8;
120 120
 		this->nonLoopLength *= 8;
121 121
 	}
122
+	this->dataptr = &this->data[0];
122 123
 }
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - SDAT SWAV (Waveform/Sample) structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-21
4
+ * Last modification on 2013-04-10
5 5
  *
6 6
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
7 7
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
... ...
@@ -21,6 +21,7 @@ struct SWAV
21 21
 	uint32_t loopOffset;
22 22
 	uint32_t nonLoopLength;
23 23
 	std::vector<int16_t> data;
24
+	const int16_t *dataptr;
24 25
 
25 26
 	SWAV();
26 27
 
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Constants/Macros
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-02
4
+ * Last modification on 2013-04-10
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -51,6 +51,20 @@ const uint32_t SOUND_FORMAT_PSG = 3 << 29;
51 51
 inline uint32_t SOUND_FORMAT(int n) { return n << 29; }
52 52
 const uint32_t SCHANNEL_ENABLE = BIT(31);
53 53
 
54
-enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE, INTERPOLATION_BSPLINE, INTERPOLATION_HERMITE, INTERPOLATION_OPTIMAL };
54
+enum Interpolation
55
+{
56
+	INTERPOLATION_NONE,
57
+	INTERPOLATION_LINEAR,
58
+	INTERPOLATION_COSINE,
59
+	INTERPOLATION_2POINTOPTIMAL,
60
+	INTERPOLATION_4POINTHERMITE,
61
+	INTERPOLATION_4POINTLAGRANGE,
62
+	INTERPOLATION_4POINTBSPLINE,
63
+	INTERPOLATION_4POINTOPTIMAL,
64
+	INTERPOLATION_6POINTHERMITE,
65
+	INTERPOLATION_6POINTLAGRANGE,
66
+	INTERPOLATION_6POINTBSPLINE,
67
+	INTERPOLATION_6POINTOPTIMAL
68
+};
55 69
 
56 70
 #endif
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF configuration
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-02
4
+ * Last modification on 2013-04-10
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -42,8 +42,8 @@ public:
42 42
 
43 43
 unsigned XSFConfig::initSampleRate = 44100;
44 44
 std::wstring XSFConfig::commonName = L"NCSF Decoder";
45
-std::wstring XSFConfig::versionNumber = L"1.2";
46
-unsigned XSFConfig_NCSF::initInterpolation = 5;
45
+std::wstring XSFConfig::versionNumber = L"1.3";
46
+unsigned XSFConfig_NCSF::initInterpolation = 7;
47 47
 std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
48 48
 
49 49
 XSFConfig *XSFConfig::Create()
... ...
@@ -82,7 +82,7 @@ void XSFConfig_NCSF::SaveSpecificConfig()
82 82
 void XSFConfig_NCSF::GenerateSpecificDialogs()
83 83
 {
84 84
 	this->configDialog.AddLabelControl(DialogLabelBuilder(L"Interpolation").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
85
-	this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(90, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
85
+	this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(110, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
86 86
 		IsDropDownList().WithTabStop());
87 87
 	this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
88 88
 	this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).
... ...
@@ -95,12 +95,18 @@ INT_PTR CALLBACK XSFConfig_NCSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARA
95 95
 	{
96 96
 		case WM_INITDIALOG:
97 97
 			// Interpolation
98
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"No Interpolation"));
99
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Interpolation"));
100
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine Interpolation"));
101
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"B-spline Interpolation"));
102
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Interpolation"));
103
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Optimal Interpolation"));
98
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"None"));
99
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear"));
100
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine"));
101
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"2-point, 3rd-order Optimal 16x"));
102
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"4-point, 3rd-order Hermite"));
103
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"4-point, 3rd-order Lagrange"));
104
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"4-point, 3rd-order B-spline"));
105
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"4-point, 4th-order Optimal 16x"));
106
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order Hermite"));
107
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order Lagrange"));
108
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order B-spline"));
109
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order Optimal 16x"));
104 110
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
105 111
 			// Mutes
106 112
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
... ...
@@ -131,13 +137,11 @@ void XSFConfig_NCSF::SaveSpecificConfigDialog(HWND hwndDlg)
131 137
 		this->mutes[x] = !!SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_GETSEL, x, 0);
132 138
 }
133 139
 
134
-void XSFConfig_NCSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
140
+void XSFConfig_NCSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool)
135 141
 {
136 142
 	XSFPlayer_NCSF *NCSFPlayer = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
137
-	if (preLoad)
138
-		NCSFPlayer->SetInterpolation(this->interpolation);
139
-	else
140
-		NCSFPlayer->SetMutes(this->mutes);
143
+	NCSFPlayer->SetInterpolation(this->interpolation);
144
+	NCSFPlayer->SetMutes(this->mutes);
141 145
 }
142 146
 
143 147
 void XSFConfig_NCSF::About(HWND parent)
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Winamp plugin
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-02
4
+ * Last modification on 2013-04-10
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -73,6 +73,8 @@ DWORD WINAPI playThread(void *b)
73 73
 void config(HWND hwndParent)
74 74
 {
75 75
 	xSFConfig->CallConfigDialog(inMod.hDllInstance, hwndParent);
76
+	if (xSFPlayer)
77
+		xSFConfig->CopyConfigToMemory(xSFPlayer, false);
76 78
 }
77 79
 
78 80
 void about(HWND hwndParent)