Basic application code

This commit is contained in:
Pinales, Omar 2025-07-09 21:35:58 -07:00
parent 28a7137322
commit b4f2370d5f
19 changed files with 1593 additions and 0 deletions

25
Projector.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36202.13 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Projector", "Projector\Projector.csproj", "{B61419F5-CBDA-4DEF-B7A9-30DD5BCC467F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B61419F5-CBDA-4DEF-B7A9-30DD5BCC467F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B61419F5-CBDA-4DEF-B7A9-30DD5BCC467F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B61419F5-CBDA-4DEF-B7A9-30DD5BCC467F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B61419F5-CBDA-4DEF-B7A9-30DD5BCC467F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {61C9AAF3-56EB-47A0-AB37-C40A3F4851E9}
EndGlobalSection
EndGlobal

15
Projector/App.config Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="Projector.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<Projector.Properties.Settings>
<setting name="Lyrics" serializeAs="String">
<value />
</setting>
</Projector.Properties.Settings>
</applicationSettings>
</configuration>

View File

@ -0,0 +1,84 @@
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Projector
{
// Custom ISampleProvider to mix 4 channels to stereo
public class FourChannelToStereoSampleProvider : ISampleProvider
{
private readonly ISampleProvider _source;
private float offTransition = 1f;
private float _voiceVolume = 0f;
private bool goingOff = false;
public WaveFormat WaveFormat { get; }
public void SetOff()
{
goingOff = true;
}
public bool IsOff => goingOff && offTransition == 0f;
public float VoiceVolume
{
get
{
return _voiceVolume;
}
set
{
_voiceVolume = Math.Clamp(value, 0f, 1f);
}
}
public FourChannelToStereoSampleProvider(ISampleProvider source)
{
if (source.WaveFormat.Channels != 4)
throw new ArgumentException("Source must have 4 channels");
if (source.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
throw new ArgumentException("Source must be IEEE float format");
_source = source;
WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(source.WaveFormat.SampleRate, 2);
}
public int Read(float[] buffer, int offset, int count)
{
int samplesNeeded = (count / 2) * 4;
float[] sourceBuffer = new float[samplesNeeded];
int samplesRead = _source.Read(sourceBuffer, 0, samplesNeeded);
int stereoSamples = samplesRead / 4 * 2;
int outIndex = offset;
if (goingOff && offTransition > 0f)
{
offTransition -= 0.2f;
if (offTransition <= 0f)
{
offTransition = 0f;
}
}
float musicVolume = 1f - VoiceVolume;
float voiceVolume = VoiceVolume;
for (int i = 0; i < samplesRead; i += 4)
{
// Mix channel 0 and 2 to left, 1 and 3 to right
float left = (sourceBuffer[i] * musicVolume) + (sourceBuffer[i + 2] * voiceVolume);
float right = (sourceBuffer[i + 1] * musicVolume) + (sourceBuffer[i + 3] * voiceVolume);
buffer[outIndex++] = left * offTransition;
buffer[outIndex++] = right * offTransition;
}
return stereoSamples;
}
}
}

109
Projector/FrmMain.Designer.cs generated Normal file
View File

@ -0,0 +1,109 @@
namespace Projector
{
partial class FrmMain
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
DgvHymns = new DataGridView();
CnHymn = new DataGridViewTextBoxColumn();
CnPlay = new DataGridViewButtonColumn();
TbFilter = new TextBox();
((System.ComponentModel.ISupportInitialize)DgvHymns).BeginInit();
SuspendLayout();
//
// DgvHymns
//
DgvHymns.AllowUserToAddRows = false;
DgvHymns.AllowUserToDeleteRows = false;
DgvHymns.AllowUserToResizeColumns = false;
DgvHymns.AllowUserToResizeRows = false;
DgvHymns.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
DgvHymns.Columns.AddRange(new DataGridViewColumn[] { CnHymn, CnPlay });
DgvHymns.Dock = DockStyle.Fill;
DgvHymns.Location = new Point(0, 38);
DgvHymns.Margin = new Padding(5);
DgvHymns.MultiSelect = false;
DgvHymns.Name = "DgvHymns";
DgvHymns.ReadOnly = true;
DgvHymns.RowHeadersVisible = false;
DgvHymns.RowHeadersWidth = 51;
DgvHymns.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
DgvHymns.Size = new Size(665, 547);
DgvHymns.TabIndex = 7;
DgvHymns.CellPainting += DgvHymns_CellPainting;
//
// CnHymn
//
CnHymn.HeaderText = "Hymn";
CnHymn.MinimumWidth = 6;
CnHymn.Name = "CnHymn";
CnHymn.ReadOnly = true;
CnHymn.Width = 600;
//
// CnPlay
//
CnPlay.HeaderText = "P";
CnPlay.MinimumWidth = 6;
CnPlay.Name = "CnPlay";
CnPlay.ReadOnly = true;
CnPlay.Width = 32;
//
// TbFilter
//
TbFilter.BorderStyle = BorderStyle.FixedSingle;
TbFilter.Dock = DockStyle.Top;
TbFilter.Location = new Point(0, 0);
TbFilter.Margin = new Padding(5);
TbFilter.Name = "TbFilter";
TbFilter.Size = new Size(665, 38);
TbFilter.TabIndex = 6;
TbFilter.TextChanged += TbFilter_TextChanged;
//
// FrmMain
//
AutoScaleDimensions = new SizeF(13F, 31F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(665, 585);
Controls.Add(DgvHymns);
Controls.Add(TbFilter);
Font = new Font("Segoe UI", 13.8F, FontStyle.Regular, GraphicsUnit.Point, 0);
Margin = new Padding(5);
Name = "FrmMain";
Text = "SDA Church Projector";
Load += FrmMain_Load;
((System.ComponentModel.ISupportInitialize)DgvHymns).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private TextBox TbFilter;
private DataGridView DgvHymns;
private DataGridViewTextBoxColumn CnHymn;
private DataGridViewButtonColumn CnPlay;
}
}

288
Projector/FrmMain.cs Normal file
View File

@ -0,0 +1,288 @@
using NAudio.Wave;
using System;
using System.Windows.Forms;
using YoutubeExplode;
using YoutubeExplode.Videos;
using YoutubeExplode.Videos.Streams;
namespace Projector
{
public partial class FrmMain : Form
{
private Video? _video = null;
private StreamManifest? _streamManifest = null;
FourChannelToStereoSampleProvider? mixer = null;
string musicPath = "C:\\Hymnal\\Music";
string editsPath = "C:\\Hymnal\\Edits";
string LyricsPath = "C:\\Hymnal\\Lyrics";
FrmPreview frmPreview = new FrmPreview();
public FrmMain()
{
InitializeComponent();
DgvHymns.CellContentClick += DgvHymns_CellContentClick;
}
private void FrmMain_Load(object sender, EventArgs e)
{
FrmMain_Resize(null, null);
if (!System.IO.Directory.Exists(musicPath))
{
MessageBox.Show("Hymns directory does not exist: " + musicPath);
return;
}
var hymns = System.IO.Directory.GetFiles(musicPath, "*.m4a");
foreach (var hymn in hymns)
{
var fileName = System.IO.Path.GetFileNameWithoutExtension(hymn);
DgvHymns.Rows.Add(fileName, "");
}
}
private void DgvHymns_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (DgvHymns.Columns[e.ColumnIndex].Name == "CnPlay" && e.RowIndex >= 0)
{
e.Paint(e.CellBounds, DataGridViewPaintParts.All);
var icon = Properties.Resources.Play; // Assuming you have a play icon in resources
var iconRect = new Rectangle(e.CellBounds.X + 2, e.CellBounds.Y + 2, e.CellBounds.Height - 4, e.CellBounds.Height - 4);
e.Graphics?.DrawImage(icon, iconRect);
e.Handled = true; // Prevent default painting
}
}
// 3. Handle the Play button click:
private void DgvHymns_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Check if PlayButton column and not header row
if (e.RowIndex >= 0 && DgvHymns.Columns[e.ColumnIndex].Name == "CnPlay")
{
var hymnName = DgvHymns.Rows[e.RowIndex].Cells["CnHymn"].Value?.ToString();
if (!string.IsNullOrEmpty(hymnName))
{
PlayHymn(hymnName);
}
}
}
private void PlayHymn(string name)
{
string audioFilePath = Path.Combine(editsPath, name + ".m4a");
if (!File.Exists(audioFilePath))
{
audioFilePath = Path.Combine(musicPath, name + ".m4a");
}
string number = name.Substring(0, 3).Trim(); // Extract the first 3 characters
try
{
// Open the audio file
var reader = new MediaFoundationReader(audioFilePath);
// Check for 4 channels
if (reader.WaveFormat.Channels != 4)
{
MessageBox.Show("Audio file does not have 4 channels.");
reader.Dispose();
return;
}
// Create a custom sample provider to mix channels 0+2 to left, 1+3 to right
mixer = new FourChannelToStereoSampleProvider(reader.ToSampleProvider());
// Search the folder in LyricsPath that starts with the hymn number
string lyricsFilePath = Directory.GetDirectories(LyricsPath).ToList().ConvertAll(d => Path.GetFileName(d))
.FirstOrDefault(dir => dir.StartsWith(number, StringComparison.OrdinalIgnoreCase));
// Get all the jpg files in the lyrics folder
if (lyricsFilePath != null)
{
string lyricsFolderPath = Path.Combine(LyricsPath, lyricsFilePath);
var jpgFiles = Directory.GetFiles(lyricsFolderPath, "*.jpg");
// Order the jpg files by name
Array.Sort(jpgFiles, StringComparer.OrdinalIgnoreCase);
// Display the first jpg file in a PictureBox or similar control
if (jpgFiles.Length > 0)
{
// Assuming you have a PictureBox named pictureBoxLyrics
frmPreview.SetImages(jpgFiles, mixer);
}
}
var waveOut = new WaveOutEvent();
waveOut.Init(mixer);
waveOut.Play();
frmPreview.ShowDialog(this);
TbFilter.SelectAll();
TbFilter.Focus();
// Crate a task to handle the transition
Task.Run(() =>
{
mixer.SetOff();
while (!mixer.IsOff)
{
Thread.Sleep(100); // Check every 100ms
}
waveOut.Stop();
});
// Optionally, store waveOut and reader as fields to stop/dispose later
}
catch (Exception ex)
{
MessageBox.Show("Error playing audio: " + ex.Message);
}
}
private void TbFilter_TextChanged(object sender, EventArgs e)
{
// Filter the DataGridView based on the text in the filter TextBox
string filterText = TbFilter.Text.ToLower();
foreach (DataGridViewRow row in DgvHymns.Rows)
{
if (row.Cells["CnHymn"].Value != null)
{
row.Visible = row.Cells["CnHymn"].Value.ToString().ToLower().Contains(filterText);
}
}
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
int firstVisibleRowIndex = visibleRows[0].Index;
DgvHymns.Rows[firstVisibleRowIndex].Selected = true;
DgvHymns.FirstDisplayedScrollingRowIndex = firstVisibleRowIndex;
}
}
private void FrmMain_Resize(object sender, EventArgs e)
{
DgvHymns.Columns["CnHymn"].Width = Width - 80;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Down)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
int selectedRowIndex = visibleRows.FindIndex(row => row.Selected);
selectedRowIndex++;
if (selectedRowIndex < visibleRows.Count)
{
visibleRows[selectedRowIndex].Selected = true;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
int lastDisplayed = firstDisplayed + displayedCount - 1;
if (selectedRowIndex >= lastDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex - displayedCount + 1].Index;
}
}
}
return true;
}
else if (keyData == Keys.Up)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
int selectedRowIndex = visibleRows.FindIndex(row => row.Selected);
selectedRowIndex--;
if (selectedRowIndex >= 0)
{
visibleRows[selectedRowIndex].Selected = true;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
if (selectedRowIndex < firstDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex].Index;
}
}
}
return true;
}
else if (keyData == Keys.Enter)
{
// Handle Enter key to simulate Play button click
var selectedRow = DgvHymns.SelectedRows.Cast<DataGridViewRow>().FirstOrDefault();
if (selectedRow != null && selectedRow.Cells["CnPlay"].Value != null)
{
DgvHymns_CellContentClick(sender: null, e: new DataGridViewCellEventArgs(1, selectedRow.Index));
return true; // Indicate that the key press has been handled
}
}
else if (keyData == Keys.Home)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
visibleRows.First().Selected = true;
int selectedRowIndex = visibleRows.First().Index;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
if (selectedRowIndex < firstDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex].Index;
}
}
return true; // Indicate that the key press has been handled
}
else if (keyData == Keys.End)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
visibleRows.Last().Selected = true;
int selectedRowIndex = visibleRows.Last().Index;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
int lastDisplayed = firstDisplayed + displayedCount - 1;
if (selectedRowIndex >= lastDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex - displayedCount + 1].Index;
}
}
return true; // Indicate that the key press has been handled
}
return base.ProcessCmdKey(ref msg, keyData); // Allow default processing if not an arrow key
}
}
}

