J2i.Net

Nothing at all and Everything in general.

Changing the Pitch of a Sound

I got a tweet earlier today from some one asking me how to change the pitch of a wave file. The person asking was aware that SoundEffectInstance has a setting to alter pitch but it wasn't sufficient for his needs. He needed to be able to save the modified WAV to a file. It's something that is easy to do. So I made a quick example

Video Example

I used a technique that comes close to matching linear interpolation. It get's the job done but isn't the best technique because of the opportunity for certain types of distortion to introduced. Methods with less distortion are available at the cost of potentially more CPU cycles. For the example I made no matter what the original sample rate was I am playing back at 44KHz and adjusting my interpolation accordingly so that no unintentional changes in pitch are introduced.

To do the work I've created a class named AdjustedSoundEffect. It has a Play() method that takes as it's argument the factor by which the pitch should be adjusted where 1 plays the sound at the original pitch, 2 plays it at twice its pitch, and 0.5 plays it at half its pitch.

If you are interested the code I used is below.

using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework.Audio;

namespace J2i.Net.VoiceRecorder.Utility
{
    public class AdjustedSoundEffect
    {
        //I will always playback at 44KHz regardless of the original sample rate. 
        //I'm making appropriate adjustments to prevent this from resulting in the
        //pitch being shifted. 
        private const int PlaybackSampleRate = 16000;
        private const int BufferSize = PlaybackSampleRate*2;

        private int _channelCount = 1;
        private int _sampleRate;
        private int _bytesPerSample = 16;
        private int _byteCount = 0;
        private float _baseStepRate = 1;
        private float _adjustedStepRate;
        private float _index = 0;
        private int playbackBufferIndex = 0;
        private int _sampleStep = 2;

        private bool _timeToStop = false;

        private byte[][] _playbackBuffers;

        public bool IsPlaying { get; set;  }

        public object SyncRoot = new object();


        private DynamicSoundEffectInstance _dse;

        public static AdjustedSoundEffect FromStream(Stream source)
        {
            var retVal = new AdjustedSoundEffect(source);
            return retVal;
        }

        public AdjustedSoundEffect()
        {
            _playbackBuffers = new byte[3][];
            for (var i = 0; i < _playbackBuffers.Length;++i )
            {
                _playbackBuffers[i] = new byte[BufferSize];
            }
                _dse = new DynamicSoundEffectInstance(PlaybackSampleRate, AudioChannels.Stereo);
            _dse.BufferNeeded += new EventHandler<EventArgs>(_dse_BufferNeeded);
        }

        void SubmitNextBuffer()
        {
            if(_timeToStop)
            {
                Stop();
            }
            lock (SyncRoot)
            {
                byte[] nextBuffer = _playbackBuffers[playbackBufferIndex];
                playbackBufferIndex = (playbackBufferIndex + 1)%_playbackBuffers.Length;
                int i_step = 0;
                int i = 0;

                int endOfBufferMargin = 2*_channelCount;
                for (;
                    i < (nextBuffer.Length / 4) && (_index < (_sourceBuffer.Length - endOfBufferMargin));
                    ++i, i_step += 4)
                {

                    int k = _sampleStep*(int) _index;
                    if (k > _sourceBuffer.Length - endOfBufferMargin)
                        k = _sourceBuffer.Length -endOfBufferMargin ;
                    nextBuffer[i_step + 0] = _sourceBuffer[k + 0];
                    nextBuffer[i_step + 1] = _sourceBuffer[k + 1];
                    if (_channelCount == 2)
                    {
                        nextBuffer[i_step + 2] = _sourceBuffer[k + 2];
                        nextBuffer[i_step + 3] = _sourceBuffer[k + 3];
                    }
                    else
                    {
                        nextBuffer[i_step + 2] = _sourceBuffer[k + 0];
                        nextBuffer[i_step + 3] = _sourceBuffer[k + 1];

                    }
                    _index += _adjustedStepRate;
                }

                if ((_index >= _sourceBuffer.Length - endOfBufferMargin))
                    _timeToStop = true;
                for (; i < (nextBuffer.Length/4); ++i, i_step += 4)
                {
                    nextBuffer[i_step + 0] = 0;
                    nextBuffer[i_step + 1] = 0;
                    if (_channelCount == 2)
                    {
                        nextBuffer[i_step + 2] = 0;
                        nextBuffer[i_step + 3] = 0;
                    }
                }
                _dse.SubmitBuffer(nextBuffer);
            }
        }

