I run it as a VST under Windows, but I also have a Linux version that I run on a Raspberry Pi 4. Coupled with a USB audio interface, a PA speaker, and a remote control app on my phone, it makes for a nice little portable rig.
Showing posts with label WPF. Show all posts
Showing posts with label WPF. Show all posts
Tuesday, November 3, 2020
Guitar amplifier and pedal simulation
I've been spending a lot of time lately playing guitar, and working on my own software for simulating guitar amplifiers and pedals. It is coming along nicely, and I have most of the important stuff covered.
Here is a little video of it in action (running as a VST in Reaper):
Monday, January 19, 2009
More FM Synth Progress

Ok, my "little" FM synthesizer project is now officially a bit out of control. It has grown to include a drum pattern editor, chord progressions and a mini song sequencer. WPF, with its clean separation between the UI and the underlying code is perfect for doing audio interface work. Too bad the digital audio world is still mired in C++...
Monday, January 12, 2009
WPF Layout Woes - MeasureOverride killed Schrödinger's Cat
A struggle I'm currently having with layout in WPF reminds me of the Observer Effect in physics. It turns out that calling Measure() on a child object has side effects. You would think that the measuring phase of layout would simply involve asking the child how big it wants to be. Instead, you need to pass it a size constraint.
Normally, that would not be a problem, but what if you want to size a set of children based on their relative desired sizes? Catch-22. You can't call Measure() on a child without knowing the maximum size you want it to be. And, in my situation, I don't know what size I want it to be without first measuring it. And, once you have measured an objected, its size "sticks" - changing it when you do Arrange() only alters the size of the clip rectangle (an important distinction if the child actually can be variably sized - such as content within a ScrollViewer).
Very frustrating.
I have found a fairly complicated way of working around the isue, but it seems like a fundamental (if not often encountered) flaw in the way WPF layout works.
Normally, that would not be a problem, but what if you want to size a set of children based on their relative desired sizes? Catch-22. You can't call Measure() on a child without knowing the maximum size you want it to be. And, in my situation, I don't know what size I want it to be without first measuring it. And, once you have measured an objected, its size "sticks" - changing it when you do Arrange() only alters the size of the clip rectangle (an important distinction if the child actually can be variably sized - such as content within a ScrollViewer).
Very frustrating.
I have found a fairly complicated way of working around the isue, but it seems like a fundamental (if not often encountered) flaw in the way WPF layout works.
Friday, December 5, 2008
FM Synth W.I.P.
Thursday, December 4, 2008
Changing the text style of a WPF GroupBox header
I wanted to change the style of the header of a WPF GroupBox today and had to do a little digging to figure out how to do it.
The GroupBox header is not limited to just text - it can be any control. Because of this, no header text styling options are available directly as properties of the GroupBox control. Instead, you need to modify the DataTemplate of the GroupBox header.
Here is a style that will make the GroupBox header text black and bold:
Note that this method is a bit of a hack, in that it assumes that your header is text. If it isn't, though, you've added your own custom controls to the header and you don't have a styling problem in the first place...
The GroupBox header is not limited to just text - it can be any control. Because of this, no header text styling options are available directly as properties of the GroupBox control. Instead, you need to modify the DataTemplate of the GroupBox header.
Here is a style that will make the GroupBox header text black and bold:
<Style x:Key="MyGroupBoxStyle" TargetType="{x:Type GroupBox}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Black" FontWeight="Bold"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Note that this method is a bit of a hack, in that it assumes that your header is text. If it isn't, though, you've added your own custom controls to the header and you don't have a styling problem in the first place...
Friday, December 21, 2007
WPF Progress Bars
Note: I've posted an updated, even easier to use version of this code here:
WPF Progress Bars Revisited
Implementing a progress bar display for long-running tasks is a commonly occurring task. WPF has a simple ProgressBar control which works as you would expect. It has a floating point Value property that is used to display progress within a range (set using the Minimum and Maximum properties). Here is some XAML to implement a progress dialog:
The progress bar is set to take progress values from 0 to 1, and has a TextBlock for displaying a status message.
It might seem like we are finished, but it is only part of what you need for a functional progress dialog. In trying to use the dialog, you quickly run into a problem - how to avoid blocking the UI thread while your operation proceeds. In Windows Forms, a common cheat was to periodically call Application.DoEvents() to allow the UI to update. While you can do something similar in WPF, it is ugly and best avoided.
Instead, you should do your work asynchronously in a separate thread. Given that, the next question becomes how to update the UI from your second thread, as WPF UI operations are not thread-safe, and you will get an exception if you try to interact with a control outside of the thread in which it was created. The solution? Use the Dispatcher. The Dispatcher basically lets you queue up function calls on the UI thread from your background thread.
To manage this communication, we will first create an interface for interacting with a progress dialog:
The UpdateProgress() method allows us to set the current progress value, UpdateStatus() allows us to display a text status message, Finish() lets us signal that our operation has completed, and the Canceled property allows us to check if the user has canceled the operation.
Now, the code-behind for the dialog:
As you can see, we are basically just implementing the IProgressContext interface. We use the dispatcher to send along our progress updates to the UI thread. To use the dialog, launch a background thread to do your work, passing it a progress dialog as IProgressContext. Your work loop will look something like this:
You can obviously get more fancy with your dialog - this is just a simple implementation to get started with.
WPF Progress Bars Revisited
Implementing a progress bar display for long-running tasks is a commonly occurring task. WPF has a simple ProgressBar control which works as you would expect. It has a floating point Value property that is used to display progress within a range (set using the Minimum and Maximum properties). Here is some XAML to implement a progress dialog:
<Window x:Class="MyNamespace.ProgressDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Progress Dialog" Width="300" SizeToContent="Height">
<Grid>
<StackPanel Margin="10">
<ProgressBar Name="Progress" Width="200" Height="20" Minimum="0" Maximum="1" Margin="10" />
<TextBlock Name="StatusText" Margin="10" Height="50"/>
<StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
<Button Name="CancelButton">Cancel</Button>
</StackPanel>
</StackPanel>
</Grid>
</Window>
The progress bar is set to take progress values from 0 to 1, and has a TextBlock for displaying a status message.
It might seem like we are finished, but it is only part of what you need for a functional progress dialog. In trying to use the dialog, you quickly run into a problem - how to avoid blocking the UI thread while your operation proceeds. In Windows Forms, a common cheat was to periodically call Application.DoEvents() to allow the UI to update. While you can do something similar in WPF, it is ugly and best avoided.
Instead, you should do your work asynchronously in a separate thread. Given that, the next question becomes how to update the UI from your second thread, as WPF UI operations are not thread-safe, and you will get an exception if you try to interact with a control outside of the thread in which it was created. The solution? Use the Dispatcher. The Dispatcher basically lets you queue up function calls on the UI thread from your background thread.
To manage this communication, we will first create an interface for interacting with a progress dialog:
public interface IProgressContext
{
void UpdateProgress(double progress);
void UpdateStatus(string status);
void Finish();
bool Canceled { get; }
}
The UpdateProgress() method allows us to set the current progress value, UpdateStatus() allows us to display a text status message, Finish() lets us signal that our operation has completed, and the Canceled property allows us to check if the user has canceled the operation.
Now, the code-behind for the dialog:
public partial class ProgressDialog : Window, IProgressContext
{
private bool canceled = false;
public bool Canceled
{
get { return canceled; }
}
public ProgressDialog()
{
InitializeComponent();
CancelButton.Click += new RoutedEventHandler(CancelButton_Click);
}
void CancelButton_Click(object sender, RoutedEventArgs e)
{
canceled = true;
CancelButton.IsEnabled = false;
}
public void UpdateProgress(double progress)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { Progress.SetValue(ProgressBar.ValueProperty, progress); }, null);
}
public void UpdateStatus(string status)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { StatusText.SetValue(TextBlock.TextProperty, status); }, null);
}
public void Finish()
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { Close(); }, null);
}
}
As you can see, we are basically just implementing the IProgressContext interface. We use the dispatcher to send along our progress updates to the UI thread. To use the dialog, launch a background thread to do your work, passing it a progress dialog as IProgressContext. Your work loop will look something like this:
for (int i = 0; i < 100; i++)
{
if (myProgressContext.Canceled)
break;
myProgressContext.UpdateProgress((double)i / 100.0);
myProgressContext.UpdateStatus("Doing Step " + i);
}
myProgressContext.Finish();
You can obviously get more fancy with your dialog - this is just a simple implementation to get started with.
Wednesday, December 12, 2007
Drag and Drop in WPF
Drag and Drop in WPF is, I think, more complex than it should be. I've had to implement it a few times now, so I recently put together a simple helper class that simplifies things.
The full class code follows at the end of the post, but first I will give a few examples of using it. If you have an object that you want to be draggable, just create a DragDropHander object for it:
Implement the handler like this:
Here is the full DragDropHandler class implementation:
The full class code follows at the end of the post, but first I will give a few examples of using it. If you have an object that you want to be draggable, just create a DragDropHander object for it:
DragDropHandler dragDrop = new DragDropHandler(myControl, new System.Windows.DataObject(myDragData));Where "myControl" is the WPF control the use will drag from, and "myDragData" is the object you wish to receive on the other end of the drag and drop. To receive the drop, make sure the control you want to drop to has AllowDrop set, and add a drop handler in your control initialization:
MyControl.Drop += new DragEventHandler(MyControl_Drop);Implement the handler like this:
void MyControl_Drop(object sender, DragEventArgs e)If you want to drag an object outside of your application, you need to create the appropriate DataObject. A common case is a filename. To create a drag handler that drags a filename, do:
{
MyDataType myData = (MyDataType )e.Data.GetData(typeof(MyDataType).ToString());
// Do something with the dropped object
}
DragDropHandler dragDrop = new DragDropHandler(myControl, new System.Windows.DataObject(DataFormats.FileDrop, new string[] { myPath }));You can obviously get much more complicated with drag and drop - handling drag enter/over/leave events and using adorners to visually display drag data, for example. This should get you started, though, and probably is sufficient for most needs.
Here is the full DragDropHandler class implementation:
using System;
using System.Windows.Data;
using System.Windows;
using System.Windows.Input;
namespace MyCoolNamespace
{
public class DragDropHandler
{
private FrameworkElement dragElement = null;
private bool dragging = false;
private bool inDragDrop = false;
private Point dragStart;
private DataObject dataObject = null;
public DragDropHandler(FrameworkElement dragElement, DataObject dataObject)
{
this.dragElement = dragElement;
this.dataObject = dataObject;
dragElement.MouseLeftButtonDown += new MouseButtonEventHandler(dragElement_MouseLeftButtonDown);
dragElement.MouseMove += new MouseEventHandler(dragElement_MouseMove);
}
void dragElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!dragElement.IsMouseCaptured)
{
dragging = true;
dragStart = e.GetPosition(dragElement);
}
}
void dragElement_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
Point currentPos = e.GetPosition(dragElement);
if ((Math.Abs(currentPos.X - dragStart.X) > 5) || (Math.Abs(currentPos.Y - dragStart.Y) > 5))
{
dragElement.CaptureMouse();
inDragDrop = true;
DragDropEffects de = DragDrop.DoDragDrop(dragElement, dataObject, DragDropEffects.Move);
inDragDrop = false;
dragging = false;
dragElement.ReleaseMouseCapture();
}
}
}
}
}
WPF ListView - Getting the Clicked Item
I recently had the need to figure out which item in a WPF ListView was under the mouse when it was clicked. The solution wasn't completely straightforward, so I thought I'd post it here.
First, obviously you need to register a mouse button event hander in your control initialization. In this case, I'm using a double-click event:
First, obviously you need to register a mouse button event hander in your control initialization. In this case, I'm using a double-click event:
MyListView.MouseDoubleClick += new MouseButtonEventHandler(MyListView_MouseDoubleClick);and then implement the event handler like such:void MyListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)What we are doing is walking up the visual tree starting at the element the generated the mouse event. We stop when we find a ListViewItem, which we can then use to get the corresponding data item. If all you want is the index of the item, use IndexFromContainer() instead.
{
DependencyObject dep = (DependencyObject)e.OriginalSource;
while ((dep != null) && !(dep is ListViewItem))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
return;
MyDataItemType item = (MyDataItemType)MyListView.ItemContainerGenerator.ItemFromContainer(dep);
// Do something with the item...
}
Monday, August 20, 2007
Using Project Resources in WPF
For a project I am working on, I have a directory full of icons that I use. I had been loading them from a fixed path on disk, but I wanted to make my application more portable so I decided to turn them into project resources.
To to this, you first create a folder in your project to store your resources. You can put them in the project root, but that gets cluttered. In my case, I created a new folder in my project called 'Icons'. Next, add your image files to the new folder. You can copy them directly to the folder and then import them into the project by using 'Add Existing Item'.
Once added, check the Properties of your images to ensure they have a Build Action of 'Resource' (they should be by default -- at least that is the behavior I get with Visual Studio 2008). Now when you build your project they will be compiled directly into the executable.
Referencing the embedded resources to create WPF images is simple. From XAML, you simply specify the relative path to the resource as your Image Source:
From code, you specify the path as a relative URI:
To to this, you first create a folder in your project to store your resources. You can put them in the project root, but that gets cluttered. In my case, I created a new folder in my project called 'Icons'. Next, add your image files to the new folder. You can copy them directly to the folder and then import them into the project by using 'Add Existing Item'.
Once added, check the Properties of your images to ensure they have a Build Action of 'Resource' (they should be by default -- at least that is the behavior I get with Visual Studio 2008). Now when you build your project they will be compiled directly into the executable.
Referencing the embedded resources to create WPF images is simple. From XAML, you simply specify the relative path to the resource as your Image Source:
<Image Source="Icons/MyImage.png" />
From code, you specify the path as a relative URI:
Image myImage = new Image();
myImage.Source = new BitmapImage(new Uri("Icons/MyImage.png", UriKind.Relative));
Monday, July 16, 2007
A TV3D ArcBall implementation
A common need in 3D applications is the ability to rotate an object with the mouse. One of the most natural ways to implement this is to imagine that there is a sphere centered on the object, and that you are grabbing a point on the sphere and rotating it. The canonical example of this "ArcBall" technique is the implementation by Ken Shoemake in Graphics Gems IV, but many other versions are floating around the Net. I needed a C# implementation for TV3D, so I rolled my own. It is most closely based on a WPF implementation by Daniel Lehenbauer (check the link for a nice overview of the theory behind the implementation).
My version is a pretty direct translation, with one nice improvement. Instead of doing a delta each mouse move from the previous mouse movement, I always do a delta from the beginning of the mouse drag. I found that without this modification, floating point rounding error caused obvious visual problems. Always computing a delta from the start of the mouse drag ensures complete consistency during the drag.
The ArcBall class follows, but first here is an example of how to use it. At some point during your application initialization, create an instance of the ArcBall class like this:
where 'windowWidth' and 'windowHeight' are the width and height of your display window, and 'mathLibrary' is a instance of the TVMathLibrary class.
Then, in your game loop where you are checking mouse input, do something like the following:
This code starts a drag when the mouse button (in this case, mouse button 2) is pressed. It initializes the ArcBall with the initial mouse position and the initial quaternion of the mesh we want to rotate. While the mouse button is down, it updates the ArcBall with the current mouse position and gets the resulting quaternion. This is then applied to the mesh to get the desired rotation.
Here is the code for the ArcBall class:
My version is a pretty direct translation, with one nice improvement. Instead of doing a delta each mouse move from the previous mouse movement, I always do a delta from the beginning of the mouse drag. I found that without this modification, floating point rounding error caused obvious visual problems. Always computing a delta from the start of the mouse drag ensures complete consistency during the drag.
The ArcBall class follows, but first here is an example of how to use it. At some point during your application initialization, create an instance of the ArcBall class like this:
ArcBall myArcBall = new ArcBall(windowWidth, windowHeight, mathLibrary);
where 'windowWidth' and 'windowHeight' are the width and height of your display window, and 'mathLibrary' is a instance of the TVMathLibrary class.
Then, in your game loop where you are checking mouse input, do something like the following:
InputEngine.GetAbsMouseState(ref mouseX, ref mouseY, ref mouseB1, ref mouseB2, ref mouseB3);
if (mouseB2)
{
if (mouseDragging)
{
TV_3DQUATERNION result = new TV_3DQUATERNION();
myArcBall.Update(new TV_2DVECTOR((float)mouseX, (float)mouseY), ref result);
myMesh.SetQuaternion(result);
}
else
{
if (selectedObject != null)
{
myArcBall.StartDrag(new TV_2DVECTOR((float)mouseX, (float)mouseY), myMesh.GetQuaternion());
mouseDragging = true;
}
}
}
else
{
mouseDragging = false;
}
This code starts a drag when the mouse button (in this case, mouse button 2) is pressed. It initializes the ArcBall with the initial mouse position and the initial quaternion of the mesh we want to rotate. While the mouse button is down, it updates the ArcBall with the current mouse position and gets the resulting quaternion. This is then applied to the mesh to get the desired rotation.
Here is the code for the ArcBall class:
class ArcBall
{
private TV_2DVECTOR startPoint;
private TV_3DVECTOR startVector = new TV_3DVECTOR(0.0f, 0.0f, 1.0f);
private TV_3DQUATERNION startRotation;
private float width, height;
private TVMathLibrary mathLib;
/// <summary>
/// ArcBall Constructor
/// </summary>
/// <param name="width">The width of your display window</param>
/// <param name="height">The height of your display window</param>
/// <param name="mathLib">An instance of the TV3D math library</param>
public ArcBall(float width, float height, TVMathLibrary mathLib)
{
this.width = width;
this.height = height;
this.mathLib = mathLib;
}
/// <summary>
/// Begin dragging
/// </summary>
/// <param name="startPoint">The X/Y position in your window at the beginning of dragging</param>
/// <param name="rotation"></param>
public void StartDrag(TV_2DVECTOR startPoint, TV_3DQUATERNION rotation)
{
this.startPoint = startPoint;
this.startVector = MapToSphere(startPoint);
this.startRotation = rotation;
}
/// <summary>
/// Get an updated rotation based on the current mouse position
/// </summary>
/// <param name="currentPoint">The curren X/Y position of the mouse</param>
/// <param name="result">The resulting quaternion to use to rotate your object</param>
public void Update(TV_2DVECTOR currentPoint, ref TV_3DQUATERNION result)
{
TV_3DVECTOR currentVector = MapToSphere(currentPoint);
TV_3DVECTOR axis = mathLib.VCrossProduct(startVector, currentVector);
float angle = mathLib.VDotProduct(startVector, currentVector);
TV_3DQUATERNION delta = new TV_3DQUATERNION(axis.x, axis.y, axis.z, -angle);
mathLib.TVQuaternionMultiply(ref result, startRotation, delta);
}
/// <summary>
/// Map a point in window space to our arc ball sphere
/// </summary>
/// <param name="point">The X/Y position to map</param>
/// <returns>The 3D position on the sphere</returns>
private TV_3DVECTOR MapToSphere(TV_2DVECTOR point)
{
float x = point.x / (width / 2.0f);
float y = point.y / (height / 2.0f);
x = x - 1.0f;
y = 1.0f - y;
float z2 = 1.0f - x * x - y * y;
float z = z2 > 0.0f ? (float)Math.Sqrt((double)z2) : 0;
TV_3DVECTOR outVec = new TV_3DVECTOR();
mathLib.TVVec3Normalize(ref outVec, new TV_3DVECTOR(x, y, z));
return outVec;
}
}
Thursday, July 12, 2007
WPF Text Woes
WPF text rendering currently has a complete show-stopper of a problem. I'm not talking about the general "blurriness" of text. That's just anti-aliasing, and while I personally prefer small text to be aliased, I can live with it.
The problem that is driving me mad is the behavior of text when it scrolls. After scrolling stops, sections of the text will slowly adjust focus over a period of a second or two. At first, I thought the issue was just eyestrain on my part, but it really is doing it. It is very uncomfortable to look at, and in my opinion makes WPF useless in text-heavy applications until Microsoft finds a way to fix it.
Other people have noticed the issue as well. This post sheds some light on the issue, and implies that it was a conscious design decision.
There has to be a better way...
The problem that is driving me mad is the behavior of text when it scrolls. After scrolling stops, sections of the text will slowly adjust focus over a period of a second or two. At first, I thought the issue was just eyestrain on my part, but it really is doing it. It is very uncomfortable to look at, and in my opinion makes WPF useless in text-heavy applications until Microsoft finds a way to fix it.
Other people have noticed the issue as well. This post sheds some light on the issue, and implies that it was a conscious design decision.
There has to be a better way...