126
Projector/FrmMain.resx Normal file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="CnHymn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="CnPlay.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

133
Projector/FrmPreview.Designer.cs generated Normal file
View File

@ -0,0 +1,133 @@
namespace Projector
{
partial class FrmPreview
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmPreview));
PbShow = new PictureBox();
toolStrip1 = new ToolStrip();
TsbPrevious = new ToolStripButton();
TsbNext = new ToolStripButton();
TkVoice = new TrackBar();
((System.ComponentModel.ISupportInitialize)PbShow).BeginInit();
toolStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)TkVoice).BeginInit();
SuspendLayout();
//
// PbShow
//
PbShow.BackColor = Color.Black;
PbShow.BorderStyle = BorderStyle.FixedSingle;
PbShow.Dock = DockStyle.Fill;
PbShow.Location = new Point(0, 0);
PbShow.Name = "PbShow";
PbShow.Size = new Size(550, 345);
PbShow.SizeMode = PictureBoxSizeMode.StretchImage;
PbShow.TabIndex = 0;
PbShow.TabStop = false;
//
// toolStrip1
//
toolStrip1.AutoSize = false;
toolStrip1.BackColor = Color.Black;
toolStrip1.Dock = DockStyle.Bottom;
toolStrip1.GripStyle = ToolStripGripStyle.Hidden;
toolStrip1.ImageScalingSize = new Size(220, 120);
toolStrip1.Items.AddRange(new ToolStripItem[] { TsbPrevious, TsbNext });
toolStrip1.Location = new Point(0, 345);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(599, 134);
toolStrip1.TabIndex = 1;
toolStrip1.Text = "toolStrip1";
//
// TsbPrevious
//
TsbPrevious.AutoSize = false;
TsbPrevious.DisplayStyle = ToolStripItemDisplayStyle.Image;
TsbPrevious.Image = (Image)resources.GetObject("TsbPrevious.Image");
TsbPrevious.ImageTransparentColor = Color.Magenta;
TsbPrevious.Name = "TsbPrevious";
TsbPrevious.Size = new Size(236, 128);
TsbPrevious.Text = "Previous";
TsbPrevious.Click += TsbPrevious_Click;
//
// TsbNext
//
TsbNext.Alignment = ToolStripItemAlignment.Right;
TsbNext.AutoSize = false;
TsbNext.DisplayStyle = ToolStripItemDisplayStyle.Image;
TsbNext.Image = (Image)resources.GetObject("TsbNext.Image");
TsbNext.ImageTransparentColor = Color.Magenta;
TsbNext.Name = "TsbNext";
TsbNext.Size = new Size(236, 128);
TsbNext.Text = "Next";
TsbNext.Click += TsbNext_Click;
//
// TkVoice
//
TkVoice.AutoSize = false;
TkVoice.BackColor = Color.Black;
TkVoice.Dock = DockStyle.Right;
TkVoice.Location = new Point(550, 0);
TkVoice.Name = "TkVoice";
TkVoice.Orientation = Orientation.Vertical;
TkVoice.Size = new Size(49, 345);
TkVoice.TabIndex = 2;
TkVoice.TickStyle = TickStyle.Both;
TkVoice.Scroll += TkVoice_Scroll;
//
// FrmPreview
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(599, 479);
Controls.Add(PbShow);
Controls.Add(TkVoice);
Controls.Add(toolStrip1);
FormBorderStyle = FormBorderStyle.SizableToolWindow;
Name = "FrmPreview";
StartPosition = FormStartPosition.CenterParent;
Text = "Preview";
FormClosed += FrmPreview_FormClosed;
Load += FrmPreview_Load;
((System.ComponentModel.ISupportInitialize)PbShow).EndInit();
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
((System.ComponentModel.ISupportInitialize)TkVoice).EndInit();
ResumeLayout(false);
}
#endregion
private PictureBox PbShow;
private ToolStrip toolStrip1;
private ToolStripButton TsbPrevious;
private ToolStripButton TsbNext;
private TrackBar TkVoice;
}
}