        void _dse_BufferNeeded(object sender, EventArgs e)
        {
            SubmitNextBuffer();
        }

        private byte[] _sourceBuffer;
        

        public AdjustedSoundEffect(Stream source): this()
        {
            byte[] header = new byte[44];
            source.Read(header, 0, 44);

            // I'm assuming you passed a proper wave file so I won't bother 
            // verifying  that  the  header  is properly formatted and will 
            // accept it on faith :-)

            _channelCount = header[22] + (header[23] << 8);
            _sampleRate = header[24] | (header[25] << 8) | (header[26] << 16) | (header[27] << 24);
            _bytesPerSample = header[34]/8;
            _byteCount = header[40] | (header[41] << 8) | (header[42] << 16) | (header[43] << 24);
            _sampleStep = _bytesPerSample*_channelCount;
            _sourceBuffer = new byte[_byteCount];
            source.Read(_sourceBuffer, 0, _sourceBuffer.Length);


            _baseStepRate = ((float)_sampleRate) / PlaybackSampleRate;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pitchFactor">Factor by which pitch will be adjusted. 2 doubles the frequency,
        /// // 1 is normal speed, 0.5 halfs the frequency</param>
        public void Play(float pitchFactor)
        {
            _timeToStop = false;

            _index = 0;
            lock (SyncRoot)
            {
                _adjustedStepRate = _baseStepRate * pitchFactor;
                _index = 0;
                playbackBufferIndex = 0;
            }
            if(!IsPlaying)
            {
                SubmitNextBuffer();
                SubmitNextBuffer();
                SubmitNextBuffer();
                _dse.Play();
                IsPlaying = true;
            }
        }

        public void Stop()
        {
            if(IsPlaying)
            {
                _dse.Stop();
            }
        }
    }
}

Adding an E-Mail Account to the WP Emulator

For one reason or another you may find that you want to add a real e-mail account to the Windows Phone emulator. Unfortunately the emulator doesn't directly expose a way for you to do this; the settings area on the phone doesn't display the tile to access the e-mail settings. You can get to the settings application indirectly though. This path is convoluted, but it works.

You'll need to make a simple application that does nothing more than show a phone call task. Once the task is displayed accept the phone call then select the option to add another caller. This takes you to the People Hub. Swipe through the People Hub to the "What's New" and you will be prompted to add a Facebook or Twitter account. Select the option to do this (even though you are not really adding an account of that type) and when you asked what type of account you want to add you can select one of the e-mail account types.

Setting Custom Ringtones from Code [Mango:Beta 1]

Written against pre-release information

One of the new features coming with the next update to Windows Phone 7 is the ability to set custom ring tones. From within code you can make a ring tone available to a user (it's up to the user to accept the ring tone, so user settings won't ever be changed without user permission). I was looking at the new API for doing this, the SaveRingtonTask()

To use the API you first need to get the ringtone of interest into isolated storage. It can be either an MP3 file or a WMA file up to 30 seconds in length. If the file is a part of your application. Just set it's build type to "Resource".

file settings

Getting the file from being packed in the application to isolated storage is a matter of reading from a resource stream and writing to isolated storage.

var
s =
    Application.GetResourceStream(new Uri("/MyApplicationName;component/1up.mp3",
                                            UriKind.Relative));
{
    using (var f = IsolatedStorageFile.GetUserStoreForApplication().CreateFile("1up.mp3"))
    {

        var buffer = new byte[2048];
        int bytesRead = 0;

        do
        {
            bytesRead = s.Stream.Read(buffer, 0, 1024);
            f.Write(buffer, 0, bytesRead);
        } while (bytesRead > 0);

        f.Close();
    }
}

Once the file is in isolated storage you must pass the URL to the SaveRingtoneTask(). URIs to isolated storage are preceded with "isostore:" (there is also an "appdata:" prefix, but we won't be using it here). Give the ringtone a display name and call the show method to present the user with the option to save it. If you don't set the

SaveRingtoneTask srt = new SaveRingtoneTask();
srt.DisplayName = "1up";
srt.IsoStore= new Uri("isostore:/1up.mp3", UriKind.Absolute);
srt.IsShareable = true;
srt.Show();

Peer Communication on Windows Phone 7

Written against pre-release information

One of the new things that we get with Windows Phone 7 is socket support. While I expected to be able to open sockets to other machines with servers running on them one thing caught me by surprised; that you can also send communication from phone to phone using UDP. I've got to give credit to Ricky_T for pointint out the presence of this feature and posting a code sample. I wanted to try this out myself. So I made a version of the code sample that would run on both Windows Phone and on the desktop (Silverlight 4 in Out of Browser mode). I was pleasantly surprised to that I was able to open up peer communication between the desktop and phone without a problem. This capability provides a number of solutions for other problems that I've been considering, such as automatic discovery and configuration for communicating with services hosted on a user's local network. 

Most of the code used in the desktop and phone version of this example are identical; I've shared some of the same files between projects. From the files that are not shared the counterparts in the phone and desktop version are still similar.  The core of the code is in a class called Peer. Let's take a look at part of the body of that class. 

 

//Define the port and multicast address to be used for communication
private string _channelAddress = "224.0.0.1";
private int _channelPort = 3007;

//The event to be raised when a message comes in
public event EventHandler<MessageReceivedEventArgs> MessageReceived; 

//the UDP channel over which communication will occur.
private UdpAnySourceMulticastClient _channel;

//Create tje cjamme;
public void Initialize()
{
    _channel = new UdpAnySourceMulticastClient(IPAddress.Parse(_channelAddress), _channelPort);
}

//Open the channel and start listening
public void Open()
{
    if (_channel == null)
        Initialize();
    ClientState = ClientStatesEnum.Opening;
            

    _openResult = _channel.BeginJoinGroup((result) =>
                                                {
                                                    _channel.EndJoinGroup(result);
                                                    ClientState = ClientStatesEnum.Opened;
                                                }, null);   
            
    Receive();
}


 

//The receive method is recursive. At the end of a call to receive it calls itself 
//so that the class can continue listening for incoming requests.
void Receive()
{
    byte[] _receiveBuffer = new byte[1024];

    _channel.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length, (r) =>
    {
        if(ClientState!=ClientStatesEnum.Closing)
        {
            try
            {
            IPEndPoint source;
            int size= _channel.EndReceiveFromGroup(r, out source);
            OnMessageReceived(_receiveBuffer, size,  source);                                                                                   
            }
            catch (Exception )
            {
            }
            finally
            {
                this.Receive();
            }
        }
    }, null);
}
public void Send(byte[] data)
{
    if(ClientState==ClientStatesEnum.Opened)
    {
        _channel.BeginSendToGroup(data, 0, data.Length, (r) => _channel.EndSendToGroup(r),null);
    }
}

This class only sends and receives byte arrays. My only goal here was to see the code work so there are other considerations that I have decided to overlook for now. I made a client to use this code too. The client sends and receives plain text. Before sending a block of text it is necessary to convert the text to a byte array. The encoding classes in .Net will take care of this for me. When a message comes in I can also use an encoder to convert the byte array back to a string.

For this program I am adding the incoming message to a list along with the IP address from which it came

void _peer_MessageReceived(object sender, MessageReceivedEventArgs e)
{
    Action a = () =>
                    {
                        string message = System.Text.UTF8Encoding.Unicode.GetString(e.Data, 0, e.Size);
                        MessageList.Add(String.Format("{0}:{1}", e.Endpoint.Address.ToString(), message));
                        OnIncomingMessageReceived(message, e.Endpoint.Address.ToString());
                    };
    if (UIDispatcher == null)
        a();
    else
        UIDispatcher.BeginInvoke(a);
}

public void SendMessage(string message)
{
    byte[] encodedMessage= UTF8Encoding.Unicode.GetBytes(message);
    _peer.Send(encodedMessage);
}

When the code is run on any combination of multiply phones or computers a message types on any one of the devices appears on all of them. Nice! Now to start making use of it.

John Conway's Game of Life part 1 of N

The Game of Life is a refinement of an idea from John von Newman in the 1940's. The refinement was done by John Conway and appeared in Scientific America in October 1970. I'll skip over the details of why such a program is of interest. But the program produces some interesting patterns.

The typical version of the game is composed of a grid of cells where some number of cells are initially marked as having life. The grid of cells is evaluated and cells get marked as alive or dead based on a small set of rules based on it's neighbors. Two cells are neighbors with each other if they touch diagonally or side-by-side.

  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overcrowding.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

The above algorithm enough and the program is easy to implement. The challenge is more in creating a decent user interface for the program. I decided to make this program myself. The first step in making the program was to implement the algorithm. I wanted to make sure the algorithm worked so I created a simple XNA program that would allow me to see the algorithm work. It's non-interactive so you can only see the program run but not impact the outcome.

Theres a small amount of data that needs to be tracked for each cell. I need to know if a cell is alive and whether or not it should be alive during the next cycle. The cell will also need to interact with other cells in the community. Some time in the future I plan to allow the cells to express something about the parent from which it came. Though I won't be doing that for this first version.

public class Cell
{
     public CellCommunity  Community   { get; set; }
     public bool           IsAlive     { get; set; }
     public bool           WillSurvive { get; set; }
     public Gene           GeneList { get; set; }
}

The community of cells themselves will be saved in a two dimensional array. The cell community class has two methods that will do the work of calculating whether or not a cell should be alive the next cycle and another for applying the results of those calculations.

public void EvaluateNewGeneration()
{
    ++GenerationCount;

    for (var cx = 0; cx < CellGrid.GetUpperBound(0); ++cx)
    {
        for (var cy = 0; cy < CellGrid.GetUpperBound(1); ++cy)
        {
            var neighborsneighborList = GetNeighborList(cx, cy);
            var len = neighborsneighborList.Length;

            if ((IsAlive(cx, cy)))
            {
                if ((neighborsneighborList.Length > MAX_NEIGHBOR_COUNT) || (neighborsneighborList.Length < MIN_NEIGHBOR_COUNT))
                    KillCell(cx, cy);
                else
                    KeepCellAlive(cx, cy);
            }
            else
            {
                if ((neighborsneighborList.Length ==3))
                {
                    KeepCellAlive(cx, cy);
                }
            }
        }
    }
}

public void ApplySurvival()
{
    for (var cx = 0; cx < CellGrid.GetUpperBound(0); ++cx)
    {
        for (var cy = 0; cy < CellGrid.GetUpperBound(1); ++cy)
        {
            var cell = CellGrid[cx, cy];
            if (cell != null)
            {
                cell.IsAlive = cell.WillSurvive;
            }
        }
    }
}

I decided to make the UI in XNA. I have an idea on how to visualize a cell changing state and I can more easily implement it using a 3D API. Since the "world" of the Game of Life is in a grid I'm going to represent the state of a cell with a square that is either black (if the cell is not alive) or some other color (if the cell is alive). I'm drawing the squares by rendering vertices instead of writing sprites. This give me greater liberty in changing the color or shape of a cell. The following will draw one of the squares.

const int _squareWidth = 5;
const int _squareHeight = 5;
private const int _offsetX = -_squareWidth*30;
private const int _offsetY = -_squareHeight*18;

void DrawSquare(int x, int y, Color c)
{
    _vertices[0].Color = c;
    _vertices[1].Color = c;
    _vertices[2].Color = c;
    _vertices[3].Color = c;

    _vertices[0].Position.X = _offsetX + _squareWidth * x + _squareWidth;
    _vertices[0].Position.Y = _offsetY + _squareHeight * y;

    _vertices[1].Position.X = _offsetX + _squareWidth*x;
    _vertices[1].Position.Y = _offsetY + _squareHeight*y;

    _vertices[2].Position.X = _offsetX + _squareWidth * x + _squareWidth;
    _vertices[2].Position.Y = _offsetY + _squareHeight * y + _squareHeight;

    _vertices[3].Position.X = _offsetX + _squareWidth * x;
    _vertices[3].Position.Y = _offsetY + _squareHeight * y +_squareHeight;

    graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, _vertices.Length-2);     
}

