2016년 10월 30일 일요일

[잡담] MorphVOX를 이용한 마이크 잡음제거

오버워치를 구매한 김에 마이크도 5만원짜리를 하나 장만했었습니다
그런데 마이크에서 삐~하느 잡음이 사라지지를 않더군요

여기저기 찾아보니 접지를 해야한다느니
비싼 마이크(10만원이상)를 구매해야한다느니 하는 글이 있던데

저는 음질과 상관없이 그저 잡음만 잡아내면 되기에
프로그램에서 답을 찾았습니다




설정에서 Sound Threashold(소리 임계값)을 조정하여 잡음과 외부 소음을 없을 수 있습니다. 일정 이상의 소리가 아니면 나오지 않도록 하는 설정이며 트랙바의 위치로 조정할 수 있습니다.
※임계값에 의해서 목소리의 끝부분이 잘릴 수 있습니다. (스팀에서 부정적 평가에 가면 해당 현상떄문에 불만을 가진 분이 계신 것 같더군요)

Hum Reduction이나 Echo Cancellation은 음질만 낮추고 큰 효과를 못보는 것 같아 끄고 쓰고 있습니다



이퀄라이저에서 가장 오른쪽에 있는 8K와 16K를 가장 밑으로 낮춥니다.
이렇게 해서 고음의 삐~하는 소리를 어느정도 없앨 수 있는 것 같습니다.


원래는 목소리를 다른 목소리(여자, 개, 로봇 등)로 변환하는 프로그램이지만
마땅히 실시간 잡음제거 프로그램이 보이지 않아 이 프로그램을 사용하게 되었네요

2016년 10월 23일 일요일