156
Projector/FrmPreview.cs Normal file
View File

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Projector
{
public partial class FrmPreview : Form
{
private List<string> imagesList = new List<string>();
private int index = 0;
private FourChannelToStereoSampleProvider? _mixer = null;
private FrmProjector frmProjector = new FrmProjector();
private bool secondScreenEnabled = false;
public FrmPreview()
{
InitializeComponent();
Screen[] screens = Screen.AllScreens;
if (screens.Length > 1)
{
secondScreenEnabled = true;
Screen targetScreen = screens[1];
frmProjector.StartPosition = FormStartPosition.Manual;
frmProjector.Location = targetScreen.Bounds.Location;
}
}
public void SetImages(string[] images, FourChannelToStereoSampleProvider mixer)
{
if (secondScreenEnabled && !frmProjector.Visible)
{
frmProjector.Show();
}
_mixer = mixer;
mixer.VoiceVolume = TkVoice.Value / 10f;
imagesList.Clear();
imagesList.AddRange(images);
index = 0;
ShowImage(index);
}
public void Clear()
{
imagesList.Clear();
PbShow.ImageLocation = null;
}
private void ShowImage(int index)
{
if (index >= 0 && index < imagesList.Count)
{
frmProjector.SetImage(imagesList[index]);
PbShow.ImageLocation = imagesList[index];
this.Text = $"Preview - {System.IO.Path.GetFileName(imagesList[index])}";
if (index + 1 < imagesList.Count)
{
TsbNext.Image = Image.FromFile(imagesList[index + 1]);
}
else
{
TsbNext.Image = null; // No next image
}
if (index > 0)
{
TsbPrevious.Image = Image.FromFile(imagesList[index - 1]);
}
else
{
TsbPrevious.Image = null; // No previous image
}
}
else if (index == imagesList.Count)
{
frmProjector.SetImage(null);
PbShow.ImageLocation = null;
this.Text = $"Preview - End";
TsbNext.Image = null;
TsbPrevious.Image = Image.FromFile(imagesList[index - 1]);
}
else
{
frmProjector.SetImage(null);
PbShow.ImageLocation = null;
TsbNext.Image = null;
TsbPrevious.Image = null;
}
}
private void TsbPrevious_Click(object sender, EventArgs e)
{
if (index > 0)
{
index--;
ShowImage(index);
}
}
private void TsbNext_Click(object sender, EventArgs e)
{
if (index < imagesList.Count)
{
index++;
ShowImage(index);
}
}
private void FrmPreview_Load(object sender, EventArgs e)
{
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Left)
{
// Handle Left arrow key press
TsbPrevious_Click(sender: null, e: null); // Simulate click on Previous button
return true; // Indicate that the key press has been handled and prevent default behavior
}
else if (keyData == Keys.Right)
{
// Handle Right arrow key press
TsbNext_Click(sender: null, e: null); // Simulate click on Next button
return true;
}
else if (keyData == Keys.Escape)
{
// Close the form when Escape is pressed
this.Close();
}
return base.ProcessCmdKey(ref msg, keyData); // Allow default processing if not an arrow key
}
private void TkVoice_Scroll(object sender, EventArgs e)
{
_mixer.VoiceVolume = TkVoice.Value / 10f;
}
private void FrmPreview_FormClosed(object sender, FormClosedEventArgs e)
{
frmProjector.SetImage(null);
//frmProjector.Close();
}
}
}

