<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>공부중</title>
    <link>https://hannom.tistory.com/</link>
    <description>다시 보기 위해 공부한 내용을 정리해 두는 곳.</description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 10:20:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>곤란</managingEditor>
    <image>
      <title>공부중</title>
      <url>https://t1.daumcdn.net/cfile/tistory/1428144850BD8D8120</url>
      <link>https://hannom.tistory.com</link>
    </image>
    <item>
      <title>임의의 원 범위 안에서 스폰하기. - 2</title>
      <link>https://hannom.tistory.com/248</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이거 카테고리와 제목을 뭐라 지을까 하다가 여기에 그냥 적어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이 내용으로 글을 쓴 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/185&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hannom.tistory.com/185&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746544028509&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[project_PQ]-[Unity3D] 임의의 원 범위 안에서 스폰하기.&quot; data-og-description=&quot;일단 위의 스크린샷은 내가 멍청하게도&amp;nbsp;Collision충돌로 알아서 밀어내겠지 하고 안일한 생각을 가지다가&amp;nbsp;is Trigger를 체크한것을&amp;nbsp;잊어버려서 결국엔 겹치는 현상을 보여주고 있다. -_-&amp;nbsp;실제 게임&quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/185&quot; data-og-url=&quot;https://hannom.tistory.com/185&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/g98NX/hyYMTuNXVB/kQIfNLj9ElpLsPOAGaehL0/img.png?width=800&amp;amp;height=826&amp;amp;face=0_0_800_826,https://scrap.kakaocdn.net/dn/bNenF2/hyYPnhf7Au/tHckYCkjJZbAOw3krM9gF1/img.png?width=800&amp;amp;height=826&amp;amp;face=0_0_800_826,https://scrap.kakaocdn.net/dn/dbYPFA/hyYMXRviW6/3zZieGbjPM9zzN2fheEBy1/img.png?width=916&amp;amp;height=946&amp;amp;face=0_0_916_946&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/185&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/185&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/g98NX/hyYMTuNXVB/kQIfNLj9ElpLsPOAGaehL0/img.png?width=800&amp;amp;height=826&amp;amp;face=0_0_800_826,https://scrap.kakaocdn.net/dn/bNenF2/hyYPnhf7Au/tHckYCkjJZbAOw3krM9gF1/img.png?width=800&amp;amp;height=826&amp;amp;face=0_0_800_826,https://scrap.kakaocdn.net/dn/dbYPFA/hyYMXRviW6/3zZieGbjPM9zzN2fheEBy1/img.png?width=916&amp;amp;height=946&amp;amp;face=0_0_916_946');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[project_PQ]-[Unity3D] 임의의 원 범위 안에서 스폰하기.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;일단 위의 스크린샷은 내가 멍청하게도&amp;nbsp;Collision충돌로 알아서 밀어내겠지 하고 안일한 생각을 가지다가&amp;nbsp;is Trigger를 체크한것을&amp;nbsp;잊어버려서 결국엔 겹치는 현상을 보여주고 있다. -_-&amp;nbsp;실제 게임&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에 이 내용으로 글을 썻는데 어쩌다보니 문제가 있던 내용이었던걸 GPT와 대화하다가 깨닫게 되어서 적어보는 글이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 지금은 언리얼을 다루고 있으므로 어떤 문제가 있는지 언리얼로 출력 결과를 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2088&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccLtYg/btsNK3hzXaT/gbp9sxGhs3b346lYqOfPF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccLtYg/btsNK3hzXaT/gbp9sxGhs3b346lYqOfPF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccLtYg/btsNK3hzXaT/gbp9sxGhs3b346lYqOfPF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccLtYg%2FbtsNK3hzXaT%2Fgbp9sxGhs3b346lYqOfPF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3840&quot; height=&quot;2088&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2088&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 글을 통해서 저번 글에 적은 코드를 사용해 출력했을경우 반쪽짜리의 결과만 얻을 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 코드를 보자 아래는 이전에 작성했던 코드다&lt;/p&gt;