With the ability to draw the square completed it's easy to iterate through the collection of cells and render them to the screen according to whether or not they are alive.

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);

    var effect = new BasicEffect(GraphicsDevice);
    effect.World = _world;
    effect.Projection = _projection;
    effect.View = _view;
    effect.VertexColorEnabled = true;
    effect.TextureEnabled = false;
    effect.LightingEnabled = false;

    foreach(var effectPass in effect.CurrentTechnique.Passes)
    {
        effectPass.Apply();
        for (int cx = 0; cx < 60;++cx )
        {
            for(int cy=0;cy<36;++cy)
            {
                Color c = _community.IsAlive(cx, cy) ? Color.Red : Color.Black;
                DrawSquare(cx,cy,c);
            }
        }                    
    }
    base.Draw(gameTime);
}

I manually populated the grid and let it run. I'm happy to say it seems to be working. Now onto designing and making the user interface.

Screen Shot

What's Coming to Windows Phone in 2011?

With more that 13,000 applications in their Marketplace Microsoft came out on stage today to make some new announcements about what's coming to Windows Phone 7. We'll see a major upgrade on all Windows Phone devices by the end of the year and developers are getting access to a lot of new APIs enabling new application scenarios.

Here is a summary list of the new features.
  • Multitasking - in addition to faster application switching multitasking will allow applications to continue processing in the background.
  • Live Tile Functionality Enhancements -
  • Sensor Library Enhancements - You'll have enhanced access to the sensor library and
      Access to the camera and compass-! Reality augmentation is possible!
    • Sockets - This needs no explanation
    • Database -
    • IE9 - with hardware acceleration
    • Silverlight+XNA - you can use Silverlight and XNA in the same application
    • Twitter in the People Hub
    • Background Transfers
    • Profile
    • Silverlight 4 Runtime
    Several new countries are being added to the Marketplace. This brings up the total count from 17 to 35. The new countries are listed below with *.
    • Australia
    • Austria
    • Belgium
    • Brazil*
    • Canada
    • Chile*
    • Columbia*
    • Czech Republic*
    • Denmark*
    • Finland*
    • France
    • Germany
    • Greece*
    • Hong Kong
    • Hungary*
    • India*
    • Ireland
    • Italy
    • Japan*
    • Mexico
    • Netherlands*
    • New Zealand
    • Norway*
    • Poland*
    • Portugal*
    • Russia*
    • Singapore
    • South Africa*
    • South Korea*
    • Spain
    • Sweden*
    • Switzerland
    • Taiwan*
    • UK
    • USA /