146
Projector/FrmPreview.resx Normal file
View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="TsbPrevious.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAEESURBVEhL3ZKvDoJQFId5Dk0238GGr2DXbqBa3Cw6uy+g
RZozaTM4gxvZQHA6kc05/2CAetzP7bIrF0Hk3iLbx91O+L5xLloQBKQSDS/TNMkwDKnAGQYw0HVdKnAK
Ae/+kIK0wPV0JHvWI3veo4M1kR+wBjot24UQFpEW4OUAX6I2MJMc2K2GoRzrwp18HXDOHjUXp9cZFaeR
GoC0OnWpODq8zqyRxMDGvYdyRtbIx8B6f6Py2HmT/xKJDVRqjY/ytAhm/FwI1FtdKg23gjCOaITdFz8X
An3rIoiSYDL+Z2BzrDl3gMmiPwPAmrHu3IEksG6sXVkAwPlHAZVovu93VKKpfp4ISreGcqlKAwAAAABJ
RU5ErkJggg==
</value>
</data>
<data name="TsbNext.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAEESURBVEhL3ZKvDoJQFId5Dk0238GGr2DXbqBa3Cw6uy+g
RZozaTM4gxvZQHA6kc05/2CAetzP7bIrF0Hk3iLbx91O+L5xLloQBKQSDS/TNMkwDKnAGQYw0HVdKnAK
Ae/+kIK0wPV0JHvWI3veo4M1kR+wBjot24UQFpEW4OUAX6I2MJMc2K2GoRzrwp18HXDOHjUXp9cZFaeR
GoC0OnWpODq8zqyRxMDGvYdyRtbIx8B6f6Py2HmT/xKJDVRqjY/ytAhm/FwI1FtdKg23gjCOaITdFz8X
An3rIoiSYDL+Z2BzrDl3gMmiPwPAmrHu3IEksG6sXVkAwPlHAZVovu93VKKpfp4ISreGcqlKAwAAAABJ
RU5ErkJggg==
</value>
</data>
</root>