[C#, Reflection] 직렬화를 자동화하기 (Automatical Serialization)

도입


직렬화는 클래스를 저장하고 불러오기에 편리한 도구지만

많은 프로퍼티와 많은 클래스들을 직렬화(Serialization)하려면

직렬화할 멤버 하나당 2줄의 코드를 쓸 필요가 있습니다

또한 코드를 일일이 쓰다보니 잘못 써서 버그가 생길 염려도 있지요

그렇기에 리플렉션을 이용하여 자동화하는 것이 필요합니다




SerializationHelper

using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace CodeGenerater.Example
{
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public sealed class SerializationTargetAttribute : Attribute
    {
    }
    public static class SerializationHelper
    {
        public static void Serialize(object Instance, SerializationInfo Info)
        {
            foreach (dynamic each in GetTarget(Instance))
                if (each is FieldInfo)
                    Info.AddValue(each.Name, each.GetValue(Instance), each.FieldType);
                else if (each is PropertyInfo)
                    Info.AddValue(each.Name, each.GetValue(Instance), each.PropertyType);
        }
        public static void Deserialize(object Instance, SerializationInfo Info)
        {
            foreach (dynamic each in GetTarget(Instance))
                if (each is FieldInfo)
                    each.SetValue(Instance, Info.GetValue(each.Name, each.FieldType));
                else if (each is PropertyInfo)
                    each.SetValue(Instance, Info.GetValue(each.Name, each.PropertyType));
        }
        static IEnumerable<MemberInfo> GetTarget(object Instance)
        {
            return from q in Instance.GetType().GetMembers(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                   where q.GetCustomAttribute<SerializationTargetAttribute>() != null
                   select q;
        }
    }
}
cs

직렬화를 자동화하기 위한 클래스입니다

Serialize, Deserialize 함수에 있는 dynamic 키워드는 4.0버전부터 가능하므로

만약 그 이전의 버전을 사용하고 계실경우 아래와 같이 쓰시면 됩니다

public static void Serialize(object Instance, SerializationInfo Info)
{
    foreach (var each in GetTarget(Instance))
        if (each is FieldInfo)
        {
            FieldInfo F = each as FieldInfo;
            Info.AddValue(F.Name, F.GetValue(Instance), F.FieldType);
        }
        else if (each is PropertyInfo)
        {
            PropertyInfo P = each as PropertyInfo;
            Info.AddValue(P.Name, P.GetValue(Instance), P.PropertyType);
        }
}
cs





Example

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace CodeGenerater.Example
{
    [Serializable]
    class Program : ISerializable
    {
        #region Serializaion
        public void GetObjectData(SerializationInfo Info, StreamingContext Context)
        {
            SerializationHelper.Serialize(this, Info);
        }
        Program(SerializationInfo Info, StreamingContext Conmtext)
        {
            SerializationHelper.Deserialize(this, Info);
        }
        #endregion
        #region Constructor
        public Program()
        {
        }
        #endregion
        #region Field
        [SerializationTarget]
        int PrivateField;
        #endregion
        #region Property
        [SerializationTarget]
        public int PublicProperty
        {
            set;
            get;
        }
        [SerializationTarget]
        public int HalfPublicProperty
        {
            private set;
            get;
        }
        [SerializationTarget]
        int PrivateProperty
        {
            set;
            get;
        }
        #endregion
        #region Method
        static void Main(string[] args)
        {
            var T = new Program();
            int R_PrivateProperty, R_HalfPublicProperty, R_PublicProperty, R_PrivateField;
        
            #region Initialize
            Random R = new Random();
            
            T.PrivateProperty = R_PrivateProperty = R.Next();
            T.HalfPublicProperty = R_HalfPublicProperty = R.Next();
            T.PublicProperty = R_PublicProperty = R.Next();
            T.PrivateField = R_PrivateField = R.Next();
            #endregion
            using (MemoryStream Stream = new MemoryStream())
            {
                #region Serialization
                BinaryFormatter F = new BinaryFormatter();
                F.Serialize(Stream, T);
                #endregion
                #region Init
                T = null;
                Stream.Position = 0;
                #endregion
                #region Deserialization
                T = (Program)F.Deserialize(Stream);
                #endregion
                #region Check
                bool TestSuccess =
                    T.PrivateProperty == R_PrivateProperty &&
                    T.HalfPublicProperty == R_HalfPublicProperty &&
                    T.PublicProperty == R_PublicProperty &&
                    T.PrivateField == R_PrivateField;
                if (TestSuccess)
                    Console.WriteLine("Success");
                else
                    Console.WriteLine("Fail");
                #endregion
            }
        }
        #endregion
    }
}
cs

간단하게 작동여부를 확인할 수 있는 예제입니다





주의할 점

프로퍼티를 직렬화할때 Setter와 Getter가 한정자와 상관없이 모두 존재해야합니다

Setter와 Getter 중 하나가 존재하지 않으면 쓰거나 읽을때 오류가 납니다





Archive File

2016년 8월 5일 금요일

[유용한 자료] 값을 누적하면서 평균을 구해야할 때 간단화하는 방법

도입 - 필요성


어떤 값의 집합이 있다고 하고

그 값들의 평균값이 아래와 같다고 할 때
평균값을 지속적으로 새로 구해야할 경우가 있습니다

예를 들어,
어떤 함수의 평균 실행 시간을 계속해서 구해야할 때
위의 방법으로 매번 평균을 구한다면
함수가 실행될때마다 그 실행 시간을 리스트에 저장할 필요성이 생기죠

한두번은 괜찮지만 만약 몇 만번 이상 실행한다면
리스트에 일일이 저장하는 것만으로도 컴퓨터에 부담을 주게 됩니다

이 글에서는 리스트에 일일이 저장하지 않고도
새로운 평균값을 구하는 방법에 대하여 설명합니다

해결 - 풀이


n 번째 평균이 Average(n)이라 한다면
n+1 번째 평균은 Average(n+1)이 됩니다

Average(n) 에서 f(n+1) 을 더하면 Average(n+1) 이 된다한다면 f(n+1) 은 아래와 같습니다

이 때 식에서 반복적으로 나오는 부분을 g(n) 이라 하면

f(n+1) 을 아래와 같이 표현할 수 있습니다


결국 Average(n+1) 은 아래와 같이 계산할 수 있는 것이죠

결론 - 정리


어떤 평균값 Average(n) 에서 새 값이 추가된 Average(n+1) 을 구하기 위해서는

1. 이전 평균값
2. 새 값
3. 새 값을 포함한 값의 갯수

이 세가지만 알면 된다는 것을 알 수 있습니다

코드로 작성하면


이렇게 간단하게 표현할 수 있습니다

부디 유용하게 써주세요 ㅇㅅㅇ!!