Streaming from the Microphone to IsolatedStorage

Last week I posted a sample voice recorder on CodeProject. The application would buffer the entire recording in memory before writing it to a file. A rather astute reader asked me what would happen if the user let the recording go long enough to fill up memory. The answer to that question is the application would crash due to an exception being trhown when it fails to allocate more memory and all of the recordingwould be lost. I had already been thinking of a sime reusable solution for doing this but I also offered to the user the following code sample to handle streaming directly to IsolatedStorage.
My two goals in writing it were to keep it simple and keep it portable/reusable. As far as usage goes I can't think of any ways to make it any easier.
   //To start a recording
   StreamingRecorder myRecorder  = new StreamingRecorder();
   myRecorder.Start("myFileName");

  //To stop a recording();
  myRecorder.Stop();
After the code has run you will have a WAVE file with a proper header ready to be consumed by a SoundEffect, MediaElement, or whatever it is that you want to do with it.
In implementing this I must say that I have a hiher appreciation for how MediaElement's interface is designed. The starting and stopping process are not immediate. In otherwords when you call Start() or Stop() it is not until a few moments later that the request is fully processed. Because of the asynchronous nature of these processes I've implemented the event RecordingStateChanged and the property RecordingState so that I would know when a state change was complete. If you are familiar with the media element class then your recognize the similarity of this pattern.
I'll go into further details on how this works along with implemeting some other functionality (such as a Pause method) in a later post. But the code is in a working state now so I'm sharing it. :-)