&lt;pre id=&quot;code_1746544278617&quot; class=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;    public Vector3 RandomSphereInPoint( float radius )     
    {         
    	// xz 바닥 평면이니까         
        float x = Random.Range(-1.0f, 1.0f);         	
        float temp = Mathf.Pow(1.0f, 2) - Mathf.Pow(x, 2);         
        float z = Mathf.Sqrt(temp);          
        return (new Vector3(x, 0.0f, z) * Random.Range(0.0f, radius)) 
        		+ new Vector3(transform.position.x, 0.0f, transform.position.z);     
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://hannom.tistory.com/185&quot;&gt;https://hannom.tistory.com/185&lt;/a&gt; [공부중:티스토리]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원의 중심이 (0,0)이고 반지름이 1인 원의 방정식 x^2 + y^2 = 1 임을 이용해서 구한 방법이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x를 먼저 랜덤하게 결정하고 y로 정리해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;y = sqrt(1-x^2) 을 얻게되어 작성한 코드였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 sqrt는 양수의 값만 나오기 때문에 위와같이 반쪽짜리 분포가 되는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결방법은 간단하게 x의 짝궁인 y의 값(유니티에서는 z)을 랜덤하게 양수로 둘지 음수로 둘지 하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2088&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhfcP/btsNL2oK57Z/WY9d4YsIe2aOvaVMFXVMVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhfcP/btsNL2oK57Z/WY9d4YsIe2aOvaVMFXVMVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhfcP/btsNL2oK57Z/WY9d4YsIe2aOvaVMFXVMVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhfcP%2FbtsNL2oK57Z%2FWY9d4YsIe2aOvaVMFXVMVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3840&quot; height=&quot;2088&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2088&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과로 이와 같이 원 안에서 고루 분포되는것을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1746544599250&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	const int32 NumPoints = 500;
	const float Radius = 500.0f;
	const FVector Center = GetActorLocation();
    
	for (int32 i = 0; i &amp;lt; NumPoints; ++i)
	{
		float Distance = FMath::RandRange(0.0f, Radius);

		FVector Point;
		Point.X = FMath::RandRange(-1.0f, 1.0f);

		float temp = FMath::Pow(1.0f, 2) - FMath::Pow(Point.X, 2);

		Point.Y = FMath::Sqrt(temp);
		Point.Z = 500.f;

		Point.X *= Distance;
		Point.Y *= Distance;

		if (FMath::RandBool())
		{
			Point.Y *= -1.0f;
		}

		DrawDebugSphere(GetWorld(), Center + Point, 2.f, 16, FColor::Blue, true);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 언리얼에서 출력한 내용의 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;500번 돌려서 찍어본 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT에게 물어보면 이것도 문제가 있다면서 여러 수정 사항을 말하긴 하지만 당장 사용하기에는 큰 문제는 없어서 여기서 일단 글을 마친다.&lt;/p&gt;</description>
      <category>Programing</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/248</guid>
      <comments>https://hannom.tistory.com/248#entry248comment</comments>
      <pubDate>Wed, 7 May 2025 00:18:31 +0900</pubDate>
    </item>
    <item>
      <title>[UE] BehaviorTree에서 Random으로 Select 해주는 노드 만들어보기(Random Selector)</title>
      <link>https://hannom.tistory.com/247</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/community/learning/tutorials/8JL3/unreal-engine-random-selector-behavior-tree-custom-composite-node&quot;&gt;https://dev.epicgames.com/community/learning/tutorials/8JL3/unreal-engine-random-selector-behavior-tree-custom-composite-node&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 읽고 제가 이해 하도록 정리 하는 글이므로 원글을 바로 보실분은 위 링크로 바로 이동하시면 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼 엔진의 BehaviorTree에서 Composites 에는 기본으로 아래와 같이 3개의 Selector가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;211&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq595K/btsNkNGpwaA/iKSjZwqPrNtEvmoIcdXGd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq595K/btsNkNGpwaA/iKSjZwqPrNtEvmoIcdXGd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq595K/btsNkNGpwaA/iKSjZwqPrNtEvmoIcdXGd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq595K%2FbtsNkNGpwaA%2FiKSjZwqPrNtEvmoIcdXGd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;211&quot; height=&quot;154&quot; data-origin-width=&quot;211&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Selector&lt;br /&gt;왼쪽에서 오른쪽 순서로 자손을 실행.&lt;br /&gt;자손중 하나가 성공하면 실행 중단.&lt;br /&gt;자손이 하나라도 성공하면 Selector도 성공&lt;br /&gt;자손이 모두 실패시 Selector도 실패&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7H8Uy/btsNnpEgb10/QXgrWoty2jUAyieKszqR31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7H8Uy/btsNnpEgb10/QXgrWoty2jUAyieKszqR31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7H8Uy/btsNnpEgb10/QXgrWoty2jUAyieKszqR31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7H8Uy%2FbtsNnpEgb10%2FQXgrWoty2jUAyieKszqR31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;162&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sequence&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽에서 오른쪽 순서로 자손을 실행&lt;br /&gt;자손중 하나가 실패하면 실행 중단&lt;br /&gt;자손이 하나라도 실패하면 Sequence도 실패&lt;br /&gt;자손이 모두 성공해야 Sequence도 성공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nBCl9/btsNnZMqvVL/EqUkoV8Lp0peFjmwRUJoXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nBCl9/btsNnZMqvVL/EqUkoV8Lp0peFjmwRUJoXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nBCl9/btsNnZMqvVL/EqUkoV8Lp0peFjmwRUJoXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnBCl9%2FbtsNnZMqvVL%2FEqUkoV8Lp0peFjmwRUJoXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;346&quot; height=&quot;189&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;189&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Simple Parallel&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 테스크(Task) 노드 하나를 전체 트리와 함께 실행.&lt;br /&gt;메인 테스크가 완료 되면 모드 완료 세팅에 따라서 보조 트리를 중단하고 즉시 완료 되거나 아니면 보조트리가 완료될 때까지 대기.&lt;br /&gt;왼쪽 보라색이 메인테스크, 오른쪽이 보조트리이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/unreal-engine-behavior-tree-node-reference-composites&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/unreal-engine-behavior-tree-node-reference-composites&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세 내용은 위 문서를 참고 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기에 추가 할 수 있는 기본 제공 데코레이터(Decorator)나 기본 제공 서비스(Service)중에는 랜덤으로 선택할 수 있는 혹은 랜덤으로 무언갈 할 수 있는 것들이 없어서 만들어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AHE3K/btsNnILfNtn/oTf4ncLy0Te3OFwbdaWYHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AHE3K/btsNnILfNtn/oTf4ncLy0Te3OFwbdaWYHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AHE3K/btsNnILfNtn/oTf4ncLy0Te3OFwbdaWYHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAHE3K%2FbtsNnILfNtn%2FoTf4ncLy0Te3OFwbdaWYHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1029&quot; height=&quot;565&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어서 Attack1과 Attack2, Smash1과 Smash2가 랜덤하게 선택되어 Task가 실행되었으면 하고 싶어서 이런 글까지 쓰게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 스크린 샷 대로라면 4가지중 하나만 성공시 상위 컴포짓이 성공하는것은&amp;nbsp; Selector 이므로 이것과 비슷하게 꾸며보면 되지 않을까 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Selector는 어떻게 돌아가는지 코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1744788214721&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int32 UBTComposite_Selector::GetNextChildHandler(FBehaviorTreeSearchData&amp;amp; SearchData, int32 PrevChild, EBTNodeResult::Type LastResult) const
{
	// success = quit
	int32 NextChildIdx = BTSpecialChild::ReturnToParent;

	if (PrevChild == BTSpecialChild::NotInitialized)
	{
		// newly activated: start from first
		NextChildIdx = 0;
	}
	else if (LastResult == EBTNodeResult::Failed &amp;amp;&amp;amp; (PrevChild + 1) &amp;lt; GetChildrenNum())
	{
		// failed = choose next child
		NextChildIdx = PrevChild + 1;
	}

	return NextChildIdx;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식의 인덱스를 return해주는 식으로 돌아가고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 먼저 첫번째(0) 부터 돌아가면서 이전 결과가 실패면 다음(+1) 이런식으로 넘어가며 리턴해주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 자식을 다 돌고 나서도 실패 했다면 처음에 넣은 BTSpecialChild::ReturnToParent가 return 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 부분을 적절하게 재구성해서 랜덤한 값으로 return해주면 내가 원하는 Selector가 만들어 질것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에 대해서는 어떤 형님이 튜토리얼로 만들어 두셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/community/learning/tutorials/8JL3/unreal-engine-random-selector-behavior-tree-custom-composite-node&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/community/learning/tutorials/8JL3/unreal-engine-random-selector-behavior-tree-custom-composite-node&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크를 들어가면 코드에 주석까지 친절하게 적어두셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 내용을 한번 보면서 내가 이해를 해보려고한다.&lt;/p&gt;
&lt;pre id=&quot;code_1744789620258&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once
 
#include &quot;CoreMinimal.h&quot;
#include &quot;BehaviorTree/BTCompositeNode.h&quot;
#include &quot;BTComp_SelectorRandom.generated.h&quot;
 
UCLASS()
class ENEMIES_API UBTComp_SelectorRandom : public UBTCompositeNode
{
    GENERATED_BODY()
 
public:
    UBTComp_SelectorRandom(const FObjectInitializer&amp;amp; ObjectInitializer);
 
    virtual void InitializeMemory(UBehaviorTreeComponent&amp;amp; OwnerComp, uint8* NodeMemory, EBTMemoryInit::Type InitType) const override;
    virtual void CleanupMemory(UBehaviorTreeComponent&amp;amp; OwnerComp, uint8* NodeMemory, EBTMemoryClear::Type CleanupType) const override;
    virtual int32 GetNextChildHandler(struct FBehaviorTreeSearchData&amp;amp; SearchData, int32 PrevChild, EBTNodeResult::Type LastResult) const override;
 
private:
    mutable TArray&amp;lt;int32&amp;gt; ExecutedChildren;
    mutable int32 LastSuccessfulChildIdx;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InitializeMemory와 CleanupMemory는 각각 InitializeInSubtree와 CleanupInSubtree에서 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 클래스인 UBTNode까지 올라가도 &quot;// empty in base&quot;&amp;nbsp; 으로 되어있어 적절하게 이곳에서 메모리를 초기화/정리 해주면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744789808384&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UBTComp_SelectorRandom::InitializeMemory(UBehaviorTreeComponent&amp;amp; OwnerComp, uint8* NodeMemory, EBTMemoryInit::Type InitType) const
{
    InitializeNodeMemory&amp;lt;FBTCompositeMemory&amp;gt;(NodeMemory, InitType);
    ExecutedChildren.Empty();
    LastSuccessfulChildIdx = INDEX_NONE;
}
 
void UBTComp_SelectorRandom::CleanupMemory(UBehaviorTreeComponent&amp;amp; OwnerComp, uint8* NodeMemory, EBTMemoryClear::Type CleanupType) const
{
    CleanupNodeMemory&amp;lt;FBTCompositeMemory&amp;gt;(NodeMemory, CleanupType);
    ExecutedChildren.Empty();
    LastSuccessfulChildIdx = INDEX_NONE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 메모리 부분부터 보면 각각&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InitializeNodeMemory&amp;lt;FBTCompositeMemory&amp;gt;(NodeMemory,&amp;nbsp;InitType);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CleanupNodeMemory&amp;lt;FBTCompositeMemory&amp;gt;(NodeMemory,&amp;nbsp;CleanupType);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 작성했는데 이것은 상속받은 UBTCompositeNode에서 각각 저렇게 작성되어 있어서 저렇게 작성한것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 TArray로 선언한 ExecuteChildren과 LastSuccessfulChildIdx를 비워주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아래 코드에는 주석으로 직접 내용을 적어놓았다.&lt;/p&gt;
&lt;pre id=&quot;code_1744789942734&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int32 UBTComp_SelectorRandom::GetNextChildHandler(FBehaviorTreeSearchData&amp;amp; SearchData, int32 PrevChild, EBTNodeResult::Type LastResult) const
{
    int32 NextChildIdx = BTSpecialChild::ReturnToParent;
 
    if (PrevChild == BTSpecialChild::NotInitialized)
    {
        // First execution, choose a random child
        // 첫 번째 실행 시, 임의의 자식을 선택합니다.
        NextChildIdx = FMath::RandRange(0, GetChildrenNum() - 1);
        if (NextChildIdx == LastSuccessfulChildIdx &amp;amp;&amp;amp; GetChildrenNum() &amp;gt; 1)
        {
            // Avoid the last successful child being chosen first if possible
            // 가능하면 마지막으로 성공한 자식이 먼저 선택되지 않도록 합니다.
            NextChildIdx = (NextChildIdx + 1) % GetChildrenNum();
        }
    }
    else
    {
        // Handle last result
        // 마지막 결과를 처리합니다.
        if (LastResult == EBTNodeResult::Succeeded)
        {
            // If last child succeeded, return success and reset
            // 만약 마지막 자식이 성공하면 성공을 반환하고 재설정합니다.
            LastSuccessfulChildIdx = PrevChild;
            ExecutedChildren.Empty();
            return BTSpecialChild::ReturnToParent;
        }
        else if (LastResult == EBTNodeResult::Failed)
        {
            // If last child failed, mark it as executed
            // 마지막 자식이 실패하면 실행됨으로 표시합니다.
            ExecutedChildren.Add(PrevChild);
 
            // If all children have failed, return failure
            // 모든 자식이 실패하면 실패를 반환합니다.
            if (ExecutedChildren.Num() &amp;gt;= GetChildrenNum())
            {
                ExecutedChildren.Empty();
                LastSuccessfulChildIdx = INDEX_NONE;
                return BTSpecialChild::ReturnToParent;
            }
 
            // Choose a new random child that has not been executed yet
            // 아직 실행되지 않은 새로운 임의의 자식을 선택합니다.
            TArray&amp;lt;int32&amp;gt; AvailableChildren;
            for (int32 ChildIdx = 0; ChildIdx &amp;lt; GetChildrenNum(); ++ChildIdx)
            {
                if (!ExecutedChildren.Contains(ChildIdx))
                {
                    AvailableChildren.Add(ChildIdx);
                }
            }
 
            // Choose a random child index from available children
            // 사용 가능한 자식에서 임의의 자식 인덱스를 선택합니다.
            NextChildIdx = AvailableChildren[FMath::RandRange(0, AvailableChildren.Num() - 1)];
        }
    }
 
    return NextChildIdx;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 아주 간단하게 Random함수를 이용해서 값을 return해주면 되는것이 아니냐? 라고 생각 할 수 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게되어도 실행은 되지만 만일 선택받은 자식이 실패한 경우 해당 Selector의 자식에 있는 다른 Task가 실행되지 않고 실패처리 되므로 주의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing/UnrealEngine</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/247</guid>
      <comments>https://hannom.tistory.com/247#entry247comment</comments>
      <pubDate>Wed, 16 Apr 2025 16:57:40 +0900</pubDate>
    </item>
    <item>
      <title>[UE] Editor에서 SeamlessTravel이 안되는 문제.</title>
      <link>https://hannom.tistory.com/246</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;작업을 하다보면 역시 Editor에서 작업을 많이 하게 되는데 여기서 SeamlessTravel이 동작을 안하는 문제가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1741467421736&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ATestGameModeBase::ATestGameModeBase(const FObjectInitializer&amp;amp; ObjectInitializer) :
	Super(ObjectInitializer)
{
	// ....
	bUseSeamlessTravel = true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;GameMode에 있는 bUseSeamlessTravel을 true로 해놓아도 에디터에서 동작하지 않는 문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT와 열심히 씨름하다가 답을 못내놓는걸 보고 답답해서 결국 내부 코드를 한번 봤다.&lt;/p&gt;
&lt;pre id=&quot;code_1741467560153&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void AGameModeBase::ProcessServerTravel(const FString&amp;amp; URL, bool bAbsolute)
{
#if WITH_SERVER_CODE

	// 생략...

	// Use game mode setting but default to full load screen if the server has been up for a long time so that TimeSeconds doesn't overflow and break everything
	bool bSeamless = (bUseSeamlessTravel &amp;amp;&amp;amp; GetWorld()-&amp;gt;TimeSeconds &amp;lt; 172800.0f); // 172800 seconds == 48 hours

	// 생략...
	}
#endif // WITH_SERVER_CODE
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UWorld::ServerTravel의 내부에 GameMode-&amp;gt;ProcessServerTravel을 호출해주는데 여기 내부를 보면 먼저 GameMode에 있는 bUseSeamlessTravel을 조건으로 본다(뒤에 시간도 보지만..) 일단 여기까지는 문제없이 bSeamless가 true로 돌아간다.&lt;/p&gt;
&lt;pre id=&quot;code_1741467762165&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void AGameModeBase::ProcessServerTravel(const FString&amp;amp; URL, bool bAbsolute)
{
#if WITH_SERVER_CODE
	// 생략...
	bool bSeamless = (bUseSeamlessTravel &amp;amp;&amp;amp; GetWorld()-&amp;gt;TimeSeconds &amp;lt; 172800.0f); // 172800 seconds == 48 hours
	// 생략...
    
   	// There are some issues with seamless travel in PIE, so fall back to hard travel unless it is supported
	if (World-&amp;gt;WorldType == EWorldType::PIE &amp;amp;&amp;amp; bSeamless &amp;amp;&amp;amp; !FParse::Param(FCommandLine::Get(), TEXT(&quot;MultiprocessOSS&quot;)))
	{
		if (!UE::GameModeBase::Private::bAllowPIESeamlessTravel)
		{
			UE_LOG(LogGameMode, Warning, TEXT(&quot;ProcessServerTravel: Seamless travel is disabled in PIE, set net.AllowPIESeamlessTravel=1 to enable.&quot;));
			bSeamless = false;
		}
	}

	// 생략...
    
	if (bSeamless)
	{
		World-&amp;gt;SeamlessTravel(World-&amp;gt;NextURL, bAbsolute);
		World-&amp;gt;NextURL = TEXT(&quot;&quot;);
	}
	else
	{
		// Switch immediately if not networking.
		if (NetMode != NM_DedicatedServer &amp;amp;&amp;amp; NetMode != NM_ListenServer)
		{
			World-&amp;gt;NextSwitchCountdown = 0.0f;
		}

		GEngine-&amp;gt;IncrementGlobalNetTravelCount();
		GEngine-&amp;gt;SaveConfig();
	}
#endif // WITH_SERVER_CODE
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 bSeamless가 ture였지만 중간에 PIE에는 문제가 있다는 주석이 있다.. 무슨 문제인지는 모르겠지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 동작하도록 하려면 아래 로그를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;ProcessServerTravel: Seamless travel is disabled in PIE, set net.AllowPIESeamlessTravel=1 to enable.&lt;/b&gt;&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ProcessServerTravel:&amp;nbsp;PIE에서&amp;nbsp;원활한&amp;nbsp;이동이&amp;nbsp;비활성화되어&amp;nbsp;있으므로&amp;nbsp;net.AllowPIESeamlessTravel=1을&amp;nbsp;설정하여&amp;nbsp;활성화합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고한다 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 if문 조건에 빠져서 bSeamless가 false가 되었고 아래 if (bSeamless)에 들어가지 못한것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주석에 나온대로 설정을 하자면 &lt;b&gt;DefaultEngin.ini&lt;/b&gt;파일에서 아래와같이 추가해주면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1741468112068&quot; class=&quot;vbnet&quot; data-ke-language=&quot;vbnet&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[SystemSettings]
net.AllowPIESeamlessTravel=1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DefaultEngine.ini을 수정하고 싶지 않은경우에는 console에 명령어를 치면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KC8cB/btsMEMOsSLn/nafCut8UJmf6vhuCNbhMt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KC8cB/btsMEMOsSLn/nafCut8UJmf6vhuCNbhMt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KC8cB/btsMEMOsSLn/nafCut8UJmf6vhuCNbhMt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKC8cB%2FbtsMEMOsSLn%2FnafCut8UJmf6vhuCNbhMt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;174&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;net.AllowPIESeamlessTravel true&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적절히 필요할때마다 콘솔 명령어를 치면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://forums.unrealengine.com/t/seamless-travel-with-play-in-editor/394250/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://forums.unrealengine.com/t/seamless-travel-with-play-in-editor/394250/20&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741468492276&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Seamless Travel with Play in Editor&quot; data-og-description=&quot;In UE5, you can set &amp;ldquo;net.AllowPIESeamlessTravel true&amp;rdquo; in the console to enable seamless travel in PIE.&quot; data-og-host=&quot;forums.unrealengine.com&quot; data-og-source-url=&quot;https://forums.unrealengine.com/t/seamless-travel-with-play-in-editor/394250/20&quot; data-og-url=&quot;https://forums.unrealengine.com/t/seamless-travel-with-play-in-editor/394250/20&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/erFtt7/hyYmMCN1MF/La8dAHlUBfY39uMXUHFkDK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/IiV6T/hyYnbo4aLR/vuaQ44xg5QQCAFSOEtVbK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://forums.unrealengine.com/t/seamless-travel-with-play-in-editor/394250/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://forums.unrealengine.com/t/seamless-travel-with-play-in-editor/394250/20&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/erFtt7/hyYmMCN1MF/La8dAHlUBfY39uMXUHFkDK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/IiV6T/hyYnbo4aLR/vuaQ44xg5QQCAFSOEtVbK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Seamless Travel with Play in Editor&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In UE5, you can set &amp;ldquo;net.AllowPIESeamlessTravel true&amp;rdquo; in the console to enable seamless travel in PIE.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;forums.unrealengine.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 포럼글&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing/UnrealEngine</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/246</guid>
      <comments>https://hannom.tistory.com/246#entry246comment</comments>
      <pubDate>Sun, 9 Mar 2025 06:10:38 +0900</pubDate>
    </item>
    <item>
      <title>[C/C++] pthread 동기화에 관하여.</title>
      <link>https://hannom.tistory.com/245</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;pthread 동기화에 관하여 글을 적어보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 동기화 내용 하나 없는 아래의 코드를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1732864541297&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;pthread.h&amp;gt;

int g_value = 0;


void *ADD(void* data)
{
	for (int i = 0; i &amp;lt; 100000; i++)
	{
		g_value++;
	}

	return nullptr;
}

int main()
{
	const int threadCount = 2;
	pthread_t pthreads[threadCount];

	for (int i = 0; i &amp;lt; threadCount; i++)
	{
		pthread_create(&amp;amp;pthreads[i], NULL, ADD, nullptr);
	}

	for (int i = 0; i &amp;lt; threadCount; i++)
	{
		pthread_join(pthreads[i], nullptr);
	}
	std::cout &amp;lt;&amp;lt; g_value &amp;lt;&amp;lt; std::endl;

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 2개의 스레드를 생성해서 ADD함수를 각각의 스레드가 돌아가는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기대하는 출력값은 100,000회의 2번이니까 200,000이 되어야 하겠지만...&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNxPgH/btsK1SQelsM/aK1pUdh4jUQlOQYIKwV6Z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNxPgH/btsK1SQelsM/aK1pUdh4jUQlOQYIKwV6Z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNxPgH/btsK1SQelsM/aK1pUdh4jUQlOQYIKwV6Z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNxPgH%2FbtsK1SQelsM%2FaK1pUdh4jUQlOQYIKwV6Z0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;120&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;175&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqdk9A/btsK13xeWFO/udsFDDvmjUv60h6K6kfVc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqdk9A/btsK13xeWFO/udsFDDvmjUv60h6K6kfVc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqdk9A/btsK13xeWFO/udsFDDvmjUv60h6K6kfVc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcqdk9A%2FbtsK13xeWFO%2FudsFDDvmjUv60h6K6kfVc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;175&quot; height=&quot;126&quot; data-origin-width=&quot;175&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxj1U/btsK2uA0hqZ/BzzjmOcGlWcAgn0A3AnaS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxj1U/btsK2uA0hqZ/BzzjmOcGlWcAgn0A3AnaS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxj1U/btsK2uA0hqZ/BzzjmOcGlWcAgn0A3AnaS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkxj1U%2FbtsK2uA0hqZ%2FBzzjmOcGlWcAgn0A3AnaS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;117&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 실행할때마다 값도 다르고 의도한 값인 200,000이 될때도 있겠지만 되지않는 경우도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 저러한 일이 발생하냐면 간단하게 적자면 동기화가 일어나지 않은 경우이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 자세히 풀어보자면&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;타임라인&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;1번 스레드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;2번 스레드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;값 읽기 ( 0 )&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;waiting...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;값 증가 ( 1 )&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;waiting...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;waiting...&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;값 읽기 ( 0 ) -&amp;gt; 아직 쓰지 않았으므로 0으로 읽음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;waiting...&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;값 증가 ( 1 )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;waiting...&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;값 쓰기 ( 1 )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;값 쓰기 ( 1 )&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;....&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;...&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center;&quot;&gt;.....&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;.....&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 스레드가 언제 접근할지도 모르는 상태이고 위의 예시처럼 접근 시점이 겹쳐 쓰기 전에 덮어씌워지기 때문에 기대한 값인 200,000이 되지 않는 경우가 발생하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같은 문제가 발생하지 않도록 동기화를 해주어야 한다. 아래의 코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1732887085838&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;pthread.h&amp;gt;

int g_value = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *ADD(void* data)
{
	for (int i = 0; i &amp;lt; 100000; i++)
	{
		pthread_mutex_lock(&amp;amp;mutex);
		g_value++;
		pthread_mutex_unlock(&amp;amp;mutex);
	}

	return nullptr;
}

int main()
{
	const int threadCount = 2;
	pthread_t pthreads[threadCount];

	for (int i = 0; i &amp;lt; threadCount; i++)
	{
		pthread_create(&amp;amp;pthreads[i], NULL, ADD, nullptr);
	}

	for (int i = 0; i &amp;lt; threadCount; i++)
	{
		pthread_join(pthreads[i], nullptr);
	}
	std::cout &amp;lt;&amp;lt; g_value &amp;lt;&amp;lt; std::endl;


	pthread_mutex_destroy(&amp;amp;mutex);

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동기화 방법중 하나인 &lt;b&gt;뮤텍스(Mutex)&lt;/b&gt;를 사용한 동기화 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤텍스는 커널(운영체제) 영역에서 동작하므로 느릴수 있지만 안정적인 동기화 방법중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;동시에 접근하지 못하도록 막는 상호배제 방식으로 동기화를 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lock / unlock 이름대로 들어갈때 문잠그고 나올때 문따고 이런식으로 이해하면 될듯하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른(?) 방법은 또 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1732891525743&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;pthread.h&amp;gt;
#include &amp;lt;semaphore.h&amp;gt;

int g_value = 0;

sem_t semaphore;

void *ADD(void* data)
{
	for (int i = 0; i &amp;lt; 100000; i++)
	{
		sem_wait(&amp;amp;semaphore);
		g_value++;
		sem_post(&amp;amp;semaphore);
	}

	return nullptr;
}

int main()
{
	sem_init(&amp;amp;semaphore, 0, 1);		// 동시에 1개의 스레드만 접근 가능하도록...

	const int threadCount = 2;
	pthread_t pthreads[threadCount];

	for (int i = 0; i &amp;lt; threadCount; i++)
	{
		pthread_create(&amp;amp;pthreads[i], NULL, ADD, nullptr);
	}

	for (int i = 0; i &amp;lt; threadCount; i++)
	{
		pthread_join(pthreads[i], nullptr);
	}
	std::cout &amp;lt;&amp;lt; g_value &amp;lt;&amp;lt; std::endl;


	sem_destroy(&amp;amp;semaphore);

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 여기서는 단 2개의 스레드만 사용중이지만 init할때 몇개의 스레드가 접근 가능할지 설정 가능하며&lt;/p&gt;
&lt;pre id=&quot;code_1732891693331&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sem_init (sem_t * sem, int pshared, unsigned int value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가운데 pshared가 뭔지 찾아봤는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0c0d0e; text-align: left;&quot;&gt;이 세마포어를 프로세스의 스레드 간에 공유할지, 아니면 프로세스 간에 공유할지 여부를 결정한다는것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0c0d0e; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0c0d0e; text-align: left;&quot;&gt;&lt;b&gt;0을 전달하면 같은 프로세스의 다른 스레드에서 액세스할 수 있는 세마포어를 얻게 됩니다.&lt;/b&gt; 라고 한다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1291566/sem-init-what-is-the-pshared-parameter-for&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/1291566/sem-init-what-is-the-pshared-parameter-for&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732891761380&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;sem_init(...): What is the pshared parameter for?&quot; data-og-description=&quot;In a graduate class, we've had to use semaphores to accomplish work with threads. We were directed to use sem_init along with a bunch of other sem_* procedure but we were not given much information&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/1291566/sem-init-what-is-the-pshared-parameter-for&quot; data-og-url=&quot;https://stackoverflow.com/questions/1291566/sem-init-what-is-the-pshared-parameter-for&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bnZzhz/hyXDcWGZmJ/3cyX2CH7jof8KBMVca7DW1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1291566/sem-init-what-is-the-pshared-parameter-for&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/1291566/sem-init-what-is-the-pshared-parameter-for&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bnZzhz/hyXDcWGZmJ/3cyX2CH7jof8KBMVca7DW1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;sem_init(...): What is the pshared parameter for?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In a graduate class, we've had to use semaphores to accomplish work with threads. We were directed to use sem_init along with a bunch of other sem_* procedure but we were not given much information&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤텍스는 락에 소유권이 있어서 락을 획득한 스레드만이 락을 해제 가능하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세마포어는 락의 소유권이 없고 누구나 세마포어를 해제 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 방법이 있는지 pthread말고 다른 스레드에는 동기화 방법에 어떠한것들이 있는지 좀 찾아보고 글을 올려봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing/C, C++</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/245</guid>
      <comments>https://hannom.tistory.com/245#entry245comment</comments>
      <pubDate>Tue, 10 Dec 2024 20:33:21 +0900</pubDate>
    </item>
    <item>
      <title>pthread를 VisualStudio2022에서 사용하기.</title>
      <link>https://hannom.tistory.com/244</link>
      <description>&lt;pre id=&quot;code_1732861755837&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vcpkg install pthreads:x64-windows&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자 권한의 명령 프롬프트에서 vcpkg를 이용해 설치하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 vcpkg 기본 설치가 &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;x86-windows이지만 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;VS2022의 기본 활성 솔루션 플랫폼은 x64이므로 뒤에 x64-windows를 붙혀주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;1313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfslhL/btsK2TmSo9T/YLTyni7s0jjTj4KlKYD7Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfslhL/btsK2TmSo9T/YLTyni7s0jjTj4KlKYD7Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfslhL/btsK2TmSo9T/YLTyni7s0jjTj4KlKYD7Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfslhL%2FbtsK2TmSo9T%2FYLTyni7s0jjTj4KlKYD7Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;614&quot; height=&quot;943&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;1313&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지가 설치 되었으면 그냥 위 스크린샷처럼 사용하면 된다 빌드 성공한 모습.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1774&quot; data-origin-height=&quot;1808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfopjG/btsK2DqUmQu/gJcYfpKysHK4tBoVDnYa00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfopjG/btsK2DqUmQu/gJcYfpKysHK4tBoVDnYa00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfopjG/btsK2DqUmQu/gJcYfpKysHK4tBoVDnYa00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfopjG%2FbtsK2DqUmQu%2FgJcYfpKysHK4tBoVDnYa00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;629&quot; height=&quot;641&quot; data-origin-width=&quot;1774&quot; data-origin-height=&quot;1808&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 F12로 헤더 내용도 볼 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;vcpkg를 설치(?)하는 방법은 이전글을 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/243&quot;&gt;https://hannom.tistory.com/243&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732863905751&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;vcpkg를 설치(?)하는 방법&quot; data-og-description=&quot;https://github.com/microsoft/vcpkg&amp;nbsp;GitHub - microsoft/vcpkg: C++ Library Manager for Windows, Linux, and MacOSC++ Library Manager for Windows, Linux, and MacOS. Contribute to microsoft/vcpkg development by creating an account on GitHub.github.com&amp;nbsp;위의 &quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/243&quot; data-og-url=&quot;https://hannom.tistory.com/243&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bxISAt/hyXGCMSril/NwcbWUwcmbK45bO7kB37t1/img.png?width=800&amp;amp;height=506&amp;amp;face=0_0_800_506,https://scrap.kakaocdn.net/dn/dad7eb/hyXDivNLH5/fmtCuGQUXXrWukIMx3pdDK/img.png?width=800&amp;amp;height=506&amp;amp;face=0_0_800_506,https://scrap.kakaocdn.net/dn/clf2kh/hyXGLbY0et/44VtqSeSqOcvC26L77TfC1/img.png?width=1734&amp;amp;height=927&amp;amp;face=0_0_1734_927&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/243&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/243&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bxISAt/hyXGCMSril/NwcbWUwcmbK45bO7kB37t1/img.png?width=800&amp;amp;height=506&amp;amp;face=0_0_800_506,https://scrap.kakaocdn.net/dn/dad7eb/hyXDivNLH5/fmtCuGQUXXrWukIMx3pdDK/img.png?width=800&amp;amp;height=506&amp;amp;face=0_0_800_506,https://scrap.kakaocdn.net/dn/clf2kh/hyXGLbY0et/44VtqSeSqOcvC26L77TfC1/img.png?width=1734&amp;amp;height=927&amp;amp;face=0_0_1734_927');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;vcpkg를 설치(?)하는 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://github.com/microsoft/vcpkg&amp;nbsp;GitHub - microsoft/vcpkg: C++ Library Manager for Windows, Linux, and MacOSC++ Library Manager for Windows, Linux, and MacOS. Contribute to microsoft/vcpkg development by creating an account on GitHub.github.com&amp;nbsp;위의&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;참고.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/answers/questions/1262076/how-to-use-pthred-h-on-visual-studio-2022&quot;&gt;https://learn.microsoft.com/en-us/answers/questions/1262076/how-to-use-pthred-h-on-visual-studio-2022&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732862642292&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to use pthred.h on Visual Studio 2022? - Microsoft Q&amp;amp;A&quot; data-og-description=&quot;Hi, I use Visual Studio 2022. When I include pthread.h file, following error occurs. How can resolve this? I installed vcpkg but the same error occurs. pthreadVC3.lib: No such file or&amp;hellip;&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/en-us/answers/questions/1262076/how-to-use-pthred-h-on-visual-studio-2022&quot; data-og-url=&quot;https://learn.microsoft.com/en-us/answers/questions/1262076/how-to-use-pthred-h-on-visual-studio-2022&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ba59zF/hyXDm50JLv/6CFUuGmKQFoJ7vKbUtNwB0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/answers/questions/1262076/how-to-use-pthred-h-on-visual-studio-2022&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/en-us/answers/questions/1262076/how-to-use-pthred-h-on-visual-studio-2022&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ba59zF/hyXDm50JLv/6CFUuGmKQFoJ7vKbUtNwB0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;How to use pthred.h on Visual Studio 2022? - Microsoft Q&amp;amp;A&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hi, I use Visual Studio 2022. When I include pthread.h file, following error occurs. How can resolve this? I installed vcpkg but the same error occurs. pthreadVC3.lib: No such file or&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/244</guid>
      <comments>https://hannom.tistory.com/244#entry244comment</comments>
      <pubDate>Fri, 29 Nov 2024 16:08:32 +0900</pubDate>
    </item>
    <item>
      <title>vcpkg를 설치(?)하는 방법</title>
      <link>https://hannom.tistory.com/243</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/vcpkg&quot;&gt;https://github.com/microsoft/vcpkg&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732863787298&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - microsoft/vcpkg: C++ Library Manager for Windows, Linux, and MacOS&quot; data-og-description=&quot;C++ Library Manager for Windows, Linux, and MacOS. Contribute to microsoft/vcpkg development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/microsoft/vcpkg&quot; data-og-url=&quot;https://github.com/microsoft/vcpkg&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/omMBD/hyXDiJhp5x/Y2ypESkKvp7cy0a0a1lQ91/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c9MKBS/hyXC87LtKL/aFKSKpThQtA7BktjLgCU5k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/vcpkg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/microsoft/vcpkg&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/omMBD/hyXDiJhp5x/Y2ypESkKvp7cy0a0a1lQ91/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/c9MKBS/hyXC87LtKL/aFKSKpThQtA7BktjLgCU5k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - microsoft/vcpkg: C++ Library Manager for Windows, Linux, and MacOS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;C++ Library Manager for Windows, Linux, and MacOS. Contribute to microsoft/vcpkg development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 github링크에서 clone이나 Download zip을 통해서 내려 받아 PowerShell이나 명령프롬프트에서 아래에 있는 bat파일을 실행하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1732863783715&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;.\bootstrap-vcpkg.bat&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;927&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhKsqk/btsK069sjTF/2ATpGjdMzydxeIVgLIVOn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhKsqk/btsK069sjTF/2ATpGjdMzydxeIVgLIVOn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhKsqk/btsK069sjTF/2ATpGjdMzydxeIVgLIVOn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhKsqk%2FbtsK069sjTF%2F2ATpGjdMzydxeIVgLIVOn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1464&quot; height=&quot;927&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;927&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제데로 되었다면 해당 경로에&lt;span&gt;&amp;nbsp;&lt;/span&gt;vcpkg.exe 가 생성되었을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 경로를 환경변수에 등록해서 사용해도 되고 일일히 경로를 찾아 들어가서 해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 여기서 설치한 패키지를 VisualStudio에서 사용하려면 아래의 명령어를 치면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1732863783716&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;.\vcpkg.exe integrate install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;927&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RPsKX/btsK00heQG1/fcdAEcMoA3KXuIPFfZQaFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RPsKX/btsK00heQG1/fcdAEcMoA3KXuIPFfZQaFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RPsKX/btsK00heQG1/fcdAEcMoA3KXuIPFfZQaFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRPsKX%2FbtsK00heQG1%2FfcdAEcMoA3KXuIPFfZQaFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1734&quot; height=&quot;927&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;927&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 사이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jungwoong.tistory.com/77&quot;&gt;https://jungwoong.tistory.com/77&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732863794292&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Tool] vcpkg 설치 및 사용법&quot; data-og-description=&quot;vcpkg란 vcpkg는 Windows linux와 MacOs 에서 C와 C++ 라이브러리 관리를 도와줍니다. 자세한 설명은 아래의 링크를 통해서 알 수 있습니다. https://docs.microsoft.com/ko-kr/cpp/build/vcpkg?view=vs-2019 vcpkg: Windows, Linux &quot; data-og-host=&quot;jungwoong.tistory.com&quot; data-og-source-url=&quot;https://jungwoong.tistory.com/77&quot; data-og-url=&quot;https://jungwoong.tistory.com/77&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ECYuJ/hyXDjao86n/5D2658AGooIoWHPkKVTgu1/img.png?width=637&amp;amp;height=553&amp;amp;face=0_0_637_553,https://scrap.kakaocdn.net/dn/cAgMCV/hyXGIzyJl3/pqVPxeFB0uR6lkHGbazW81/img.png?width=637&amp;amp;height=553&amp;amp;face=0_0_637_553,https://scrap.kakaocdn.net/dn/3WFUg/hyXGDSyDZP/TyvCbk0WEqUUPOq4w8bKpk/img.png?width=949&amp;amp;height=682&amp;amp;face=0_0_949_682&quot;&gt;&lt;a href=&quot;https://jungwoong.tistory.com/77&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jungwoong.tistory.com/77&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ECYuJ/hyXDjao86n/5D2658AGooIoWHPkKVTgu1/img.png?width=637&amp;amp;height=553&amp;amp;face=0_0_637_553,https://scrap.kakaocdn.net/dn/cAgMCV/hyXGIzyJl3/pqVPxeFB0uR6lkHGbazW81/img.png?width=637&amp;amp;height=553&amp;amp;face=0_0_637_553,https://scrap.kakaocdn.net/dn/3WFUg/hyXGDSyDZP/TyvCbk0WEqUUPOq4w8bKpk/img.png?width=949&amp;amp;height=682&amp;amp;face=0_0_949_682');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Tool] vcpkg 설치 및 사용법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;vcpkg란 vcpkg는 Windows linux와 MacOs 에서 C와 C++ 라이브러리 관리를 도와줍니다. 자세한 설명은 아래의 링크를 통해서 알 수 있습니다. https://docs.microsoft.com/ko-kr/cpp/build/vcpkg?view=vs-2019 vcpkg: Windows, Linux&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jungwoong.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@pikamon/CC-15&quot;&gt;https://velog.io/@pikamon/CC-15&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732863795331&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[C/C++] vcpkg 설치 방법 on Windows 11 x64&quot; data-og-description=&quot;vcpkg는 Microsoft에서 제공하는 C/C++ 패키지 관리자이다.Python의 pip, Node.js의 npm과 같이, C/C++ 환경에서 용이하게 패키지를 설치/삭제할 때 사용한다.간혹 윈도우 환경에서 C/C++로 개발하는 중 필요한 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@pikamon/CC-15&quot; data-og-url=&quot;https://velog.io/@pikamon/CC-15&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yYig5/hyXGzijUqv/RwJkjavMhc7xXPkk26xDZk/img.png?width=1627&amp;amp;height=1030&amp;amp;face=0_0_1627_1030,https://scrap.kakaocdn.net/dn/bTVpeZ/hyXGJrHa2r/rNcTktOTNv27Z5HJVTMg6K/img.png?width=1627&amp;amp;height=1030&amp;amp;face=0_0_1627_1030,https://scrap.kakaocdn.net/dn/bppXS9/hyXGKc41IR/NH8GfjUPWd2XT5AEdjKMUk/img.png?width=1150&amp;amp;height=702&amp;amp;face=0_0_1150_702&quot;&gt;&lt;a href=&quot;https://velog.io/@pikamon/CC-15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@pikamon/CC-15&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yYig5/hyXGzijUqv/RwJkjavMhc7xXPkk26xDZk/img.png?width=1627&amp;amp;height=1030&amp;amp;face=0_0_1627_1030,https://scrap.kakaocdn.net/dn/bTVpeZ/hyXGJrHa2r/rNcTktOTNv27Z5HJVTMg6K/img.png?width=1627&amp;amp;height=1030&amp;amp;face=0_0_1627_1030,https://scrap.kakaocdn.net/dn/bppXS9/hyXGKc41IR/NH8GfjUPWd2XT5AEdjKMUk/img.png?width=1150&amp;amp;height=702&amp;amp;face=0_0_1150_702');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[C/C++] vcpkg 설치 방법 on Windows 11 x64&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;vcpkg는 Microsoft에서 제공하는 C/C++ 패키지 관리자이다.Python의 pip, Node.js의 npm과 같이, C/C++ 환경에서 용이하게 패키지를 설치/삭제할 때 사용한다.간혹 윈도우 환경에서 C/C++로 개발하는 중 필요한&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/243</guid>
      <comments>https://hannom.tistory.com/243#entry243comment</comments>
      <pubDate>Fri, 29 Nov 2024 16:04:00 +0900</pubDate>
    </item>
    <item>
      <title>[C++] 생성자 호출순서 다시 돌아보기</title>
      <link>https://hannom.tistory.com/241</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 제목을 뭐로 지을까 하다가 일단 이렇게 지어놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 상속이란 무엇이고 다형성이란 무엇이다라는 설명이 아니고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 생성자 호출순서에 대한 내 실수를 다시 되짚고자 작성하는 글이므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속에대한 개념, 그리고 다형성이라는 개념을 찾으려고 들어오신 분들은 뒤로가기를 추천드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제가 되었던것은 어제 출력결과를 묻는 특정 문제를 보게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1732671599106&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

class AA
{
public:
	AA() { std::cout &amp;lt;&amp;lt; &quot;A constructor&quot; &amp;lt;&amp;lt; std::endl; }
	~AA() { std::cout &amp;lt;&amp;lt; &quot;A destructor&quot; &amp;lt;&amp;lt; std::endl; }

};

class BB  : public AA
{
public:
	BB() { std::cout &amp;lt;&amp;lt; &quot;B constructor&quot; &amp;lt;&amp;lt; std::endl; }
	BB(int a) { std::cout &amp;lt;&amp;lt; &quot;B constructor int&quot; &amp;lt;&amp;lt; std::endl; }
	~BB() { std::cout &amp;lt;&amp;lt; &quot;B destructor&quot; &amp;lt;&amp;lt; std::endl; }

};

int main()
{
	BB bb(10);

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AA의 자식으로 BB가 있고 main에 있는것처럼 생성 할 때 어떠한 출력 결과가 나올것인가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거 입사 시험에서 은근히 비슷한 유형의 문제를 많이 봐서 나는 그만 실수를 저지르고 말았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음.. 일단 virtual이 소멸자에 없네? 그러면 정답은 이거지 하고 너무 짧게 생각해버렸다.&lt;/p&gt;
&lt;pre id=&quot;code_1732671753408&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;A constructor
B constructor int
A destructor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 나올것이라고 생각하고 집에와서 복기를 해보니 하.. 자세히 안본 멍청한 내 자신을 탓해야했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1732671829130&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;A constructor
B constructor int
B destructor
A destructor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BB의 형으로 bb의 객체를 생성했기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BB의 부모인 AA의 생성자를 먼저 호출하고 그 다음 BB의 생성자를 호출하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;param으로 int를 받고 있으므로 BB(int a) 생성자가 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 BB의 형으로 소멸자가 먼저 호출되고 그 다음 부모인 AA의 소멸자가 호출되어서 이런 출력결과가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니 그러면 나는 도데체 어떤 코드랑 햇깔린것인가?&lt;/p&gt;
&lt;pre id=&quot;code_1732672239173&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main()
{
	AA* bb = new BB(10);
	delete bb;

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우에는 AA의 형으로 BB의 객체를 담고있는 다형성을 보여주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 간단하게 &lt;b&gt;다형성이란, 기본 클래스(동물) 포인터로 파생 클래스(개,고양이, 기타 등등..) 객체를 관리하는것&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우에는 소멸자가 virtual이 아니면 내가 오답으로 적었던 아래의 출력 문구가 나오게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1732672336547&quot; class=&quot;delphi&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;A constructor
B constructor int
A destructor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 BB의 객체이지만 AA클래스 포인터를 기준으로 소멸자 호출을 하게 되는데 소멸자에 virtual이 붙어있지 않으므로 이 경우 자식이 있는지 알지 못하게 된다. 그러므로 소멸자 호출이 AA만 호출되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 main코드를 아래와 같이 바꾸면 어떻게 될것인가?&lt;/p&gt;
&lt;pre id=&quot;code_1732672547046&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main()
{
	BB* bb = new BB(10);
	delete bb;

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 포인터의 형과 생성하는 객체의 형이 서로 같으므로 다형성을 보여주지 않고 있으므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BB의 소멸자는 AA의 소멸자도 호출하기 때문에 위에서 봤던 &lt;b&gt;BB bb(10);&lt;/b&gt; 으로 생성하고 제거한것과 같은 출력결과를 보여준다.&lt;/p&gt;
&lt;pre id=&quot;code_1732672754324&quot; class=&quot;delphi&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;A constructor
B constructor int
B destructor
A destructor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 좀 꼼꼼히 봐야할것 같다 -_-..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing/C, C++</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/241</guid>
      <comments>https://hannom.tistory.com/241#entry241comment</comments>
      <pubDate>Wed, 27 Nov 2024 11:12:03 +0900</pubDate>
    </item>
    <item>
      <title>[UE] WAV파일을 DownSampling, Stereo To Mono로 변경 해보자.</title>
      <link>https://hannom.tistory.com/240</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요거 카테고리를 어디에 배치 해야 할까 하다가 단순히 언리얼엔진에서 작업한거라 언리얼로 분류 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이를 참조해서 다른 엔진 그리고 다른언어에서도 적용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 WAV파일을 읽어서 DownSampling 그리고 스테레오를 모노로 변경(Stereo To Mono)하는 내용을 구현한뒤 내용을 정리해보려고 작성하는 글이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거 WAV파일 DownSampling, 그리고 스테레오를 모노로 변경(Stereo To Mono) 작업을 사내에서 사용한 경험을 토대로 다시 작성하여 나중에 잊어버리면 내가 다시 볼 목적으로 적어놓는 글이며 &lt;b&gt;전문적인 프로그램과는 다른 결과를 불러올 수 있으므로&amp;nbsp;자세하고 깊은 wav파일 지식은 작성하지 않으려고 한다.(더 좋은 내용의 글들이 다른곳에 더 많을것이므로...)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 이 글에서 말하는 Sample은(정확히는 Sampling Frequency) WAV파일에 저장된 소리로부터 초당 샘플링한 횟수를 의미한다. 쉽게 말하면 높으면 음질이 좋다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 내 기억속에서의 언리얼은 녹음시 기본으로 48000Hz를 사용 했던것으로 기억한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YvfBw/btsINZjo7OB/7AE8HmaT2ccSYTNJgwhYa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YvfBw/btsINZjo7OB/7AE8HmaT2ccSYTNJgwhYa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YvfBw/btsINZjo7OB/7AE8HmaT2ccSYTNJgwhYa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYvfBw%2FbtsINZjo7OB%2F7AE8HmaT2ccSYTNJgwhYa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1179&quot; height=&quot;518&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 세팅에서 각 플랫폼마다 확인할 수 있고 수정도 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내에서 관련 작업을 할 때 이를 임의로 수정하기보다는 내가 DownSampling을 통해서 적절히 변경하는것이 나중에 사이드 이펙트가 줄지 않을까라는 생각이 들어서 작업하다보니 이런 작업도 하게 되었다 하하..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성된 코드는 이전 언리얼엔진에서 마이크를 통해 wav파일로 저장해보자 글에서 작성된 코드의 연장으로 작업 되어있다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/237&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hannom.tistory.com/237&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721931328490&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1&quot; data-og-description=&quot;들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어서 앉을수 있게 되었다 하하하하하하 건강챙기자.. -_-...이전 회사에서 했던 작업중 마&quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/237&quot; data-og-url=&quot;https://hannom.tistory.com/237&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b0P9Ut/hyWCJ2bIwK/zhAi8OZca9EDLZIvYXfNEk/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/lBkNI/hyWCNwKbCv/lrgHghXFwJh4SbEWD9xrV0/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/mLbhA/hyWCB4bAoH/rMFKRDDUakKZ5tu7YoLEH1/img.png?width=1739&amp;amp;height=786&amp;amp;face=0_0_1739_786&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/237&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/237&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b0P9Ut/hyWCJ2bIwK/zhAi8OZca9EDLZIvYXfNEk/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/lBkNI/hyWCNwKbCv/lrgHghXFwJh4SbEWD9xrV0/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/mLbhA/hyWCB4bAoH/rMFKRDDUakKZ5tu7YoLEH1/img.png?width=1739&amp;amp;height=786&amp;amp;face=0_0_1739_786');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어서 앉을수 있게 되었다 하하하하하하 건강챙기자.. -_-...이전 회사에서 했던 작업중 마&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/238&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hannom.tistory.com/238&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721931332694&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2&quot; data-og-description=&quot;https://hannom.tistory.com/237&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어&quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/238&quot; data-og-url=&quot;https://hannom.tistory.com/238&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NNxZe/hyWCGYGorw/Fx0YZaXe8liXuIpNTOXW8k/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/hv3nM/hyWCIa7aq0/rxgCM7s9E1VFOpmkvPEZkK/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/bGGbTm/hyWCz6l9Dm/xRZ2Ukx1wnbZhvONhkG5ak/img.png?width=2717&amp;amp;height=1473&amp;amp;face=0_0_2717_1473&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/238&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/238&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NNxZe/hyWCGYGorw/Fx0YZaXe8liXuIpNTOXW8k/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/hv3nM/hyWCIa7aq0/rxgCM7s9E1VFOpmkvPEZkK/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/bGGbTm/hyWCz6l9Dm/xRZ2Ukx1wnbZhvONhkG5ak/img.png?width=2717&amp;amp;height=1473&amp;amp;face=0_0_2717_1473');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://hannom.tistory.com/237&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/239&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hannom.tistory.com/239&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721931335581&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 3&quot; data-og-description=&quot;https://hannom.tistory.com/238&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2https://hannom.tistory.com/237&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1들어가기전 잡담을 좀 &quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/239&quot; data-og-url=&quot;https://hannom.tistory.com/239&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/j9spw/hyWCBiNwQd/MZ08OUqbV4K04n44AIDpXk/img.png?width=800&amp;amp;height=472&amp;amp;face=0_0_800_472,https://scrap.kakaocdn.net/dn/bW1RE5/hyWCIIXkCB/L6m71NAK72hUH4e8UpjDKK/img.png?width=800&amp;amp;height=472&amp;amp;face=0_0_800_472,https://scrap.kakaocdn.net/dn/V7ngO/hyWG2FMTLq/XQLdaRtyhXaN7KmNptpL31/img.png?width=1634&amp;amp;height=825&amp;amp;face=0_0_1634_825&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/239&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/239&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/j9spw/hyWCBiNwQd/MZ08OUqbV4K04n44AIDpXk/img.png?width=800&amp;amp;height=472&amp;amp;face=0_0_800_472,https://scrap.kakaocdn.net/dn/bW1RE5/hyWCIIXkCB/L6m71NAK72hUH4e8UpjDKK/img.png?width=800&amp;amp;height=472&amp;amp;face=0_0_800_472,https://scrap.kakaocdn.net/dn/V7ngO/hyWG2FMTLq/XQLdaRtyhXaN7KmNptpL31/img.png?width=1634&amp;amp;height=825&amp;amp;face=0_0_1634_825');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 3&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://hannom.tistory.com/238&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2https://hannom.tistory.com/237&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1들어가기전 잡담을 좀&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 작업을 하면서 참고했던 사이트들은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://infograph.tistory.com/333&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://infograph.tistory.com/333&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721928670018&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;01. WAV 파일 구조&quot; data-og-description=&quot;컴퓨터에서 소리를 담는 가장 기본적인 파일 구조가 WAV 파일 구조이다. 1999년 경부터 Microsoft와 IBM에 의해 파일 구조가 정의되어 사용되었고, PCM 방식으로 인코딩 된 디지털 신호를 압축되지 않&quot; data-og-host=&quot;infograph.tistory.com&quot; data-og-source-url=&quot;https://infograph.tistory.com/333&quot; data-og-url=&quot;https://infograph.tistory.com/333&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/99AcE/hyWGSJVJUw/hrKHk6mAbT8uBERorw0Vq0/img.png?width=800&amp;amp;height=728&amp;amp;face=0_0_800_728,https://scrap.kakaocdn.net/dn/TKauu/hyWGZI3zQU/390gTuTzCy2XgNBKagknHk/img.png?width=800&amp;amp;height=728&amp;amp;face=0_0_800_728,https://scrap.kakaocdn.net/dn/bverqh/hyWGN9GVJB/Mg2ERw43VLMbBk8XiUdXr1/img.png?width=878&amp;amp;height=799&amp;amp;face=0_0_878_799&quot;&gt;&lt;a href=&quot;https://infograph.tistory.com/333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://infograph.tistory.com/333&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/99AcE/hyWGSJVJUw/hrKHk6mAbT8uBERorw0Vq0/img.png?width=800&amp;amp;height=728&amp;amp;face=0_0_800_728,https://scrap.kakaocdn.net/dn/TKauu/hyWGZI3zQU/390gTuTzCy2XgNBKagknHk/img.png?width=800&amp;amp;height=728&amp;amp;face=0_0_800_728,https://scrap.kakaocdn.net/dn/bverqh/hyWGN9GVJB/Mg2ERw43VLMbBk8XiUdXr1/img.png?width=878&amp;amp;height=799&amp;amp;face=0_0_878_799');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;01. WAV 파일 구조&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터에서 소리를 담는 가장 기본적인 파일 구조가 WAV 파일 구조이다. 1999년 경부터 Microsoft와 IBM에 의해 파일 구조가 정의되어 사용되었고, PCM 방식으로 인코딩 된 디지털 신호를 압축되지 않&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;infograph.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://anythingcafe.tistory.com/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://anythingcafe.tistory.com/2&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721928673827&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;WAV 파일의 헤더 구조와 Raw Data(pcm data)&quot; data-og-description=&quot;우리는 .mp3 형식의 오디오 파일엔 익숙하고, .wav 형식의 오디오 파일은 다소 생소한 느낌이 있다. 과연 wav 파일은 무엇일까? Wav 는 Waveform audio format의 준말로 개인용 컴퓨터에서 오디오를 재생하&quot; data-og-host=&quot;anythingcafe.tistory.com&quot; data-og-source-url=&quot;https://anythingcafe.tistory.com/2&quot; data-og-url=&quot;https://anythingcafe.tistory.com/2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bEMwCK/hyWG2lt3rI/tOtKzwEGHahNSZYYMftTq0/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/nH6rd/hyWCMxPmzv/0BDOvu5lebI7DaGIKNSvMk/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/bkP8sM/hyWCCorV7P/l9CkKzoKhaP4KDFypv8EkK/img.png?width=1418&amp;amp;height=851&amp;amp;face=0_0_1418_851&quot;&gt;&lt;a href=&quot;https://anythingcafe.tistory.com/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://anythingcafe.tistory.com/2&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bEMwCK/hyWG2lt3rI/tOtKzwEGHahNSZYYMftTq0/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/nH6rd/hyWCMxPmzv/0BDOvu5lebI7DaGIKNSvMk/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/bkP8sM/hyWCCorV7P/l9CkKzoKhaP4KDFypv8EkK/img.png?width=1418&amp;amp;height=851&amp;amp;face=0_0_1418_851');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;WAV 파일의 헤더 구조와 Raw Data(pcm data)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;우리는 .mp3 형식의 오디오 파일엔 익숙하고, .wav 형식의 오디오 파일은 다소 생소한 느낌이 있다. 과연 wav 파일은 무엇일까? Wav 는 Waveform audio format의 준말로 개인용 컴퓨터에서 오디오를 재생하&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;anythingcafe.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://psychoria.tistory.com/entry/DirectSound-1-Wave-%ED%8C%8C%EC%9D%BC%EC%9D%98-%EA%B5%AC%EC%A1%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://psychoria.tistory.com/entry/DirectSound-1-Wave-%ED%8C%8C%EC%9D%BC%EC%9D%98-%EA%B5%AC%EC%A1%B0&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721928681393&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[DirectSound] 1. Wave 파일의 구조&quot; data-og-description=&quot;DirectSound는 DirectX 중에서 음악의 재생 및 녹음과 같은 기능을 담당합니다.DirectSound를 하기 전에 기본적으로 wav 파일의 구조를 알아보겠습니다.간단하게 wav 파일은 헤더(Header) 정보 + PCM 데이터로 &quot; data-og-host=&quot;psychoria.tistory.com&quot; data-og-source-url=&quot;https://psychoria.tistory.com/entry/DirectSound-1-Wave-%ED%8C%8C%EC%9D%BC%EC%9D%98-%EA%B5%AC%EC%A1%B0&quot; data-og-url=&quot;https://psychoria.tistory.com/212&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eq1Peu/hyWGO8BtQg/TCaaYZmkegNKAtylHEXouK/img.png?width=643&amp;amp;height=466&amp;amp;face=0_0_643_466,https://scrap.kakaocdn.net/dn/S9mfX/hyWG26QOph/G9ZSwvlATnqnBLnBstPyr0/img.png?width=643&amp;amp;height=466&amp;amp;face=0_0_643_466,https://scrap.kakaocdn.net/dn/wf7ZR/hyWG0OJufN/bOZ8t0yCMbzIB9jSjVF8k0/img.gif?width=612&amp;amp;height=567&amp;amp;face=0_0_612_567&quot;&gt;&lt;a href=&quot;https://psychoria.tistory.com/entry/DirectSound-1-Wave-%ED%8C%8C%EC%9D%BC%EC%9D%98-%EA%B5%AC%EC%A1%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://psychoria.tistory.com/entry/DirectSound-1-Wave-%ED%8C%8C%EC%9D%BC%EC%9D%98-%EA%B5%AC%EC%A1%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eq1Peu/hyWGO8BtQg/TCaaYZmkegNKAtylHEXouK/img.png?width=643&amp;amp;height=466&amp;amp;face=0_0_643_466,https://scrap.kakaocdn.net/dn/S9mfX/hyWG26QOph/G9ZSwvlATnqnBLnBstPyr0/img.png?width=643&amp;amp;height=466&amp;amp;face=0_0_643_466,https://scrap.kakaocdn.net/dn/wf7ZR/hyWG0OJufN/bOZ8t0yCMbzIB9jSjVF8k0/img.gif?width=612&amp;amp;height=567&amp;amp;face=0_0_612_567');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[DirectSound] 1. Wave 파일의 구조&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;DirectSound는 DirectX 중에서 음악의 재생 및 녹음과 같은 기능을 담당합니다.DirectSound를 하기 전에 기본적으로 wav 파일의 구조를 알아보겠습니다.간단하게 wav 파일은 헤더(Header) 정보 + PCM 데이터로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;psychoria.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아예 코드로도 만들어 놓은 외국인 형도 있었는데 위에서 헤더파일을 좀 보고 코드를 고쳐서 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/69085916/ue4-convert-audio-from-48-stereo-to-16-mono&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/69085916/ue4-convert-audio-from-48-stereo-to-16-mono&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721928727569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ue4 Convert audio from 48 stereo to 16 mono&quot; data-og-description=&quot;How to change sampling rate from 48000 (ue4 default) to 16000 samples and stereo to mono in a wav recording in ue4? I have searched in BPs but not lack. The image below shows what I have done with ...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/69085916/ue4-convert-audio-from-48-stereo-to-16-mono&quot; data-og-url=&quot;https://stackoverflow.com/questions/69085916/ue4-convert-audio-from-48-stereo-to-16-mono&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b3DwFS/hyWGYQUs0O/7yCL2T0hLwhrixLltpuIaK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/kD4PA/hyWCKGNh4Y/q8fNcuaR0dtBuzzpC8LVgk/img.png?width=2137&amp;amp;height=429&amp;amp;face=0_0_2137_429,https://scrap.kakaocdn.net/dn/bLID6h/hyWCOh6XZ9/yB0MlXkfFXlRK0AEt5LPc0/img.png?width=1405&amp;amp;height=521&amp;amp;face=0_0_1405_521&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/69085916/ue4-convert-audio-from-48-stereo-to-16-mono&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/69085916/ue4-convert-audio-from-48-stereo-to-16-mono&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b3DwFS/hyWGYQUs0O/7yCL2T0hLwhrixLltpuIaK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/kD4PA/hyWCKGNh4Y/q8fNcuaR0dtBuzzpC8LVgk/img.png?width=2137&amp;amp;height=429&amp;amp;face=0_0_2137_429,https://scrap.kakaocdn.net/dn/bLID6h/hyWCOh6XZ9/yB0MlXkfFXlRK0AEt5LPc0/img.png?width=1405&amp;amp;height=521&amp;amp;face=0_0_1405_521');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ue4 Convert audio from 48 stereo to 16 mono&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to change sampling rate from 48000 (ue4 default) to 16000 samples and stereo to mono in a wav recording in ue4? I have searched in BPs but not lack. The image below shows what I have done with ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 내가 작성한 코드는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1721929406866&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;USTRUCT()
struct FWaveInfo
{
	GENERATED_BODY()

	// Pointers to variables in the in-memory WAVE file.
	uint32	SamplesPerSec	= 0;
	uint32	AvgBytesPerSec	= 0;
	uint16	BlockAlign	= 0;
	uint16	BitsPerSample	= 0;
	uint16	Channels	= 0;
	uint16	FormatTag	= 0;

	uint32	WaveDataSize	= 0;
	uint32	MasterSize	= 0;
	uint8	SampleDataStart	= 0;
	uint8	SampleDataEnd	= 0;
	uint32	SampleDataSize	= 0;
	uint8	WaveDataEnd	= 0;

	uint32	NewDataSize	= 0;

	// 생성자, 복사생성자 operator= 생략.

};

void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	if (ReadWavFileData.Num() == 0)
	{
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 5.f, FColor::Red, &quot;Stereo Bytes is empty&quot;);
		return;
	}

	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)
		{
			short NumChannelCount = ConvertWavInfo.Channels;
			OutConvertResultFileData.Append((uint8*)&amp;amp;NumChannelCount, sizeof(NumChannelCount));
			i++;
		}
		else if (i == 24)	//SamplingRate starts from 24 to 27
		{
			int OriginalSamplingRate = (*(int*)&amp;amp;ReadWavFileData[i]);
			int SamplingRate = OriginalSamplingRate / ((OriginalSamplingRate / ConvertWavInfo.SamplesPerSec));

			OutConvertResultFileData.Append((uint8*)&amp;amp;SamplingRate, sizeof(SamplingRate));
			i += 3;
		}
		else if (i == 28)	//ByteRate starts from 28 to 32
		{
			int OriginalByteRate = (*(int*)&amp;amp;ReadWavFileData[i]);
			int ByteRate = OriginalByteRate / ((OriginWavInfo.SamplesPerSec / ConvertWavInfo.SamplesPerSec) * (OriginWavInfo.Channels / ConvertWavInfo.Channels));

			OutConvertResultFileData.Append((uint8*)&amp;amp;ByteRate, sizeof(ByteRate));
			i += 3;
		}
		else if (i == 32)	//BlockAlign starts from 32 to 34
		{
			short BlockAlign = (*(short*)&amp;amp;ReadWavFileData[i]) / (OriginWavInfo.Channels / ConvertWavInfo.Channels);
			OutConvertResultFileData.Append((uint8*)&amp;amp;BlockAlign, sizeof(BlockAlign));
			i++;
		}
		else if (i == 40)
		{
			int SubChunkSize = (*(int*)&amp;amp;ReadWavFileData[i]) / (OriginWavInfo.Channels / ConvertWavInfo.Channels);
			OutConvertResultFileData.Append((uint8*)&amp;amp;SubChunkSize, sizeof(SubChunkSize));
			i += 3;
		}
		else
		{
			OutConvertResultFileData.Add(ReadWavFileData[i]);
		}
	}

	short BlockAlign = (OriginWavInfo.BlockAlign * (OriginWavInfo.Channels / ConvertWavInfo.Channels)) * (OriginWavInfo.SamplesPerSec / ConvertWavInfo.SamplesPerSec);

	for (int i = 44; i &amp;lt; ReadWavFileData.Num(); i += BlockAlign)
	{
		OutConvertResultFileData.Add(ReadWavFileData[i]);
		OutConvertResultFileData.Add(ReadWavFileData[i + 1]);
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 먼저 FWaveInfo라는 구조체는 내가 임의로 만든것이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Engine/Public/Audio.h에&amp;nbsp;FWaveModInfo라는 구조체 내부를 보고 멤버 똑같이 작성하고 깊은복사 되도록 적어놓은것 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터로 전달받은 내용은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래의 wav파일 정보를 OriginWavInfo&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경하려고 하는 wav파일 정보를 ConvertWavInfo&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 wav파일을 읽어들인것은 ReadWavFileData&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경된 wav파일 내용은 OutConvertResultFileData&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 살펴보면..&lt;/p&gt;
&lt;pre id=&quot;code_1721931676375&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	//Change wav headers
	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)
		{
			short NumChannelCount = ConvertWavInfo.Channels;

			OutConvertResultFileData.Append((uint8*)&amp;amp;NumChannelCount, sizeof(NumChannelCount));
			i++;
		}

	// ....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 참고한 사이트들의 정보를 모으고 모아 offset의 22 이전값은 특별히 변경할 필요가 없는 내용들이라 건너뛰었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Channel은 여기서 단순히 모노(Mono) 또는 스테레오(Stereo)만 정해주면되므로 1 또는 2를 전달받은것을 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Sample Rate를 기입해 주어야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1721931878704&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	//Change wav headers
	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)	{ /* 생략 */ }
		else if (i == 24)
        	{
                	int OriginalSamplingRate = (*(int*)&amp;amp;ReadWavFileData[i]);
        		int SamplingRate = OriginalSamplingRate / ((OriginalSamplingRate / ConvertWavInfo.SamplesPerSec));
			OutConvertResultFileData.Append((uint8*)&amp;amp;SamplingRate, sizeof(SamplingRate));
			i += 3;
        	}

	// ....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서는 SamplingRate값을 단순히 전달받은 ConvertWavInfo.SamplesPerSec를 넣어주면 끝이 아닌가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 11025같은 값이 들어오면 음성이 늘어지도록 재생되는 문제가 있어서 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;일단 위와같이 두었다.(그러면 12000이 된다.)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OBj9v/btsIPVPpOzI/NmEvNWxIBCR7RLq1DNFyOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OBj9v/btsIPVPpOzI/NmEvNWxIBCR7RLq1DNFyOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OBj9v/btsIPVPpOzI/NmEvNWxIBCR7RLq1DNFyOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOBj9v%2FbtsIPVPpOzI%2FNmEvNWxIBCR7RLq1DNFyOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;477&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;477&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;음악파일 편집 프로그램(GoldWave)에서 기본 Preset에서 12000이 아닌 11025가 되어있길래 이 값을 넣었다가 위와 같은 문제를 발견 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내에서 이 내용을 개발할 당시 필요한값이 8000과 12000이었기 때문에 해당 문제에 대해서 깊게 따로 파진 않았다. (만들어야 하는 것이 완벽한 음성데이터 조작이 아니었기 때문에 여기에 시간을 많이 할애할 필요가 없기 때문. 이와 같은 문제가 발생 할 수 있다정도를 주석에 달아놓았다.)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722185475234&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	//Change wav headers
	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)	{ /* 생략 */ }
		else if (i == 24)	{ /* 생략 */ }
        	else if (i == 28)	
		{
        		int OriginalByteRate = (*(int*)&amp;amp;ReadWavFileData[i]);
			
        		int ByteRate = OriginalByteRate / (
                		(OriginWavInfo.SamplesPerSec / ConvertWavInfo.SamplesPerSec) * 
                		(OriginWavInfo.Channels / ConvertWavInfo.Channels)
                    	);
			
        		OutConvertResultFileData.Append((uint8*)&amp;amp;ByteRate, sizeof(ByteRate));
        		i += 3;
		}


	// ....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ByteRate부분인데 여기 값은 (SampleRate * NumChannels * BitPerSample / 8)로 이루어진 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OriginalByteRate에서 변경된 값은 SampleRate와 NumChannels만 변경되므로 원래의 값에서 변경될 값이 얼마만큼 줄어든건지를 계산하려고 위와 같이 ByteRate를 계산했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722195328427&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	//Change wav headers
	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)	{ /* 생략 */ }
		else if (i == 24)	{ /* 생략 */ }
        	else if (i == 28)	{ /* 생략 */ }
		else if (i == 32)
		{
			short BlockAlign = (*(short*)&amp;amp;ReadWavFileData[i]) / (OriginWavInfo.Channels / ConvertWavInfo.Channels);
			
			OutConvertResultFileData.Append((uint8*)&amp;amp;BlockAlign, sizeof(BlockAlign));
			i++;
		}



	// ....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BlockAlign은 (NumChannels * BitsPerSample / 8) 으로 이루어진 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 마찬가지로 원래 BlockAlign값에서 변경된 NumChannels값만 변경하면 되므로 채널값만 변경된것을 적용해 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722195525826&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	//Change wav headers
	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)	{ /* 생략 */ }
		else if (i == 24)	{ /* 생략 */ }
        	else if (i == 28)	{ /* 생략 */ }
		else if (i == 32)	{ /* 생략 */ }
		else if (i == 40)
		{
			int SubChunkSize = (*(int*)&amp;amp;ReadWavFileData[i]) / (OriginWavInfo.Channels / ConvertWavInfo.Channels);
			
			OutConvertResultFileData.Append((uint8*)&amp;amp;SubChunkSize, sizeof(SubChunkSize));
			i += 3;
		}
		else
		{
			OutConvertResultFileData.Add(ReadWavFileData[i]);
		}
	}



	// ....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기는 SubChunkSize 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(BitsPerSample / 8) * NumChannels * 실제 샘플수&lt;/b&gt; 로 계산이 되는데 역시 여기서 변경되는건 NumChannels만 있으므로 위에 BlockAlign과 똑같이 채널만 조절되도록 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 else에 해당되는 부분은 모두 값 그대로 넣어주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 헤더부분은 끝이 났고 이제 Data부분이다.&lt;/p&gt;
&lt;pre id=&quot;code_1722196410657&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordComponent::ConvertWaveFileData(const FWaveInfo&amp;amp; OriginWavInfo, const FWaveInfo&amp;amp; ConvertWavInfo, TArray&amp;lt;uint8&amp;gt;&amp;amp; OutConvertResultFileData, const TArray&amp;lt;uint8&amp;gt;&amp;amp; ReadWavFileData)
{
	//Change wav headers
	for (int i = 0; i &amp;lt; 44; i++)
	{
		//NumChannels starts from 22 to 24
		if (i == 22)	{ /* 생략 */ }
		else if (i == 24)	{ /* 생략 */ }
        	else if (i == 28)	{ /* 생략 */ }
		else if (i == 32)	{ /* 생략 */ }
		else if (i == 40)	{ /* 생략 */ }
		else	{ /* 생략 */ }
	}

	short BlockAlign = OriginWavInfo.BlockAlign * 
			(OriginWavInfo.Channels / ConvertWavInfo.Channels) *
			(OriginWavInfo.SamplesPerSec / ConvertWavInfo.SamplesPerSec);
                        
	for (int i = 44; i &amp;lt; ReadWavFileData.Num(); i += BlockAlign)
	{
		OutConvertResultFileData.Add(ReadWavFileData[i]);
		OutConvertResultFileData.Add(ReadWavFileData[i + 1]);
	}
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 음성 데이터를 직접적으로 수정하는것이 아닌 건너뛰는 형식으로 음성 데이터를 넣었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방법이 실제 음악편집 프로그램의 방식인지는 모르겠다. 위에서 적어놓은 페이지를 참고해서 구현하고 이해했을뿐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한것을 GPT에게 물어봐도 외부 라이브러리를 써야 제데로된 샘플링 조절이 된다고 말하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 원래의 BlockAlign에서 채널이 스테레오인지 모노인지에 따라서 건너뛸 크기가 결정되고 Sample에 따라서 얼마나 건너뛰어야 할지가 결정되므로 해당 내용을 계산해서 for문에서 건너뛰는 식으로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sample이 원래에 비해서 어떤 비율로 낮아졌는지, 그리고 스테레오에서 모노로 변경되면 left 혹은 right만 가져와야 할것이므로 더 건너뛰어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2088&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjXASj/btsIRoW9BFR/zc9O4c3KWYUKz379UEXD90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjXASj/btsIRoW9BFR/zc9O4c3KWYUKz379UEXD90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjXASj/btsIRoW9BFR/zc9O4c3KWYUKz379UEXD90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjXASj%2FbtsIRoW9BFR%2Fzc9O4c3KWYUKz379UEXD90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3840&quot; height=&quot;2088&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2088&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 GoldWave라는 편집프로그램을 통해서 본 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;16bit 스테레오 48000hz wav파일을 16bit mono 12000hz로 변경한 모습이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 전문 프로그램과 비교하자면 정확하게 다운샘플이 된건지는 모르겠지만 그래도 야매로 이렇게 구현해 본 경험을 정리해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 내가 지금도 이걸 작성하면서 잘못 알고있는 부분이 있을수 있으므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완벽한 정답은 아니더라도 미래의 나 혹은 이 글을 읽을 사람들이 참고만 했으면 해서 적어놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 작성하면서 Wav헤더에 관한 내용은 Engine/Public/Audio.h와 Engine/Private/Audio.cpp에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FWaveModInfo 클래스 그리고 void SerializeWaveFile 함수를 보는것도 좋을것 같다.&lt;/p&gt;</description>
      <category>Programing/UnrealEngine</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/240</guid>
      <comments>https://hannom.tistory.com/240#entry240comment</comments>
      <pubDate>Mon, 29 Jul 2024 05:12:04 +0900</pubDate>
    </item>
    <item>
      <title>[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 3</title>
      <link>https://hannom.tistory.com/239</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/238&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hannom.tistory.com/238&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721129353618&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2&quot; data-og-description=&quot;https://hannom.tistory.com/237&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어&quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/238&quot; data-og-url=&quot;https://hannom.tistory.com/238&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jAj7z/hyWCHhew8X/gZykCFMkJ9uJ1RhjY2gsp1/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/mz7yD/hyWzvJuxts/2CuNklVy8EKsPixArnA1e1/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/jsZX8/hyWCPfgh4Z/v3pHsfgd0BZC85F3ot8Fx0/img.png?width=2717&amp;amp;height=1473&amp;amp;face=0_0_2717_1473&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/238&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/238&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jAj7z/hyWCHhew8X/gZykCFMkJ9uJ1RhjY2gsp1/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/mz7yD/hyWzvJuxts/2CuNklVy8EKsPixArnA1e1/img.png?width=800&amp;amp;height=484&amp;amp;face=0_0_800_484,https://scrap.kakaocdn.net/dn/jsZX8/hyWCPfgh4Z/v3pHsfgd0BZC85F3ot8Fx0/img.png?width=2717&amp;amp;height=1473&amp;amp;face=0_0_2717_1473');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://hannom.tistory.com/237&amp;nbsp;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크의 이전 글에서 저장하고 녹음 되는것까지 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번글에서는 녹음중 소리 크기를 눈으로 보이게끔 하는 내용이라 굳이 볼 필요는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 코드 작성부터 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1721130078319&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class VOICERECORDPROJ_API UVoiceRecordWidget : public UUserWidget
{
	GENERATED_BODY()
	
	// 생략..
    
public:

	// 생략..

    UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = &quot;VoiceRecordWidget | MIC | Volume&quot;)
	void	BP_OnAudioEnvelopeValue(const float EnvelopeValue);

	void	OnAudioEnvelopeValue(const class UAudioComponent*, const float EnvelopeValue);

	// 생략..
    
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;녹음을 시작하면 VoiceRecordComponent의 부모인 SynthComponent에 OnAudioEnvelopeValueNative라는 Delegate가 있는데 여기에 위의 OnAudioEnvelopeValue를 Bind해서 EnvelopeValue를 받아올 생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721130023028&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UPPVoiceRecordWidget::OnAudioEnvelopeValue(const UAudioComponent* AudioComponent, const float EnvelopeValue)
{
	UE_LOG(LogTemp, Log, TEXT(&quot;EnvelopeValue : [%f]&quot;), EnvelopeValue );
	BP_OnAudioEnvelopeValue(EnvelopeValue);
}

void UVoiceRecordWidget::SetVoiceRecordComponent(UVoiceRecordComponent* VoiceRecordComponent)
{
	if (!VoiceRecordComponent)
	{
		return;
	}

	_VoiceRecordComponent = VoiceRecordComponent;

	_VoiceRecordComponent-&amp;gt;GetOnStartVoiceRecord().AddDynamic(this, &amp;amp;UVoiceRecordWidget::OnStartVoiceRecord);
	_VoiceRecordComponent-&amp;gt;GetOnStopVoiceRecord().AddDynamic(this, &amp;amp;UVoiceRecordWidget::OnStopVoiceRecord);
    
    	// Add &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;
    	_VoiceRecordComponent-&amp;gt;OnAudioEnvelopeValueNative.AddUObject(this, &amp;amp;UVoiceRecordWidget::OnAudioEnvelopeValue);
    	// Add &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VoiceRecordComponent를 Set할때 델리게이트에 Bind해주고 OnAudioEnvelopeValue의 Param의 값을 일단 로그로 출력시켜보도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 시각적으로 보이는것은 BP_OnAudioEnvelopeValue를 통해서 처리해줄 생각이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;1095&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XNyxJ/btsIB5c3k23/FAq4slpNHpSRLqxt9kRVbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XNyxJ/btsIB5c3k23/FAq4slpNHpSRLqxt9kRVbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XNyxJ/btsIB5c3k23/FAq4slpNHpSRLqxt9kRVbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXNyxJ%2FbtsIB5c3k23%2FFAq4slpNHpSRLqxt9kRVbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1854&quot; height=&quot;1095&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;1095&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크에 얼마나 크게 말하냐에 따라서 값이 달라지는것을 로그로 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이걸 눈에 보이도록 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표현 방법에는 텍스트가 될 수도 있고 이미지를 사용할 수도 있고 프로그래스바를 이용할수도 있고 다양하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 나는 에픽에서 샘플로 제공해준 UI Material Lab에 있는것을 가져와 적절하게 사용해볼 생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/marketplace/ko/product/ui-material-lab&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.unrealengine.com/marketplace/ko/product/ui-material-lab&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2035&quot; data-origin-height=&quot;1051&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nduMZ/btsIBhZwM3v/KKzwMy5RZ5okg7QEhJ1Wek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nduMZ/btsIBhZwM3v/KKzwMy5RZ5okg7QEhJ1Wek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nduMZ/btsIBhZwM3v/KKzwMy5RZ5okg7QEhJ1Wek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnduMZ%2FbtsIBhZwM3v%2FKKzwMy5RZ5okg7QEhJ1Wek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2035&quot; height=&quot;1051&quot; data-origin-width=&quot;2035&quot; data-origin-height=&quot;1051&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에는 이쁜 UI Material이 아주 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2142&quot; data-origin-height=&quot;1176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN7LVB/btsIBijRNuf/12x6JbG3YlF0hHGnHM63b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN7LVB/btsIBijRNuf/12x6JbG3YlF0hHGnHM63b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN7LVB/btsIBijRNuf/12x6JbG3YlF0hHGnHM63b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN7LVB%2FbtsIBijRNuf%2F12x6JbG3YlF0hHGnHM63b1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2142&quot; height=&quot;1176&quot; data-origin-width=&quot;2142&quot; data-origin-height=&quot;1176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 여기에 표시된 SDF progress bars에 있는 material을 이주시켜서 사용해 보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1661&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3yfuc/btsIAPvFjyX/ON12KoChnIF2cVbmJzvqg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3yfuc/btsIAPvFjyX/ON12KoChnIF2cVbmJzvqg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3yfuc/btsIAPvFjyX/ON12KoChnIF2cVbmJzvqg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3yfuc%2FbtsIAPvFjyX%2FON12KoChnIF2cVbmJzvqg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1661&quot; height=&quot;770&quot; data-origin-width=&quot;1661&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머티리얼 경로는 여기에 존재하고 이걸 이주 시켜서 사용하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이주 방법은 따로 설명하지 않겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;825&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CcGfh/btsIAzfwNoD/lNSlszCE8XOuhoSYMZ68tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CcGfh/btsIAzfwNoD/lNSlszCE8XOuhoSYMZ68tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CcGfh/btsIAzfwNoD/lNSlszCE8XOuhoSYMZ68tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCcGfh%2FbtsIAzfwNoD%2FlNSlszCE8XOuhoSYMZ68tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1634&quot; height=&quot;825&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;825&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이주 된것을 확인 했으면 열어보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3810&quot; data-origin-height=&quot;1955&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQmzp1/btsIBCPU3Nz/DZoo2zyJW3sx9OgBrHw2T1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQmzp1/btsIBCPU3Nz/DZoo2zyJW3sx9OgBrHw2T1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQmzp1/btsIBCPU3Nz/DZoo2zyJW3sx9OgBrHw2T1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQmzp1%2FbtsIBCPU3Nz%2FDZoo2zyJW3sx9OgBrHw2T1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3810&quot; height=&quot;1955&quot; data-origin-width=&quot;3810&quot; data-origin-height=&quot;1955&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머티리얼 노드들은 나도 잘 못다루지만 한번 수정해 보려고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2031&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w5iv3/btsIBjC3GKr/myykKRP4EPn4ddnUTUVy60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w5iv3/btsIBjC3GKr/myykKRP4EPn4ddnUTUVy60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w5iv3/btsIBjC3GKr/myykKRP4EPn4ddnUTUVy60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw5iv3%2FbtsIBjC3GKr%2FmyykKRP4EPn4ddnUTUVy60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2031&quot; height=&quot;610&quot; data-origin-width=&quot;2031&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 자동적으로 값이 증가를 하고 가득차면 처음부터 다시 시작하는데 이 부분에 볼륨값을 전달해 주면 될것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWhlN4/btsIAOXRhZm/l5fs1m4dlvOEu5pNdLyVB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWhlN4/btsIAOXRhZm/l5fs1m4dlvOEu5pNdLyVB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWhlN4/btsIAOXRhZm/l5fs1m4dlvOEu5pNdLyVB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWhlN4%2FbtsIAOXRhZm%2Fl5fs1m4dlvOEu5pNdLyVB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;679&quot; height=&quot;361&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 float값 하나를 넘겨주는 Parameter를 추가하기 위해서 Scalar Parameter를 추가해주자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lcoVR/btsIAQ9cj7l/mmDT2jBTPKu052HCgYtx5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lcoVR/btsIAQ9cj7l/mmDT2jBTPKu052HCgYtx5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lcoVR/btsIAQ9cj7l/mmDT2jBTPKu052HCgYtx5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlcoVR%2FbtsIAQ9cj7l%2FmmDT2jBTPKu052HCgYtx5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;721&quot; height=&quot;676&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터 이름은 ProgressValue로 지었고 '명명된 경우 선언 노드 추가'를 통해서 이전에 작성되었던 머터리얼과 최대한 비슷하게 만들어놓았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egD6AJ/btsIASFLHfK/vRnALNqDndKhALYMW4dwCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egD6AJ/btsIASFLHfK/vRnALNqDndKhALYMW4dwCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egD6AJ/btsIASFLHfK/vRnALNqDndKhALYMW4dwCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegD6AJ%2FbtsIASFLHfK%2FvRnALNqDndKhALYMW4dwCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1537&quot; height=&quot;668&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성한 파라미터 노드를 선택 후 디테일 패널에 값을 적절하게 변경해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그룹도 다들 Pip SDF로 설정되어있어서 똑같이 해주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1993&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k1UIW/btsICSYm9t6/TMgkwdg0rqysLPe3fLPgAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k1UIW/btsICSYm9t6/TMgkwdg0rqysLPe3fLPgAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k1UIW/btsICSYm9t6/TMgkwdg0rqysLPe3fLPgAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk1UIW%2FbtsICSYm9t6%2FTMgkwdg0rqysLPe3fLPgAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1993&quot; height=&quot;590&quot; data-origin-width=&quot;1993&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 MF_UI_linearTime 과 연결되어있던 부분을 끊고 위에서 만든 progress value를 넘겨주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1167&quot; data-origin-height=&quot;1143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nhd4c/btsICwgWrHZ/kfWEQtpkrEEFKkkfStByck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nhd4c/btsICwgWrHZ/kfWEQtpkrEEFKkkfStByck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nhd4c/btsICwgWrHZ/kfWEQtpkrEEFKkkfStByck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnhd4c%2FbtsICwgWrHZ%2FkfWEQtpkrEEFKkkfStByck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1167&quot; height=&quot;1143&quot; data-origin-width=&quot;1167&quot; data-origin-height=&quot;1143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장을 하고 머티리얼 인스턴스를 생성해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/instanced-materials-in-unreal-engine?application_version=5.3&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/instanced-materials-in-unreal-engine?application_version=5.3&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머티리얼 인스턴스에 대해서는 위의 문서를 읽어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1618&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bP7YIl/btsIBj4a1ey/Ww06mEz5XaepAFo6lt9D2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bP7YIl/btsIBj4a1ey/Ww06mEz5XaepAFo6lt9D2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bP7YIl/btsIBj4a1ey/Ww06mEz5XaepAFo6lt9D2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbP7YIl%2FbtsIBj4a1ey%2FWw06mEz5XaepAFo6lt9D2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1618&quot; height=&quot;639&quot; data-origin-width=&quot;1618&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 MI_UI_ProgressBar_Segmented_Inst로 지었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzODKg/btsIBJnPoF9/udtbN8kiODpWHiqy34PzM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzODKg/btsIBJnPoF9/udtbN8kiODpWHiqy34PzM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzODKg/btsIBJnPoF9/udtbN8kiODpWHiqy34PzM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzODKg%2FbtsIBJnPoF9%2FudtbN8kiODpWHiqy34PzM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1145&quot; height=&quot;836&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들어 놓은 MI(Material Instance)를 열고 값은 위와같이 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 WBP_VoiceRecordWidget에서 적절하게 사용해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3411&quot; data-origin-height=&quot;1585&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Wufk/btsIB4L1RjO/TD2BYmF5s2JgkCwgVtBgIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Wufk/btsIB4L1RjO/TD2BYmF5s2JgkCwgVtBgIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Wufk/btsIB4L1RjO/TD2BYmF5s2JgkCwgVtBgIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Wufk%2FbtsIB4L1RjO%2FTD2BYmF5s2JgkCwgVtBgIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3411&quot; height=&quot;1585&quot; data-origin-width=&quot;3411&quot; data-origin-height=&quot;1585&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보여질 위젯을 적절하게 배치해주고 UI Material Lab에 있던것처럼 Image에 방금 만든 MI를 넣어주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1633&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IHgNR/btsIBXTRbaj/0e6DqkCsIv1Fgu6zWCaBzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IHgNR/btsIBXTRbaj/0e6DqkCsIv1Fgu6zWCaBzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IHgNR/btsIBXTRbaj/0e6DqkCsIv1Fgu6zWCaBzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIHgNR%2FbtsIBXTRbaj%2F0e6DqkCsIv1Fgu6zWCaBzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1633&quot; height=&quot;517&quot; data-origin-width=&quot;1633&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 위젯 블루프린트는 위와 같이 적용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=e0e5xy2fBxY&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=e0e5xy2fBxY&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=e0e5xy2fBxY&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bETnIO/hyWzpvM3vp/WMMKpwV83c3OZUwetmSUN1/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480&quot; data-video-width=&quot;640&quot; data-video-height=&quot;480&quot; data-video-origin-width=&quot;640&quot; data-video-origin-height=&quot;480&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;VoiceRecordProj 프리뷰 NetMode  Standalone 0  64 bit PC D3D SM6 2024 07 16 21 18 49&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/e0e5xy2fBxY&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상에 마이크 녹음 소리는 들리지 않지만 크게 말하면 적절하게 높게 보여진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing/UnrealEngine</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/239</guid>
      <comments>https://hannom.tistory.com/239#entry239comment</comments>
      <pubDate>Tue, 16 Jul 2024 21:22:24 +0900</pubDate>
    </item>
    <item>
      <title>[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 2</title>
      <link>https://hannom.tistory.com/238</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/237&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hannom.tistory.com/237&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721047860492&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1&quot; data-og-description=&quot;들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어서 앉을수 있게 되었다 하하하하하하 건강챙기자.. -_-...이전 회사에서 했던 작업중 마&quot; data-og-host=&quot;hannom.tistory.com&quot; data-og-source-url=&quot;https://hannom.tistory.com/237&quot; data-og-url=&quot;https://hannom.tistory.com/237&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/crGNLO/hyWCFjgXY8/OsOkOUdKlZHF4U2nKJlqwK/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/ckmFiH/hyWCA3leFn/GCTIog3gmkho8f0VTNIBrK/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/XbTvd/hyWzCPhI9H/ad03LnG9ySXl4sM5kKiCr1/img.png?width=1432&amp;amp;height=880&amp;amp;face=0_0_1432_880&quot;&gt;&lt;a href=&quot;https://hannom.tistory.com/237&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hannom.tistory.com/237&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/crGNLO/hyWCFjgXY8/OsOkOUdKlZHF4U2nKJlqwK/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/ckmFiH/hyWCA3leFn/GCTIog3gmkho8f0VTNIBrK/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/XbTvd/hyWzCPhI9H/ad03LnG9ySXl4sM5kKiCr1/img.png?width=1432&amp;amp;height=880&amp;amp;face=0_0_1432_880');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE] 마이크로 전달한 음성 데이터를 wav파일로 저장해보자. - 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;들어가기전 잡담을 좀 하자면 6월초에 수술을 받고 6월 내내 누워 지내다가 이제서야 어느정도 회복이 되어서 앉을수 있게 되었다 하하하하하하 건강챙기자.. -_-...이전 회사에서 했던 작업중 마&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hannom.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전글에서 이어서 위젯을 만들고 실제로 녹음까지 해보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1417&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1Hztb/btsIAQAdx9j/vUIkQrj26FmjWc0agSrab1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1Hztb/btsIAQAdx9j/vUIkQrj26FmjWc0agSrab1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1Hztb/btsIAQAdx9j/vUIkQrj26FmjWc0agSrab1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1Hztb%2FbtsIAQAdx9j%2FvUIkQrj26FmjWc0agSrab1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1417&quot; height=&quot;858&quot; data-origin-width=&quot;1417&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserWidget을 상속받는 클래스를 만들어준다. 이름은 VoiceRecordWidget으로 지었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqyNlc/btsIzrVyGS4/AkGVKI0rUfLqoKwDh5s4o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqyNlc/btsIzrVyGS4/AkGVKI0rUfLqoKwDh5s4o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqyNlc/btsIzrVyGS4/AkGVKI0rUfLqoKwDh5s4o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqyNlc%2FbtsIzrVyGS4%2FAkGVKI0rUfLqoKwDh5s4o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;932&quot; height=&quot;471&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 코드는 이후에 작성해 주도록 하고 앞에서 만든 VoiceRecordWidget을 상속받는 위젯 블루프린트를 만들어 준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3P31l/btsIBbREkhT/6m6B9IeMCwzKUwdcOQn2k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3P31l/btsIBbREkhT/6m6B9IeMCwzKUwdcOQn2k0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3P31l/btsIBbREkhT/6m6B9IeMCwzKUwdcOQn2k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3P31l%2FbtsIBbREkhT%2F6m6B9IeMCwzKUwdcOQn2k0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;254&quot; height=&quot;395&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 WBP_VoiceRecordWidget으로 지어주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2717&quot; data-origin-height=&quot;1473&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eey0aR/btsIBkt2Hil/InNgiuvBKI1imE0adrdhf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eey0aR/btsIBkt2Hil/InNgiuvBKI1imE0adrdhf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eey0aR/btsIBkt2Hil/InNgiuvBKI1imE0adrdhf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feey0aR%2FbtsIBkt2Hil%2FInNgiuvBKI1imE0adrdhf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2717&quot; height=&quot;1473&quot; data-origin-width=&quot;2717&quot; data-origin-height=&quot;1473&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적당히 위젯 디자인을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 테스트 할것이고 RecordStart / RecordStop 두개의 버튼을 WidgetSwitcher를 통해서 변경하도록 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 작성해보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1721048918107&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class UVoiceRecordComponent;

class UButton;
class UWidgetSwitcher;

UCLASS()
class VOICERECORDPROJ_API UVoiceRecordWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	UFUNCTION(BlueprintCallable, Category = &quot;VoiceRecord&quot;)
	void			RecordStart();

	UFUNCTION(BlueprintCallable, Category = &quot;VoiceRecord&quot;)
	void			RecordStop();

public:
	UFUNCTION()
	void			OnClicked_RecordStart();

	UFUNCTION()
	void			OnClicked_RecordStop();

	UFUNCTION()
	void			OnStartVoiceRecord();

	UFUNCTION()
	void			OnStopVoiceRecord();
public:
	UFUNCTION(BlueprintCallable, Category = &quot;VoiceRecordWidget&quot;)
	void			SetVoiceRecordComponent(UVoiceRecordComponent* VoiceRecordComponent);
    
    UFUNCTION(BlueprintCallable, Category = &quot;VoiceRecordWidget&quot;)
	void			ResetVoiceRecordComponent();

protected:
	virtual void		NativeConstruct() override;
	virtual void		NativeDestruct() override;

protected:
	TWeakObjectPtr&amp;lt;UVoiceRecordComponent&amp;gt;	_VoiceRecordComponent = nullptr;

protected:
	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr&amp;lt;UButton&amp;gt;					Button_RecordStart;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr&amp;lt;UButton&amp;gt;					Button_RecordStop;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr&amp;lt;UWidgetSwitcher&amp;gt;			WidgetSwitcher_RecordButtons;

};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위젯이 바인드 되었는지 확인하고 버튼 클릭 이벤트 바인딩/언바인딩 모두 NativeConstruct와 NativeDestruct에서 해줄 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 CPP코드를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1721051301623&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;UMG/VoiceRecordWidget.h&quot;
#include &quot;Components/Button.h&quot;
#include &quot;Components/WidgetSwitcher.h&quot;
#include &quot;Component/VoiceRecordComponent.h&quot;

void UVoiceRecordWidget::RecordStart()
{
	if (_VoiceRecordComponent.IsValid())
	{
		_VoiceRecordComponent-&amp;gt;StartRecord();
	}
}

void UVoiceRecordWidget::RecordStop()
{
	if (_VoiceRecordComponent.IsValid())
	{
		_VoiceRecordComponent-&amp;gt;StopRecord();
	}
}

void UVoiceRecordWidget::OnClicked_RecordStart()
{
	RecordStart();
}

void UVoiceRecordWidget::OnClicked_RecordStop()
{
	RecordStop();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼 클릭시 OnClicked_ 접두가 붙은 RecordStart와 RecordStop을 호출 하도록 할 예정이다.&lt;/p&gt;
&lt;pre id=&quot;code_1721052092287&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordWidget::OnStartVoiceRecord()
{
	if (WidgetSwitcher_RecordButtons)
	{
		WidgetSwitcher_RecordButtons-&amp;gt;SetActiveWidget(Button_RecordStop);
	}
}

void UVoiceRecordWidget::OnStopVoiceRecord()
{
	if (WidgetSwitcher_RecordButtons)
	{
		WidgetSwitcher_RecordButtons-&amp;gt;SetActiveWidget(Button_RecordStop);
	}
}

void UVoiceRecordWidget::SetVoiceRecordComponent(UVoiceRecordComponent* VoiceRecordComponent)
{
	if (!VoiceRecordComponent)
	{
		return;
	}

	_VoiceRecordComponent = VoiceRecordComponent;

	_VoiceRecordComponent-&amp;gt;GetOnStartVoiceRecord().AddDynamic(this, &amp;amp;UVoiceRecordWidget::OnStartVoiceRecord);
	_VoiceRecordComponent-&amp;gt;GetOnStopVoiceRecord().AddDynamic(this, &amp;amp;UVoiceRecordWidget::OnStopVoiceRecord);
}

void UVoiceRecordWidget::ResetVoiceRecordComponent()
{
	if (_VoiceRecordComponent.IsValid())
	{
		_VoiceRecordComponent-&amp;gt;GetOnStartVoiceRecord().RemoveDynamic(this, &amp;amp;UVoiceRecordWidget::OnStartVoiceRecord);
		_VoiceRecordComponent-&amp;gt;GetOnStopVoiceRecord().RemoveDynamic(this, &amp;amp;UVoiceRecordWidget::OnStopVoiceRecord);

		_VoiceRecordComponent = nullptr;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VoiceRecordComponent에서 Record 시작/정지 일때 호출된 델리게이트에 따라서 WidgetSwitch로 보여줄 위젯을 바꾸도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 VoiceRecordComponent의 Delegate에 Bind / UnBind 하는 코드도 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1721052587465&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UVoiceRecordWidget::NativeConstruct()
{
	if (Button_RecordStart)
	{
		Button_RecordStart-&amp;gt;OnClicked.AddDynamic(this, &amp;amp;UVoiceRecordWidget::OnClicked_RecordStart);
	}

	if (Button_RecordStop)
	{
		Button_RecordStop-&amp;gt;OnClicked.AddDynamic(this, &amp;amp;UVoiceRecordWidget::OnClicked_RecordStop);
	}
}

void UVoiceRecordWidget::NativeDestruct()
{
	if (Button_RecordStart)
	{
		Button_RecordStart-&amp;gt;OnClicked.RemoveDynamic(this, &amp;amp;UVoiceRecordWidget::OnClicked_RecordStart);
	}

	if (Button_RecordStop)
	{
		Button_RecordStop-&amp;gt;OnClicked.RemoveDynamic(this, &amp;amp;UVoiceRecordWidget::OnClicked_RecordStop);
	}

	ResetVoiceRecordComponent();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Construct / Destruct에서 Button OnCliecked 이벤트에 바인딩 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 위젯을 생성하고 Viewport에 추가해보자. 간단하게 작업하기 위해서 Blueprint로 호다닥 작업해주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLTRy6/btsIBMdmRP2/f82Ch3U38dY9VVyqasvVxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLTRy6/btsIBMdmRP2/f82Ch3U38dY9VVyqasvVxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLTRy6/btsIBMdmRP2/f82Ch3U38dY9VVyqasvVxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLTRy6%2FbtsIBMdmRP2%2Ff82Ch3U38dY9VVyqasvVxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;804&quot; height=&quot;496&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 만들었던 BP_RecordActor를 열어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2413&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dD2TP5/btsIBnx8vF7/EqooLoNoFH8MLNysAAQB1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dD2TP5/btsIBnx8vF7/EqooLoNoFH8MLNysAAQB1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dD2TP5/btsIBnx8vF7/EqooLoNoFH8MLNysAAQB1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdD2TP5%2FbtsIBnx8vF7%2FEqooLoNoFH8MLNysAAQB1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2413&quot; height=&quot;637&quot; data-origin-width=&quot;2413&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WBP_VoiceRecordWidget을 생성하고 위젯에서 SetVoiceRecordComponent를 통해서 BP_RecordActor에 Component를 넘겨준다 그리고 Add To Viewport를 호출해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실행해서 제데로 녹음 되는지 확인해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/5eNIfSTdrik&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/5eNIfSTdrik&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=5eNIfSTdrik&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/rhQow/hyWCLqlSD1/5CTD395ftLlLAuRE6SNk00/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480&quot; data-video-width=&quot;640&quot; data-video-height=&quot;480&quot; data-video-origin-width=&quot;640&quot; data-video-origin-height=&quot;480&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;VoiceRecordProj 프리뷰 NetMode  Standalone 0  64 bit PC D3D SM6 2024 07 16 15 05 28&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/5eNIfSTdrik&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecordRecv의 출력볼륨과 웻레벨을 최솟값 -96.0으로 설정해서 마이크로 말하는 내용이 들리지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwTlOT/btsICdaEfyJ/wmRYyJ60KwFG6AK6Qbwhz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwTlOT/btsICdaEfyJ/wmRYyJ60KwFG6AK6Qbwhz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwTlOT/btsICdaEfyJ/wmRYyJ60KwFG6AK6Qbwhz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwTlOT%2FbtsICdaEfyJ%2FwmRYyJ60KwFG6AK6Qbwhz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1096&quot; height=&quot;645&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드에서 작성한 대로 saved 폴더 안에 들어가면 RecordVoiceFile.wav파일이 생성된것을 확인 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=unomY6FCuB8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=unomY6FCuB8&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=unomY6FCuB8&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bP3U6F/hyWzwuPNWe/0EHaJLvdxAKMO6sreHPwKK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;RecordVoiceFile wav   GoldWave   RecordVoiceFile wav 2024 07 16 15 11 56&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/unomY6FCuB8&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재생해 보면 음성 녹음 된것을 확인 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programing/UnrealEngine</category>
      <author>곤란</author>
      <guid isPermaLink="true">https://hannom.tistory.com/238</guid>
      <comments>https://hannom.tistory.com/238#entry238comment</comments>
      <pubDate>Tue, 16 Jul 2024 15:15:17 +0900</pubDate>
    </item>
  </channel>
</rss>