64
Projector/FrmProjector.Designer.cs generated Normal file
View File

@ -0,0 +1,64 @@
namespace Projector
{
partial class FrmProjector
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
PbShow = new PictureBox();
((System.ComponentModel.ISupportInitialize)PbShow).BeginInit();
SuspendLayout();
//
// PbShow
//
PbShow.BackColor = Color.Black;
PbShow.Dock = DockStyle.Fill;
PbShow.Location = new Point(0, 0);
PbShow.Name = "PbShow";
PbShow.Size = new Size(800, 450);
PbShow.SizeMode = PictureBoxSizeMode.StretchImage;
PbShow.TabIndex = 0;
PbShow.TabStop = false;
//
// FrmProjector
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(PbShow);
FormBorderStyle = FormBorderStyle.None;
Name = "FrmProjector";
Text = "FrmProjector";
WindowState = FormWindowState.Maximized;
((System.ComponentModel.ISupportInitialize)PbShow).EndInit();
ResumeLayout(false);
}
#endregion
private PictureBox PbShow;
}
}

25
Projector/FrmProjector.cs Normal file
View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Projector
{
public partial class FrmProjector : Form
{
public FrmProjector()
{
InitializeComponent();
}
public void SetImage(string? imagePath)
{
PbShow.ImageLocation = imagePath;
}
}
}

120
Projector/FrmProjector.resx Normal file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

17
Projector/Program.cs Normal file
View File

@ -0,0 +1,17 @@
namespace Projector
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new FrmMain());
}
}
}

View File

@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NAudio" Version="2.2.1" />
<PackageReference Include="YoutubeExplode" Version="6.5.4" />
<PackageReference Include="YoutubeExplode.Converter" Version="6.5.4" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Hymns.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Hymns.settings</DependentUpon>
</Compile>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Hymns.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Hymns.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>

35
Projector/Properties/Hymns.Designer.cs generated Normal file
View File

@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Projector.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
internal sealed partial class Hymns : global::System.Configuration.ApplicationSettingsBase {
private static Hymns defaultInstance = ((Hymns)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Hymns())));
public static Hymns Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string Lyrics {
get {
return ((string)(this["Lyrics"]));
}
}
}
}

View File

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Projector.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="Lyrics" Type="System.String" Scope="Application">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Projector.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Projector.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Play {
get {
object obj = ResourceManager.GetObject("Play", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Play" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Play.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B