Here is the source:
public class StreamingRecorder :INotifyPropertyChanged,  IDisposable
{


    object SyncLock = new object();

    private Queue<MemoryStream> _availablBufferQueue;        
    private Queue<MemoryStream> _writeBufferQueue;

    private int _bufferCount;
    private byte[] _audioBuffer;

    //private int _currentRecordingBufferIndex;
        

    private TimeSpan _bufferDuration;
    private int _bufferSize;
    private Stream _outputStream;
    private Microphone _currentMicrophone;
    private bool _ownsStream = false;
    private long _startPosition;

    

    public  StreamingRecorder(TimeSpan? bufferDuration = null, int bufferCount=2)
    {
        _bufferDuration = bufferDuration.HasValue ? bufferDuration.Value : TimeSpan.FromSeconds(0);
        _bufferCount = bufferCount;
        _currentMicrophone= Microphone.Default;   
    }

    private MemoryStream CurrentBuffer
    {
        get; set;
    }

    public void Start(string fileName)
    {
        var isoStore = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication();
        var targetFile = isoStore.OpenFile(fileName, FileMode.Create);
        Start(targetFile, true);
    }

    public void Start(Stream outputStream, bool ownsStream=false)
    {
        _outputStream = outputStream;
        _ownsStream = ownsStream;
        _startPosition = outputStream.Position;

        Size = 0;

        //Create our recording buffers
        _availablBufferQueue = new Queue<MemoryStream>();
        _writeBufferQueue = new Queue<MemoryStream>();
        _audioBuffer = new byte[_currentMicrophone.GetSampleSizeInBytes(_currentMicrophone.BufferDuration)];
        _bufferSize = _currentMicrophone.GetSampleSizeInBytes(_bufferDuration + _currentMicrophone.BufferDuration);
        for (var i = 0; i < _bufferCount; ++i)
        {
            _availablBufferQueue.Enqueue(new MemoryStream(_bufferSize));
        }

        CurrentBuffer = _availablBufferQueue.Dequeue();
        //Stuff a bogus wave header in the output stream as a space holder.
        //we will come back and make it valid later. For now the size is invalid.
        //I could have just as easily stuffed any set of values here as long as 
        //the size of those values equaled 0x2C
        WaveHeaderWriter.WriteHeader(CurrentBuffer, -1, 1, _currentMicrophone.SampleRate);
        Size += (int)CurrentBuffer.Position;

        //Subscribe to the Microphone's buffer ready event and start listening.
        _currentMicrophone.BufferReady += new EventHandler<EventArgs>(_currentMicrophone_BufferReady);            
        _currentMicrophone.Start();
    }


    void _currentMicrophone_BufferReady(object sender, EventArgs e)
    {
        _currentMicrophone.GetData(_audioBuffer);
        //If the recorder is paused (not implemented) then don't add this audio chunk to
        // the output. If HasFlushed is set then the recording is actually ready to shut
        //down and we shouldn't accumulate anything more. 
        if ((CurrentState != RecordingState.Paused))
        {
            //Append the audio chunk to our current buffer
            CurrentBuffer.Write(_audioBuffer, 0, _audioBuffer.Length);
            //Increment the size of the recording.
            Size += _audioBuffer.Length;
            //If the buffer is full or if we are shutting down then we need to submit
            //the buffer to be written to the output stream.
            if ((CurrentBuffer.Length > _bufferSize)||(CurrentState==RecordingState.Stopping))
            {

                SubmitToWriteBuffer(CurrentBuffer);
                //If we were shutting down then set a flag so that it is known that the last audio
                //chunk has been written. 
                if (CurrentState == RecordingState.Stopping)
                {
                    _currentMicrophone.Stop();
                    _currentMicrophone.BufferReady -= _currentMicrophone_BufferReady;
                }
                CurrentBuffer = _availablBufferQueue.Count > 0 ? _availablBufferQueue.Dequeue() : new MemoryStream();
            }
        }
    }

                

    // CurrentState - generated from ObservableField snippet - Joel Ivory Johnson

    private RecordingState _currentState;
    public RecordingState CurrentState
    {
        get { return _currentState; }
        set
        {
            if (_currentState != value)
            {
                _currentState = value;
                OnPropertyChanged("CurrentState");
                OnRecordingStateChanged(value);
            }
        }
    }
    //-----


    void WriteData(object a )
    {

        lock(SyncLock)
        {                
            while (_writeBufferQueue.Count > 0)
            {
                var item = _writeBufferQueue.Dequeue();
                var buffer = item.GetBuffer();
                _outputStream.Write(buffer, 0,(int) item.Length);
                item.SetLength(0);

                _availablBufferQueue.Enqueue(item);

                if (CurrentState == RecordingState.Stopping)
                {
                    //Correct the information in the wave header. After it is
                    //written set the file pointer back to the end of the file.
                    long prePosition = _outputStream.Position;
                    _outputStream.Seek(_startPosition, SeekOrigin.Begin);
                    WaveHeaderWriter.WriteHeader(_outputStream,Size-44,1,_currentMicrophone.SampleRate);
                    _outputStream.Seek(prePosition, SeekOrigin.Begin);
                    _outputStream.Flush();
                    if (_ownsStream)
                        _outputStream.Close();
                    CurrentState = RecordingState.Stopped;
                }
            }
        }
    }

    void SubmitToWriteBuffer(MemoryStream target)
    {
        //Do the writing on another thread so that processing on this thread can continue. 
        _writeBufferQueue.Enqueue(target);
        ThreadPool.QueueUserWorkItem(new WaitCallback(WriteData));
    }

    public void Pause()
    {
        if ((CurrentState != RecordingState.Paused) && (CurrentState != RecordingState.Recording))
        {
            throw new Exception("you can't pause if you are not recording");
        }
        CurrentState = RecordingState.Paused;
    }

    public void Stop()
    {
        CurrentState = RecordingState.Stopping;
    }


    // Size - generated from ObservableField snippet - Joel Ivory Johnson

    private int  _size;
    public int Size
    {
        get { return _size; }
        set
        {
            if (_size != value)
            {
                _size = value;
                OnPropertyChanged("Size");
            }
        }
    }
    //-----

    public long RemainingSpace
    {
        get
        {                
            return System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication().AvailableFreeSpace;
        }
    }

    public TimeSpan RecordingDuration
    {
        get
        {
            return _currentMicrophone.GetSampleDuration((int)Size);
        }
    }

    public TimeSpan RemainingRecordingTime
    {
        get
        {
            return _currentMicrophone.GetSampleDuration((int)RemainingSpace);
        }
    }

    //-------

    public event EventHandler<RecordingStateChangedEventArgs> RecordingStateChanged;
    protected void OnRecordingStateChanged(RecordingState newState)
    {
        if(RecordingStateChanged!=null)
        {
            RecordingStateChanged(this, new RecordingStateChangedEventArgs(){NewState = newState});
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public void Dispose()
    {
        Stop();
    }
}

 

Voice Memo source for WP7

This question keeps coming up in the forums so I decided to put the application together and make it publically available. If you head over to CodeProject you'll find a small article that I uploaded on making a voice memo application on Windows Phone 7. Among other things is demonstrates how to convert the raw recording bytes to a proper wave file, simple serialization, and a few other tid bits. For the sake of the article I did send the code through certification. 

However the application looks ugly right now. I've got a graphic artist that I'll be paying to design the UI for me and since I'm paying her for this I've decided not to include the graphic assets that she is producing in the code that I'm gicing away for free. 

There's no obligations attached to the code. But if you use it in your own products I would appreciate a heads up just so that I know where it's being used. 

Share photos on twitter with Twitpic

More than enough?

When it comes to computer resources I've always had this philosiphy that you don't have enough until you have more than enough. That philosiphy worked out fine for me in the desktop days when the cost in space and power consumption were unnoticable. But now with all my machines (save one) being portables, it makes a big difference. 

The laptop I use for work is a Dell Precision M6400. I received the machine with 4 gigs of ram and a measley 160 gig hard drive. The machine had empty memory slots and an empty drive slot. So I bumped the ram up to 12 gigs and added a second (500 gig) drive.  Adding the RAM solved a performance problem I was having; 4 gigs just wasn't enough for the virtual machines I needed to run and for multiple instances of Visual Studio. But now that I have the RAM the machine runs much hotter. When it comes out of the hibernate state I've got to wait for a 12 gig hibernation file to open. If I put it in standby it won't last a full day before the battery dies. With the extra drive and the RAM together its hard to make this machine last much longer than 20 minutes on battery power. I didn't think I'd ever say this but I don't plan to ever max this machins RAM or storage out in light of the tradeoffs of doing so. I'm going to take the original hard drive out.

The lesson I learned from this is that everything has it's cost, even having more than enough. 

Changing the Background on a Button

A recent question in the Windows Phone Development Forums asking for the XAML to display a background image in a button when it is pressed. Generating the XAML to do this is pretty easy (if you know how!). While the request was for the XAML for doing this I thought the instructions for producing the XAML to do this are of great value.

Open expressions blend and start a new project. In your project add a new button. Right-click on the button and select "Edit template"->"Edit Copy" You will be prompted for the name of the new button style that we are creating (call it what you want) and whether the template will be defined in the document (page) or defined globally for the application. If you only plan on using the style in one page then it's fine to define it within the document. In general you are probably going to use your style on more than one page. In either case for this exercise select the option to create the style within the document.

Switch to code view so that we can edit the XAML. Towards the top of your document you will see a style defined with the name you gave to it. Scroll down within the style until you find the construct with a ContentControl enveloped within a Border element. It will look like the following.

<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" 
            BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" 
            CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">								
     <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" 
                             Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" 
                             HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
                             Padding="{TemplateBinding Padding}" 
                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>

We are going to make most our changes here. We need to place an image within this border element. It is going to be behind the content and so it will have to appear before the ContentControl element. The Border element can only have one child so we will need to make a Grid the Border's direct child and then place the Image element and ContentControl element within the Grid. The Image attribute will need to have a name and it will need to have its Opacity set to zero since the image usually will not be visible. The resulting XAML will look like the following.

<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">								
	<Grid>
		<Image x:Name="BackgroundImage" Source="/Background.png" 
                            Stretch="Fill" VerticalAlignment="Bottom" Opacity="0" />
		<ContentControl x:Name="ContentContainer" 
                                       ContentTemplate="{TemplateBinding ContentTemplate}" 
                                       Content="{TemplateBinding Content}" 
                                       Foreground="{TemplateBinding Foreground}" 
                                       HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                       Padding="{TemplateBinding Padding}" 
                                       VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
	</Grid>
</Border>

Almost done! There's only a couple of things left. We want the image to be visible when the user is pressing the button. Scroll up within the template and you'll find several VisualStateGroup elements defined. This area contains the changes and transitions that need to occur on the button when certain things happen such as the button going to a disabled state, loosing or gaining focus, and so on. We are interested in changes that occur in the pressed state. Within the VisualState named Press is a StoryBoard containing several animations. We need to add one more animation that changes the opacity of our button. As the last child of the StoryBoard element add the following.

<DoubleAnimation To="100" Duration="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundImage" />

Now if you run the project you'll see the image show up in the button any time you press it, and disappear when ever you release it. Now how do you use this in another project? If you copy the Style element from this project and place it as a resource within your other projects it will be readily available for you (just make sure that your image source also appears in your target project). The style can be applied to a button through setting the buttons style.

<Button  Style="{StaticResource MyCustomButton}"/>

If you want to see what my entire style looks like here it is.

<Style x:Key="MyCustomButton" TargetType="Button">
	<Setter Property="Background" Value="Transparent"/>
	<Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
	<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
	<Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
	<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
	<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
	<Setter Property="Padding" Value="10,3,10,5"/>
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="Button">
				<Grid Background="Transparent">
					<VisualStateManager.VisualStateGroups>
						<VisualStateGroup x:Name="CommonStates">
							<VisualState x:Name="Normal"/>
							<VisualState x:Name="MouseOver"/>
							<VisualState x:Name="Pressed">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
										<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
									</ObjectAnimationUsingKeyFrames>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
										<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
									</ObjectAnimationUsingKeyFrames>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
										<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
									</ObjectAnimationUsingKeyFrames>
									<DoubleAnimation To="100" Duration="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundImage" />
								</Storyboard>
							</VisualState>
							<VisualState x:Name="Disabled">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
										<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
									</ObjectAnimationUsingKeyFrames>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
										<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
									</ObjectAnimationUsingKeyFrames>
									<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
										<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
					</VisualStateManager.VisualStateGroups>
					<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">								
						<Grid>
							<Image x:Name="BackgroundImage" Source="/Background.png" Stretch="Fill" VerticalAlignment="Bottom" Opacity="0" />
							<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
						</Grid>
					</Border>
					
				</Grid>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
</Style>